diff options
34 files changed, 373 insertions, 357 deletions
diff --git a/Android.bp b/Android.bp index cb32b36be7fc..773c9b74cb28 100644 --- a/Android.bp +++ b/Android.bp @@ -1116,6 +1116,9 @@ doc_defaults { local_sourcepaths: frameworks_base_subdirs, installable: false, metalava_enabled: true, + metalava_annotations_enabled: true, + metalava_previous_api: ":public-api-for-metalava-annotations", + metalava_merge_annotations_dir: "tools/metalava/manual", } droiddoc { diff --git a/CleanSpec.mk b/CleanSpec.mk index cc0e76205abb..1f6860b2b226 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -244,6 +244,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/os/storage/*) $(call add-clean-step, rm -rf $(OUT_DIR)/host/common/obj/JAVA_LIBRARIES/platformprotos_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.mediadrm.signer.jar) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.location.provider.jar) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER # ****************************************************************** diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 0e74d9ec2c50..a22f6d61b39f 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -96,8 +96,8 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; import libcore.io.IoUtils; - import libcore.util.EmptyArray; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -2340,10 +2340,10 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { - targetCode = minCode = val.string.toString(); + minCode = val.string.toString(); } else { // If it's not a string, it's an integer. - targetVers = minVers = val.data; + minVers = val.data; } } @@ -2359,6 +2359,9 @@ public class PackageParser { // If it's not a string, it's an integer. targetVers = val.data; } + } else { + targetVers = minVers; + targetCode = minCode; } sa.recycle(); diff --git a/core/java/android/util/TimestampedValue.java b/core/java/android/util/TimestampedValue.java index 21603801d4cb..75fa18db3908 100644 --- a/core/java/android/util/TimestampedValue.java +++ b/core/java/android/util/TimestampedValue.java @@ -72,6 +72,14 @@ public final class TimestampedValue<T> { return Objects.hash(mReferenceTimeMillis, mValue); } + @Override + public String toString() { + return "TimestampedValue{" + + "mReferenceTimeMillis=" + mReferenceTimeMillis + + ", mValue=" + mValue + + '}'; + } + /** * Read a {@link TimestampedValue} from a parcel that was stored using * {@link #writeToParcel(Parcel, TimestampedValue)}. diff --git a/core/java/com/android/internal/util/HexDump.java b/core/java/com/android/internal/util/HexDump.java index 7be95d89dcf9..af004009e1ee 100644 --- a/core/java/com/android/internal/util/HexDump.java +++ b/core/java/com/android/internal/util/HexDump.java @@ -16,18 +16,21 @@ package com.android.internal.util; +import android.annotation.Nullable; + public class HexDump { private final static char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; private final static char[] HEX_LOWER_CASE_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - public static String dumpHexString(byte[] array) - { + public static String dumpHexString(@Nullable byte[] array) { + if (array == null) return "(null)"; return dumpHexString(array, 0, array.length); } - public static String dumpHexString(byte[] array, int offset, int length) + public static String dumpHexString(@Nullable byte[] array, int offset, int length) { + if (array == null) return "(null)"; StringBuilder result = new StringBuilder(); byte[] line = new byte[16]; diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index d3da21b5635b..b35d92fe0d0c 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -902,146 +902,6 @@ jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz); jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz); jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz); - -/* pulled out of bionic */ -extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, - size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); -extern "C" void free_malloc_leak_info(uint8_t* info); -#define SIZE_FLAG_ZYGOTE_CHILD (1<<31) - -static size_t gNumBacktraceElements; - -/* - * This is a qsort() callback. - * - * See dumpNativeHeap() for comments about the data format and sort order. - */ -static int compareHeapRecords(const void* vrec1, const void* vrec2) -{ - const size_t* rec1 = (const size_t*) vrec1; - const size_t* rec2 = (const size_t*) vrec2; - size_t size1 = *rec1; - size_t size2 = *rec2; - - if (size1 < size2) { - return 1; - } else if (size1 > size2) { - return -1; - } - - uintptr_t* bt1 = (uintptr_t*)(rec1 + 2); - uintptr_t* bt2 = (uintptr_t*)(rec2 + 2); - for (size_t idx = 0; idx < gNumBacktraceElements; idx++) { - uintptr_t addr1 = bt1[idx]; - uintptr_t addr2 = bt2[idx]; - if (addr1 == addr2) { - if (addr1 == 0) - break; - continue; - } - if (addr1 < addr2) { - return -1; - } else if (addr1 > addr2) { - return 1; - } - } - - return 0; -} - -/* - * The get_malloc_leak_info() call returns an array of structs that - * look like this: - * - * size_t size - * size_t allocations - * intptr_t backtrace[32] - * - * "size" is the size of the allocation, "backtrace" is a fixed-size - * array of function pointers, and "allocations" is the number of - * allocations with the exact same size and backtrace. - * - * The entries are sorted by descending total size (i.e. size*allocations) - * then allocation count. For best results with "diff" we'd like to sort - * primarily by individual size then stack trace. Since the entries are - * fixed-size, and we're allowed (by the current implementation) to mangle - * them, we can do this in place. - */ -static void dumpNativeHeap(FILE* fp) -{ - uint8_t* info = NULL; - size_t overallSize, infoSize, totalMemory, backtraceSize; - - get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, - &backtraceSize); - if (info == NULL) { - fprintf(fp, "Native heap dump not available. To enable, run these" - " commands (requires root):\n"); - fprintf(fp, "# adb shell stop\n"); - fprintf(fp, "# adb shell setprop libc.debug.malloc.options " - "backtrace\n"); - fprintf(fp, "# adb shell start\n"); - return; - } - assert(infoSize != 0); - assert(overallSize % infoSize == 0); - - fprintf(fp, "Android Native Heap Dump v1.0\n\n"); - - size_t recordCount = overallSize / infoSize; - fprintf(fp, "Total memory: %zu\n", totalMemory); - fprintf(fp, "Allocation records: %zd\n", recordCount); - fprintf(fp, "Backtrace size: %zd\n", backtraceSize); - fprintf(fp, "\n"); - - /* re-sort the entries */ - gNumBacktraceElements = backtraceSize; - qsort(info, recordCount, infoSize, compareHeapRecords); - - /* dump the entries to the file */ - const uint8_t* ptr = info; - for (size_t idx = 0; idx < recordCount; idx++) { - size_t size = *(size_t*) ptr; - size_t allocations = *(size_t*) (ptr + sizeof(size_t)); - uintptr_t* backtrace = (uintptr_t*) (ptr + sizeof(size_t) * 2); - - fprintf(fp, "z %d sz %8zu num %4zu bt", - (size & SIZE_FLAG_ZYGOTE_CHILD) != 0, - size & ~SIZE_FLAG_ZYGOTE_CHILD, - allocations); - for (size_t bt = 0; bt < backtraceSize; bt++) { - if (backtrace[bt] == 0) { - break; - } else { -#ifdef __LP64__ - fprintf(fp, " %016" PRIxPTR, backtrace[bt]); -#else - fprintf(fp, " %08" PRIxPTR, backtrace[bt]); -#endif - } - } - fprintf(fp, "\n"); - - ptr += infoSize; - } - - free_malloc_leak_info(info); - - fprintf(fp, "MAPS\n"); - const char* maps = "/proc/self/maps"; - UniqueFile in = MakeUniqueFile(maps, "re"); - if (in == nullptr) { - fprintf(fp, "Could not open %s\n", maps); - return; - } - char buf[BUFSIZ]; - while (size_t n = fread(buf, sizeof(char), BUFSIZ, in.get())) { - fwrite(buf, sizeof(char), n, fp); - } - - fprintf(fp, "END\n"); -} - static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp) { if (fileDescriptor == NULL) { @@ -1072,6 +932,9 @@ static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp) return true; } +/* pulled out of bionic */ +extern "C" void write_malloc_leak_info(FILE* fp); + /* * Dump the native heap, writing human-readable output to the specified * file descriptor. @@ -1085,7 +948,9 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject, } ALOGD("Native heap dump starting...\n"); - dumpNativeHeap(fp.get()); + // Formatting of the native heap dump is handled by malloc debug itself. + // See https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md#backtrace-heap-dump-format + write_malloc_leak_info(fp.get()); ALOGD("Native heap dump complete.\n"); } diff --git a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java index 951e87a99da3..359bd5e93dae 100644 --- a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java +++ b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java @@ -25,4 +25,7 @@ public final class HexDumpTest extends TestCase { assertEquals("ABCDEF", HexDump.toHexString( new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef }, true)); } + public void testNullArray() { + assertEquals("(null)", HexDump.toHexString(null)); + } } diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp index 1e71cb081b39..69d5130e780f 100644 --- a/libs/hwui/Extensions.cpp +++ b/libs/hwui/Extensions.cpp @@ -59,6 +59,7 @@ Extensions::Extensions() { mHas1BitStencil = extensions.has("GL_OES_stencil1"); mHas4BitStencil = extensions.has("GL_OES_stencil4"); mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage"); + mHasRenderableFloatTexture = extensions.has("GL_OES_texture_half_float"); mHasSRGB = mVersionMajor >= 3 || extensions.has("GL_EXT_sRGB"); mHasSRGBWriteControl = extensions.has("GL_EXT_sRGB_write_control"); diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h index 0ecfdb1b3e0a..7af7f7944ac9 100644 --- a/libs/hwui/Extensions.h +++ b/libs/hwui/Extensions.h @@ -38,6 +38,9 @@ public: inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; } inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; } inline bool hasFloatTextures() const { return mVersionMajor >= 3; } + inline bool hasRenderableFloatTextures() const { + return (mVersionMajor >= 3 && mVersionMinor >= 2) || mHasRenderableFloatTexture; + } inline bool hasSRGB() const { return mHasSRGB; } inline bool hasSRGBWriteControl() const { return hasSRGB() && mHasSRGBWriteControl; } inline bool hasLinearBlending() const { return hasSRGB() && mHasLinearBlending; } @@ -56,6 +59,7 @@ private: bool mHasSRGB; bool mHasSRGBWriteControl; bool mHasLinearBlending; + bool mHasRenderableFloatTexture; int mVersionMajor; int mVersionMinor; diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp index 2687410897ac..751e2037db91 100644 --- a/libs/hwui/OpenGLReadback.cpp +++ b/libs/hwui/OpenGLReadback.cpp @@ -128,7 +128,8 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, return CopyResult::DestinationInvalid; } - if (bitmap->colorType() == kRGBA_F16_SkColorType && !caches.extensions().hasFloatTextures()) { + if (bitmap->colorType() == kRGBA_F16_SkColorType && + !caches.extensions().hasRenderableFloatTextures()) { ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); return CopyResult::DestinationInvalid; } diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index f7a90b0a65ec..32b5132a6fa3 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -134,7 +134,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path, service::Graph return false; } void* addr = mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (!addr) { + if (addr == MAP_FAILED) { int err = errno; // The file not existing is normal for addToDump(), so only log if // we get an unexpected error diff --git a/location/lib/Android.bp b/location/lib/Android.bp new file mode 100644 index 000000000000..447195d6d532 --- /dev/null +++ b/location/lib/Android.bp @@ -0,0 +1,21 @@ +// +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +java_sdk_library { + name: "com.android.location.provider", + srcs: ["java/**/*.java"], + api_packages: ["com.android.location.provider"], +} diff --git a/location/lib/Android.mk b/location/lib/Android.mk deleted file mode 100644 index 6642134ec32b..000000000000 --- a/location/lib/Android.mk +++ /dev/null @@ -1,66 +0,0 @@ -# -# Copyright (C) 2010 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -LOCAL_PATH := $(call my-dir) - -# the library -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_MODULE:= com.android.location.provider -LOCAL_MODULE_TAGS := optional - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -include $(BUILD_JAVA_LIBRARY) - - -# ==== com.google.location.xml lib def ======================== -include $(CLEAR_VARS) - -LOCAL_MODULE := com.android.location.provider.xml -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE_CLASS := ETC - -# This will install the file in /system/etc/permissions -# -LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions - -LOCAL_SRC_FILES := $(LOCAL_MODULE) - -include $(BUILD_PREBUILT) - -# ==== Stub library =========================================== -include $(CLEAR_VARS) -LOCAL_MODULE := com.android.location.provider-stubs-gen -LOCAL_MODULE_CLASS := JAVA_LIBRARIES -LOCAL_SRC_FILES := $(call all-java-files-under,java) -LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.location.provider.stubs_intermediates/src -LOCAL_DROIDDOC_OPTIONS:= \ - -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \ - -stubpackages com.android.location.provider \ - -nodocs -LOCAL_UNINSTALLABLE_MODULE := true -include $(BUILD_DROIDDOC) -com_android_nfc_extras_gen_stamp := $(full_target) - -include $(CLEAR_VARS) -LOCAL_MODULE := com.android.location.provider.stubs -LOCAL_SOURCE_FILES_ALL_GENERATED := true -LOCAL_SDK_VERSION := current -LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_nfc_extras_gen_stamp) -com_android_nfc_extras_gen_stamp := -include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt new file mode 100644 index 000000000000..1e69f162fb07 --- /dev/null +++ b/location/lib/api/current.txt @@ -0,0 +1,47 @@ +package com.android.location.provider { + + public abstract deprecated class FusedProvider { + ctor public FusedProvider(); + method public android.os.IBinder getBinder(); + } + + public abstract class LocationProviderBase { + ctor public LocationProviderBase(java.lang.String, com.android.location.provider.ProviderPropertiesUnbundled); + method public android.os.IBinder getBinder(); + method public abstract void onDisable(); + method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); + method public abstract void onEnable(); + method public abstract int onGetStatus(android.os.Bundle); + method public abstract long onGetStatusUpdateTime(); + method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle); + method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); + method public final void reportLocation(android.location.Location); + field public static final java.lang.String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; + field public static final java.lang.String FUSED_PROVIDER = "fused"; + } + + public final class LocationRequestUnbundled { + method public long getFastestInterval(); + method public long getInterval(); + method public int getQuality(); + method public float getSmallestDisplacement(); + field public static final int ACCURACY_BLOCK = 102; // 0x66 + field public static final int ACCURACY_CITY = 104; // 0x68 + field public static final int ACCURACY_FINE = 100; // 0x64 + field public static final int POWER_HIGH = 203; // 0xcb + field public static final int POWER_LOW = 201; // 0xc9 + field public static final int POWER_NONE = 200; // 0xc8 + } + + public final class ProviderPropertiesUnbundled { + method public static com.android.location.provider.ProviderPropertiesUnbundled create(boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int); + } + + public final class ProviderRequestUnbundled { + method public long getInterval(); + method public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests(); + method public boolean getReportLocation(); + } + +} + diff --git a/location/lib/api/removed.txt b/location/lib/api/removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/location/lib/api/removed.txt diff --git a/location/lib/api/system-current.txt b/location/lib/api/system-current.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/location/lib/api/system-current.txt diff --git a/location/lib/api/system-removed.txt b/location/lib/api/system-removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/location/lib/api/system-removed.txt diff --git a/location/lib/api/test-current.txt b/location/lib/api/test-current.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/location/lib/api/test-current.txt diff --git a/location/lib/api/test-removed.txt b/location/lib/api/test-removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/location/lib/api/test-removed.txt diff --git a/location/lib/com.android.location.provider.xml b/location/lib/com.android.location.provider.xml deleted file mode 100644 index 000e68ffc865..000000000000 --- a/location/lib/com.android.location.provider.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2008 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<permissions> - <library name="com.android.location.provider" - file="/system/framework/com.android.location.provider.jar" /> -</permissions> diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk index fd7c87e2545b..c9f997232768 100644 --- a/packages/SettingsLib/Android.mk +++ b/packages/SettingsLib/Android.mk @@ -21,6 +21,8 @@ LOCAL_JAR_EXCLUDE_FILES := none LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_MIN_SDK_VERSION := 21 + include $(BUILD_STATIC_JAVA_LIBRARY) # For the test package. diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index dadd3274eeed..49d60a7aa6bb 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -990,7 +990,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) { + @VisibleForTesting + protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) { if (network == null) { return null; } @@ -3334,35 +3335,7 @@ public class ConnectivityService extends IConnectivityManager.Stub && Uri.EMPTY.equals(proxy.getPacFileUrl())) { proxy = null; } - synchronized (mProxyTracker.mProxyLock) { - if (mProxyTracker.mDefaultProxy != null && mProxyTracker.mDefaultProxy.equals(proxy)) { - return; - } - if (mProxyTracker.mDefaultProxy == proxy) return; // catches repeated nulls - if (proxy != null && !proxy.isValid()) { - if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString()); - return; - } - - // This call could be coming from the PacManager, containing the port of the local - // proxy. If this new proxy matches the global proxy then copy this proxy to the - // global (to get the correct local port), and send a broadcast. - // TODO: Switch PacManager to have its own message to send back rather than - // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy. - if ((mProxyTracker.mGlobalProxy != null) && (proxy != null) - && (!Uri.EMPTY.equals(proxy.getPacFileUrl())) - && proxy.getPacFileUrl().equals(mProxyTracker.mGlobalProxy.getPacFileUrl())) { - mProxyTracker.mGlobalProxy = proxy; - mProxyTracker.sendProxyBroadcast(mProxyTracker.mGlobalProxy); - return; - } - mProxyTracker.mDefaultProxy = proxy; - - if (mProxyTracker.mGlobalProxy != null) return; - if (!mProxyTracker.mDefaultProxyDisabled) { - mProxyTracker.sendProxyBroadcast(proxy); - } - } + mProxyTracker.setDefaultProxy(proxy); } // If the proxy has changed from oldLp to newLp, resend proxy broadcast with default proxy. diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index 1ad14047adf9..2c24798204eb 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -69,13 +69,10 @@ public class NetworkTimeUpdateService extends Binder { private static final String ACTION_POLL = "com.android.server.NetworkTimeUpdateService.action.POLL"; - private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000; - private static int POLL_REQUEST = 0; + private static final int POLL_REQUEST = 0; private static final long NOT_SET = -1; private long mNitzTimeSetTime = NOT_SET; - // TODO: Have a way to look up the timezone we are in - private long mNitzZoneSetTime = NOT_SET; private Network mDefaultNetwork = null; private Context mContext; @@ -144,7 +141,6 @@ public class NetworkTimeUpdateService extends Binder { private void registerForTelephonyIntents() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME); - intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); mContext.registerReceiver(mNitzReceiver, intentFilter); } @@ -257,8 +253,6 @@ public class NetworkTimeUpdateService extends Binder { if (DBG) Log.d(TAG, "Received " + action); if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) { mNitzTimeSetTime = SystemClock.elapsedRealtime(); - } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) { - mNitzZoneSetTime = SystemClock.elapsedRealtime(); } } }; diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java index 19b61e6fc739..c370959dd2cf 100644 --- a/services/core/java/com/android/server/connectivity/PacManager.java +++ b/services/core/java/com/android/server/connectivity/PacManager.java @@ -166,14 +166,14 @@ public class PacManager { /** * Updates the PAC Manager with current Proxy information. This is called by - * the ConnectivityService directly before a broadcast takes place to allow + * the ProxyTracker directly before a broadcast takes place to allow * the PacManager to indicate that the broadcast should not be sent and the * PacManager will trigger a new broadcast when it is ready. * * @param proxy Proxy information that is about to be broadcast. * @return Returns true when the broadcast should not be sent */ - public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) { + synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) { if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) { if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) { // Allow to send broadcast, nothing to do. diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index daaedd813163..dc65e1e69834 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -51,15 +51,25 @@ public class ProxyTracker { // possible @NonNull public final Object mProxyLock = new Object(); + // The global proxy is the proxy that is set device-wide, overriding any network-specific + // proxy. Note however that proxies are hints ; the system does not enforce their use. Hence + // this value is only for querying. @Nullable @GuardedBy("mProxyLock") public ProxyInfo mGlobalProxy = null; + // The default proxy is the proxy that applies to no particular network if the global proxy + // is not set. Individual networks have their own settings that override this. This member + // is set through setDefaultProxy, which is called when the default network changes proxies + // in its LinkProperties, or when ConnectivityService switches to a new default network, or + // when PacManager resolves the proxy. @Nullable @GuardedBy("mProxyLock") public volatile ProxyInfo mDefaultProxy = null; + // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled @GuardedBy("mProxyLock") public boolean mDefaultProxyDisabled = false; + // The object responsible for Proxy Auto Configuration (PAC). @NonNull private final PacManager mPacManager; @@ -98,6 +108,16 @@ public class ProxyTracker { return Objects.equals(pa, pb) && (pa == null || Objects.equals(pa.getHost(), pb.getHost())); } + /** + * Gets the default system-wide proxy. + * + * This will return the global proxy if set, otherwise the default proxy if in use. Note + * that this is not necessarily the proxy that any given process should use, as the right + * proxy for a process is the proxy for the network this process will use, which may be + * different from this value. This value is simply the default in case there is no proxy set + * in the network that will be used by a specific process. + * @return The default system-wide proxy or null if none. + */ @Nullable public ProxyInfo getDefaultProxy() { // This information is already available as a world read/writable jvm property. @@ -108,6 +128,11 @@ public class ProxyTracker { } } + /** + * Gets the global proxy. + * + * @return The global proxy or null if none. + */ @Nullable public ProxyInfo getGlobalProxy() { // This information is already available as a world read/writable jvm property. @@ -116,19 +141,22 @@ public class ProxyTracker { } } - public boolean setCurrentProxyScriptUrl(@NonNull final ProxyInfo proxy) { - return mPacManager.setCurrentProxyScriptUrl(proxy); - } - - // TODO : make the argument NonNull final - public void sendProxyBroadcast(@Nullable ProxyInfo proxy) { - if (proxy == null) proxy = new ProxyInfo("", 0, ""); - if (setCurrentProxyScriptUrl(proxy)) return; - if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxy); + /** + * Sends the system broadcast informing apps about a new proxy configuration. + * + * Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing + * to do in a "sendProxyBroadcast" method. + * @param proxyInfo the proxy spec, or null for no proxy. + */ + // TODO : make the argument NonNull final and the method private + public void sendProxyBroadcast(@Nullable ProxyInfo proxyInfo) { + if (proxyInfo == null) proxyInfo = new ProxyInfo("", 0, ""); + if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)) return; + if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo); Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); + intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxyInfo); final long ident = Binder.clearCallingIdentity(); try { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); @@ -137,30 +165,39 @@ public class ProxyTracker { } } - public void setGlobalProxy(@Nullable ProxyInfo proxyProperties) { + /** + * Sets the global proxy in memory. Also writes the values to the global settings of the device. + * + * @param proxyInfo the proxy spec, or null for no proxy. + */ + public void setGlobalProxy(@Nullable ProxyInfo proxyInfo) { synchronized (mProxyLock) { - if (proxyProperties == mGlobalProxy) return; - if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; - if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return; - - String host = ""; - int port = 0; - String exclList = ""; - String pacFileUrl = ""; - if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) || - !Uri.EMPTY.equals(proxyProperties.getPacFileUrl()))) { - if (!proxyProperties.isValid()) { - if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties); + // ProxyInfo#equals is not commutative :( and is public API, so it can't be fixed. + if (proxyInfo == mGlobalProxy) return; + if (proxyInfo != null && proxyInfo.equals(mGlobalProxy)) return; + if (mGlobalProxy != null && mGlobalProxy.equals(proxyInfo)) return; + + final String host; + final int port; + final String exclList; + final String pacFileUrl; + if (proxyInfo != null && (!TextUtils.isEmpty(proxyInfo.getHost()) || + !Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))) { + if (!proxyInfo.isValid()) { + if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo); return; } - mGlobalProxy = new ProxyInfo(proxyProperties); + mGlobalProxy = new ProxyInfo(proxyInfo); host = mGlobalProxy.getHost(); port = mGlobalProxy.getPort(); exclList = mGlobalProxy.getExclusionListAsString(); - if (!Uri.EMPTY.equals(proxyProperties.getPacFileUrl())) { - pacFileUrl = proxyProperties.getPacFileUrl().toString(); - } + pacFileUrl = Uri.EMPTY.equals(proxyInfo.getPacFileUrl()) + ? "" : proxyInfo.getPacFileUrl().toString(); } else { + host = ""; + port = 0; + exclList = ""; + pacFileUrl = ""; mGlobalProxy = null; } final ContentResolver res = mContext.getContentResolver(); @@ -175,10 +212,45 @@ public class ProxyTracker { Binder.restoreCallingIdentity(token); } - if (mGlobalProxy == null) { - proxyProperties = mDefaultProxy; + sendProxyBroadcast(mGlobalProxy == null ? mDefaultProxy : proxyInfo); + } + } + + /** + * Sets the default proxy for the device. + * + * The default proxy is the proxy used for networks that do not have a specific proxy. + * @param proxyInfo the proxy spec, or null for no proxy. + */ + public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) { + synchronized (mProxyLock) { + if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) { + return; + } + if (mDefaultProxy == proxyInfo) return; // catches repeated nulls + if (proxyInfo != null && !proxyInfo.isValid()) { + if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo); + return; + } + + // This call could be coming from the PacManager, containing the port of the local + // proxy. If this new proxy matches the global proxy then copy this proxy to the + // global (to get the correct local port), and send a broadcast. + // TODO: Switch PacManager to have its own message to send back rather than + // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy. + if ((mGlobalProxy != null) && (proxyInfo != null) + && (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) + && proxyInfo.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) { + mGlobalProxy = proxyInfo; + sendProxyBroadcast(mGlobalProxy); + return; + } + mDefaultProxy = proxyInfo; + + if (mGlobalProxy != null) return; + if (!mDefaultProxyDisabled) { + sendProxyBroadcast(proxyInfo); } - sendProxyBroadcast(proxyProperties); } } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 0cba76ba7346..f6b032ede5be 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -514,8 +514,7 @@ abstract class HdmiCecLocalDevice { static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) { byte[] params = message.getParams(); return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED - && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER - || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION + && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 502a21c822cb..5b2bc9e10faf 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -559,7 +559,7 @@ public class NotificationManagerService extends SystemService { { final int pid; final String pkg; - ITransientNotification callback; + final ITransientNotification callback; int duration; Binder token; @@ -576,10 +576,6 @@ public class NotificationManagerService extends SystemService { this.duration = duration; } - void update(ITransientNotification callback) { - this.callback = callback; - } - void dump(PrintWriter pw, String prefix, DumpFilter filter) { if (filter != null && !filter.matches(pkg)) return; pw.println(prefix + this); @@ -1648,28 +1644,38 @@ public class NotificationManagerService extends SystemService { long callingId = Binder.clearCallingIdentity(); try { ToastRecord record; - int index; - // All packages aside from the android package can enqueue one toast at a time - if (!isSystemToast) { - index = indexOfToastPackageLocked(pkg); - } else { - index = indexOfToastLocked(pkg, callback); - } - - // If the package already has a toast, we update its toast - // in the queue, we don't move it to the end of the queue. + int index = indexOfToastLocked(pkg, callback); + // If it's already in the queue, we update it in place, we don't + // move it to the end of the queue. if (index >= 0) { record = mToastQueue.get(index); record.update(duration); - record.update(callback); } else { + // Limit the number of toasts that any given package except the android + // package can enqueue. Prevents DOS attacks and deals with leaks. + if (!isSystemToast) { + int count = 0; + final int N = mToastQueue.size(); + for (int i=0; i<N; i++) { + final ToastRecord r = mToastQueue.get(i); + if (r.pkg.equals(pkg)) { + count++; + if (count >= MAX_PACKAGE_NOTIFICATIONS) { + Slog.e(TAG, "Package has already posted " + count + + " toasts. Not showing more. Package=" + pkg); + return; + } + } + } + } + Binder token = new Binder(); mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY); record = new ToastRecord(callingPid, pkg, callback, duration, token); mToastQueue.add(record); index = mToastQueue.size() - 1; + keepProcessAliveIfNeededLocked(callingPid); } - keepProcessAliveIfNeededLocked(callingPid); // If it's at index 0, it's the current toast. It doesn't matter if it's // new or just been updated. Call back and tell it to show itself. // If the callback fails, this will remove it from the list, so don't @@ -4328,21 +4334,7 @@ public class NotificationManagerService extends SystemService { int len = list.size(); for (int i=0; i<len; i++) { ToastRecord r = list.get(i); - if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) { - return i; - } - } - return -1; - } - - @GuardedBy("mToastQueue") - int indexOfToastPackageLocked(String pkg) - { - ArrayList<ToastRecord> list = mToastQueue; - int len = list.size(); - for (int i=0; i<len; i++) { - ToastRecord r = list.get(i); - if (r.pkg.equals(pkg)) { + if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { return i; } } diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java index efd49b5a2c45..0ec24d8cfedb 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.app.timedetector.ITimeDetectorService; import android.app.timedetector.TimeSignal; import android.content.Context; +import android.os.Binder; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; @@ -69,7 +70,13 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { @Override public void suggestTime(@NonNull TimeSignal timeSignal) { enforceSetTimePermission(); - mTimeDetectorStrategy.suggestTime(timeSignal); + + long callerIdToken = Binder.clearCallingIdentity(); + try { + mTimeDetectorStrategy.suggestTime(timeSignal); + } finally { + Binder.restoreCallingIdentity(callerIdToken); + } } @Override diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java index f7e6840f7580..4354314dac29 100644 --- a/telephony/java/android/telephony/NetworkService.java +++ b/telephony/java/android/telephony/NetworkService.java @@ -36,8 +36,8 @@ import java.util.List; /** * Base class of network service. Services that extend NetworkService must register the service in * their AndroidManifest to be detected by the framework. They must be protected by the permission - * "android.permission.BIND_NETWORK_SERVICE". The network service definition in the manifest must - * follow the following format: + * "android.permission.BIND_TELEPHONY_NETWORK_SERVICE". The network service definition in the + * manifest must follow the following format: * ... * <service android:name=".xxxNetworkService" * android:permission="android.permission.BIND_TELEPHONY_NETWORK_SERVICE" > diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 4ca5ce3004be..1db58506bb1c 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -44,11 +44,11 @@ import java.util.List; /** * Base class of data service. Services that extend DataService must register the service in * their AndroidManifest to be detected by the framework. They must be protected by the permission - * "android.permission.BIND_DATA_SERVICE". The data service definition in the manifest must follow - * the following format: + * "android.permission.BIND_TELEPHONY_DATA_SERVICE". The data service definition in the manifest + * must follow the following format: * ... * <service android:name=".xxxDataService" - * android:permission="android.permission.BIND_DATA_SERVICE" > + * android:permission="android.permission.BIND_TELEPHONY_DATA_SERVICE" > * <intent-filter> * <action android:name="android.telephony.data.DataService" /> * </intent-filter> diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java index 421b0151b9c6..6ad44ba7075f 100644 --- a/telephony/java/com/android/ims/ImsConfig.java +++ b/telephony/java/com/android/ims/ImsConfig.java @@ -35,7 +35,6 @@ public class ImsConfig { private static final String TAG = "ImsConfig"; private boolean DBG = true; private final IImsConfig miConfig; - private Context mContext; /** * Broadcast action: the feature enable status was changed @@ -541,14 +540,12 @@ public class ImsConfig { public static final int WIFI_PREFERRED = 2; } - public ImsConfig(IImsConfig iconfig, Context context) { - if (DBG) Rlog.d(TAG, "ImsConfig created"); + public ImsConfig(IImsConfig iconfig) { miConfig = iconfig; - mContext = context; } /** - * @deprecated see {@link #getInt(int)} instead. + * @deprecated see {@link #getConfigInt(int)} instead. */ public int getProvisionedValue(int item) throws ImsException { return getConfigInt(item); diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java index c0954385a0a3..4790b75d9630 100644 --- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java @@ -105,7 +105,7 @@ public class IccUtils { /** * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3 * Returns a concatenated string of MCC+MNC, stripping - * all invalid character 'f' + * all invalid character 'F' */ public static String bcdPlmnToString(byte[] data, int offset) { if (offset + 3 > data.length) { @@ -117,9 +117,9 @@ public class IccUtils { trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF)); String ret = bytesToHexString(trans); - // For a valid plmn we trim all character 'f' - if (ret.contains("f")) { - ret = ret.replaceAll("f", ""); + // For a valid plmn we trim all character 'F' + if (ret.contains("F")) { + ret = ret.replaceAll("F", ""); } return ret; } diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 0248e97bd59b..983802035bfb 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -314,9 +314,9 @@ public class ApfTest { // Test multiply. gen = new ApfGenerator(MIN_APF_VERSION); - gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLoadImmediate(Register.R0, 123456789); gen.addMul(2); - gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); + gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL); assertDrop(gen); // Test divide. @@ -379,10 +379,10 @@ public class ApfTest { // Test multiply. gen = new ApfGenerator(MIN_APF_VERSION); - gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLoadImmediate(Register.R0, 123456789); gen.addLoadImmediate(Register.R1, 2); gen.addMulR1(); - gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); + gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL); assertDrop(gen); // Test divide. diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index d6018f1b1300..5e5ba4d15e76 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -57,6 +57,7 @@ import static com.android.internal.util.TestUtils.waitForIdleLooper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -95,6 +96,7 @@ import android.net.ConnectivityManager.TooManyRequestsException; import android.net.ConnectivityThread; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; +import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; @@ -125,6 +127,7 @@ import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; +import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; @@ -132,6 +135,7 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.test.mock.MockContentResolver; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; @@ -145,6 +149,7 @@ import com.android.server.connectivity.DefaultNetworkMetrics; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.MockableSystemProperties; +import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.Vpn; @@ -161,10 +166,13 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import java.net.Inet4Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -190,6 +198,7 @@ public class ConnectivityServiceTest { private static final int TIMEOUT_MS = 500; private static final int TEST_LINGER_DELAY_MS = 120; + private static final String CLAT_PREFIX = "v4-"; private static final String MOBILE_IFNAME = "test_rmnet_data0"; private static final String WIFI_IFNAME = "test_wlan0"; @@ -950,6 +959,10 @@ public class ConnectivityServiceTest { return monitor; } + public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) { + return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd; + } + @Override public MultinetworkPolicyTracker createMultinetworkPolicyTracker( Context c, Handler h, Runnable r) { @@ -4418,4 +4431,97 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); } + + /** + * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info. + */ + private InterfaceConfiguration getClatInterfaceConfig(LinkAddress la) { + InterfaceConfiguration cfg = new InterfaceConfiguration(); + cfg.setHardwareAddress("11:22:33:44:55:66"); + cfg.setLinkAddress(la); + return cfg; + } + + /** + * Make expected stack link properties, copied from Nat464Xlat. + */ + private LinkProperties makeClatLinkProperties(LinkAddress la) { + LinkAddress clatAddress = la; + LinkProperties stacked = new LinkProperties(); + stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME); + RouteInfo ipv4Default = new RouteInfo( + new LinkAddress(Inet4Address.ANY, 0), + clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME); + stacked.addRoute(ipv4Default); + stacked.addLinkAddress(clatAddress); + return stacked; + } + + @Test + public void testStackedLinkProperties() throws UnknownHostException, RemoteException { + final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24"); + final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64"); + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + mCm.registerNetworkCallback(networkRequest, networkCallback); + + // Prepare ipv6 only link properties and connect. + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + final LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName(MOBILE_IFNAME); + cellLp.addLinkAddress(myIpv6); + cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME)); + cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME)); + reset(mNetworkManagementService); + when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME)) + .thenReturn(getClatInterfaceConfig(myIpv4)); + + // Connect with ipv6 link properties, then expect clat setup ipv4 and update link + // properties properly. + mCellNetworkAgent.sendLinkProperties(cellLp); + mCellNetworkAgent.connect(true); + networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME); + Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent); + + // Clat iface up, expect stack link updated. + clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true); + waitForIdle(); + List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork()) + .getStackedLinks(); + assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0)); + + // Change trivial linkproperties and see if stacked link is preserved. + cellLp.addDnsServer(InetAddress.getByName("8.8.8.8")); + mCellNetworkAgent.sendLinkProperties(cellLp); + waitForIdle(); + networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); + + List<LinkProperties> stackedLpsAfterChange = + mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks(); + assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST); + assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0)); + + // Add ipv4 address, expect stacked linkproperties be cleaned up + cellLp.addLinkAddress(myIpv4); + cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME)); + mCellNetworkAgent.sendLinkProperties(cellLp); + waitForIdle(); + networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); + verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME); + + // Clat iface removed, expect linkproperties revert to original one + clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME); + waitForIdle(); + networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); + LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork()); + assertEquals(cellLp, actualLpAfterIpv4); + + // Clean up + mCellNetworkAgent.disconnect(); + mCm.unregisterNetworkCallback(networkCallback); + } } |