Merge "Removed dead code in DcTracker"
diff --git a/Android.bp b/Android.bp
index cb32b36..773c9b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1116,6 +1116,9 @@
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 cc0e762..1f6860b 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -244,6 +244,7 @@
$(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 0e74d9e..a22f6d6 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.XmlUtils;
import libcore.io.IoUtils;
-
import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -2340,10 +2340,10 @@
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 @@
// 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 2160380..75fa18d 100644
--- a/core/java/android/util/TimestampedValue.java
+++ b/core/java/android/util/TimestampedValue.java
@@ -72,6 +72,14 @@
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 7be95d8..af00400 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 d3da21b..b35d92f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -902,146 +902,6 @@
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 @@
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 @@
}
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 951e87a..359bd5e 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 @@
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 1e71cb0..69d5130 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -59,6 +59,7 @@
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 0ecfdb1..7af7f79 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -38,6 +38,9 @@
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 @@
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 2687410..751e203 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -128,7 +128,8 @@
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 f7a90b0..32b5132 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -134,7 +134,7 @@
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 0000000..447195d
--- /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 6642134..0000000
--- 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 0000000..1e69f16
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 0000000..e69de29
--- /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 000e68f..0000000
--- 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 fd7c87e..c9f9972 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -21,6 +21,8 @@
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 dadd327..49d60a7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -990,7 +990,8 @@
}
}
- private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
+ @VisibleForTesting
+ protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
if (network == null) {
return null;
}
@@ -3334,35 +3335,7 @@
&& 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 1ad1404..2c24798 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -69,13 +69,10 @@
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 @@
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 @@
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 19b61e6..c370959 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 @@
/**
* 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 daaedd8..dc65e1e 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 @@
// 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 @@
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 @@
}
}
+ /**
+ * 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 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 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;
+ // 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;
- 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);
+ 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 @@
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;
}
- sendProxyBroadcast(proxyProperties);
+ 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);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 0cba76b..f6b032e 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 @@
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 502a21c..5b2bc9e 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 @@
{
final int pid;
final String pkg;
- ITransientNotification callback;
+ final ITransientNotification callback;
int duration;
Binder token;
@@ -576,10 +576,6 @@
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 @@
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 @@
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 efd49b5..0ec24d8 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.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 @@
@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 f7e6840..4354314 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -36,8 +36,8 @@
/**
* 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 4ca5ce3..1db5850 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -44,11 +44,11 @@
/**
* 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 421b015..6ad44ba 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -35,7 +35,6 @@
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 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 c095438..4790b75 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 @@
/**
* 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 @@
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 0248e97..9838020 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -314,9 +314,9 @@
// 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 @@
// 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 d6018f1..5e5ba4d 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 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.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.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.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.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.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 @@
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 @@
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 @@
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);
+ }
}