summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ResourcesManager.java2
-rw-r--r--core/java/android/net/nsd/NsdManager.java14
-rw-r--r--core/java/android/os/SystemProperties.java80
-rw-r--r--core/jni/android_os_SystemProperties.cpp269
-rw-r--r--core/res/res/values/config.xml19
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rwxr-xr-xcore/tests/systemproperties/run_core_systemproperties_test.sh2
-rw-r--r--core/tests/systemproperties/src/android/os/SystemPropertiesTest.java76
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java16
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java2
-rw-r--r--services/core/Android.mk5
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java24
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java41
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java131
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java24
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java65
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java27
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java16
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java9
-rw-r--r--services/net/java/android/net/apf/ApfFilter.java53
-rw-r--r--services/net/java/android/net/ip/InterfaceController.java162
-rw-r--r--services/net/java/android/net/ip/IpManager.java151
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java2
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java1
-rw-r--r--telephony/java/com/android/internal/telephony/ExponentialBackoff.java84
-rw-r--r--tests/net/Android.mk2
-rw-r--r--tests/net/java/android/net/apf/ApfTest.java97
-rw-r--r--tests/net/java/android/net/nsd/NsdManagerTest.java30
-rw-r--r--tests/net/java/com/android/server/NsdServiceTest.java5
-rw-r--r--tests/net/java/com/android/server/connectivity/Nat464XlatTest.java226
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java84
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp1
36 files changed, 1268 insertions, 480 deletions
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 6f326de76150..80554fff75ac 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -961,7 +961,7 @@ public class ResourcesManager {
// TODO(adamlesinski): Make this accept more than just overlay directories.
final void applyNewResourceDirsLocked(@NonNull final String baseCodePath,
- @NonNull final String[] newResourceDirs) {
+ @Nullable final String[] newResourceDirs) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#applyNewResourceDirsLocked");
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 1e41eea925a5..535bf675cd0e 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -21,25 +21,24 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkStringNotEmpty;
import android.annotation.SdkConstant;
-import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemService;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.os.Messenger;
-import android.text.TextUtils;
+import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
-import java.util.concurrent.CountDownLatch;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
+import java.util.concurrent.CountDownLatch;
+
/**
* The Network Service Discovery Manager class provides the API to discover services
* on a network. As an example, if device A and device B are connected over a Wi-Fi
@@ -244,7 +243,7 @@ public final class NsdManager {
return name;
}
- private static int FIRST_LISTENER_KEY = 1;
+ private static final int FIRST_LISTENER_KEY = 1;
private final INsdManager mService;
private final Context mContext;
@@ -278,6 +277,7 @@ public final class NsdManager {
@VisibleForTesting
public void disconnect() {
mAsyncChannel.disconnect();
+ mHandler.getLooper().quitSafely();
}
/**
@@ -650,7 +650,7 @@ public final class NsdManager {
private static void checkServiceInfo(NsdServiceInfo serviceInfo) {
checkNotNull(serviceInfo, "NsdServiceInfo cannot be null");
- checkStringNotEmpty(serviceInfo.getServiceName(),"Service name cannot be empty");
+ checkStringNotEmpty(serviceInfo.getServiceName(), "Service name cannot be empty");
checkStringNotEmpty(serviceInfo.getServiceType(), "Service type cannot be empty");
}
}
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 8632194f2b02..560b4b31cdc6 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Log;
import android.util.MutableInt;
@@ -43,17 +45,12 @@ public class SystemProperties {
public static final int PROP_VALUE_MAX = 91;
+ @GuardedBy("sChangeCallbacks")
private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
@GuardedBy("sRoReads")
- private static final HashMap<String, MutableInt> sRoReads;
- static {
- if (TRACK_KEY_ACCESS) {
- sRoReads = new HashMap<>();
- } else {
- sRoReads = null;
- }
- }
+ private static final HashMap<String, MutableInt> sRoReads =
+ TRACK_KEY_ACCESS ? new HashMap<>() : null;
private static void onKeyAccess(String key) {
if (!TRACK_KEY_ACCESS) return;
@@ -85,77 +82,102 @@ public class SystemProperties {
private static native void native_report_sysprop_change();
/**
- * Get the value for the given key.
- * @return an empty string if the key isn't found
+ * Get the String value for the given {@code key}.
+ *
+ * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
+ * method will crash in native code.
+ *
+ * @param key the key to lookup
+ * @return an empty string if the {@code key} isn't found
*/
- public static String get(String key) {
+ @NonNull
+ public static String get(@NonNull String key) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key);
}
/**
- * Get the value for the given key.
- * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
+ * Get the String value for the given {@code key}.
+ *
+ * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
+ * method will crash in native code.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+ * string otherwise
*/
- public static String get(String key, String def) {
+ @NonNull
+ public static String get(@NonNull String key, @Nullable String def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key, def);
}
/**
- * Get the value for the given key, and return as an integer.
+ * Get the value for the given {@code key}, and return as an integer.
+ *
* @param key the key to lookup
* @param def a default value to return
* @return the key parsed as an integer, or def if the key isn't found or
* cannot be parsed
*/
- public static int getInt(String key, int def) {
+ public static int getInt(@NonNull String key, int def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_int(key, def);
}
/**
- * Get the value for the given key, and return as a long.
+ * Get the value for the given {@code key}, and return as a long.
+ *
* @param key the key to lookup
* @param def a default value to return
* @return the key parsed as a long, or def if the key isn't found or
* cannot be parsed
*/
- public static long getLong(String key, long def) {
+ public static long getLong(@NonNull String key, long def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_long(key, def);
}
/**
- * Get the value for the given key, returned as a boolean.
+ * Get the value for the given {@code key}, returned as a boolean.
* Values 'n', 'no', '0', 'false' or 'off' are considered false.
* Values 'y', 'yes', '1', 'true' or 'on' are considered true.
* (case sensitive).
* If the key does not exist, or has any other value, then the default
* result is returned.
+ *
* @param key the key to lookup
* @param def a default value to return
* @return the key parsed as a boolean, or def if the key isn't found or is
* not able to be parsed as a boolean.
*/
- public static boolean getBoolean(String key, boolean def) {
+ public static boolean getBoolean(@NonNull String key, boolean def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_boolean(key, def);
}
/**
- * Set the value for the given key.
- * @throws IllegalArgumentException if the value exceeds 92 characters
+ * Set the value for the given {@code key} to {@code val}.
+ *
+ * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
*/
- public static void set(String key, String val) {
+ public static void set(@NonNull String key, @Nullable String val) {
if (val != null && val.length() > PROP_VALUE_MAX) {
- throw newValueTooLargeException(key, val);
+ throw new IllegalArgumentException("value of system property '" + key
+ + "' is longer than " + PROP_VALUE_MAX + " characters: " + val);
}
if (TRACK_KEY_ACCESS) onKeyAccess(key);
native_set(key, val);
}
- public static void addChangeCallback(Runnable callback) {
+ /**
+ * Add a callback that will be run whenever any system property changes.
+ *
+ * @param callback The {@link Runnable} that should be executed when a system property
+ * changes.
+ */
+ public static void addChangeCallback(@NonNull Runnable callback) {
synchronized (sChangeCallbacks) {
if (sChangeCallbacks.size() == 0) {
native_add_change_callback();
@@ -164,7 +186,8 @@ public class SystemProperties {
}
}
- static void callChangeCallbacks() {
+ @SuppressWarnings("unused") // Called from native code.
+ private static void callChangeCallbacks() {
synchronized (sChangeCallbacks) {
//Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
if (sChangeCallbacks.size() == 0) {
@@ -177,11 +200,6 @@ public class SystemProperties {
}
}
- private static IllegalArgumentException newValueTooLargeException(String key, String value) {
- return new IllegalArgumentException("value of system property '" + key + "' is longer than "
- + PROP_VALUE_MAX + " characters: " + value);
- }
-
/*
* Notifies listeners that a system property has changed
*/
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 8844fb0a261f..a94cac0f18f5 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -17,188 +17,109 @@
#define LOG_TAG "SysPropJNI"
+#include "android-base/logging.h"
+#include "android-base/properties.h"
#include "cutils/properties.h"
#include "utils/misc.h"
#include <utils/Log.h>
#include "jni.h"
#include "core_jni_helpers.h"
#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
namespace android
{
-static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
- jstring keyJ, jstring defJ)
-{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- jstring rvJ = NULL;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if ((len <= 0) && (defJ != NULL)) {
- rvJ = defJ;
- } else if (len >= 0) {
- rvJ = env->NewStringUTF(buf);
- } else {
- rvJ = env->NewStringUTF("");
+namespace {
+
+template <typename T, typename Handler>
+T ConvertKeyAndForward(JNIEnv *env, jstring keyJ, T defJ, Handler handler) {
+ std::string key;
+ {
+ // Scope the String access. If the handler can throw an exception,
+ // releasing the string characters late would trigger an abort.
+ ScopedUtfChars key_utf(env, keyJ);
+ if (key_utf.c_str() == nullptr) {
+ return defJ;
+ }
+ key = key_utf.c_str(); // This will make a copy, but we can't avoid
+ // with the existing interface in
+ // android::base.
}
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return rvJ;
+ return handler(key, defJ);
}
-static jstring SystemProperties_getS(JNIEnv *env, jobject clazz,
- jstring keyJ)
+jstring SystemProperties_getSS(JNIEnv *env, jclass clazz, jstring keyJ,
+ jstring defJ)
{
- return SystemProperties_getSS(env, clazz, keyJ, NULL);
+ // Using ConvertKeyAndForward is sub-optimal for copying the key string,
+ // but improves reuse and reasoning over code.
+ auto handler = [&](const std::string& key, jstring defJ) {
+ std::string prop_val = android::base::GetProperty(key, "");
+ if (!prop_val.empty()) {
+ return env->NewStringUTF(prop_val.c_str());
+ };
+ if (defJ != nullptr) {
+ return defJ;
+ }
+ // This function is specified to never return null (or have an
+ // exception pending).
+ return env->NewStringUTF("");
+ };
+ return ConvertKeyAndForward(env, keyJ, defJ, handler);
}
-static jint SystemProperties_get_int(JNIEnv *env, jobject clazz,
- jstring keyJ, jint defJ)
+jstring SystemProperties_getS(JNIEnv *env, jclass clazz, jstring keyJ)
{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- char* end;
- jint result = defJ;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if (len > 0) {
- result = strtol(buf, &end, 0);
- if (end == buf) {
- result = defJ;
- }
- }
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return result;
+ return SystemProperties_getSS(env, clazz, keyJ, nullptr);
}
-static jlong SystemProperties_get_long(JNIEnv *env, jobject clazz,
- jstring keyJ, jlong defJ)
+template <typename T>
+T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ,
+ T defJ)
{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- char* end;
- jlong result = defJ;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if (len > 0) {
- result = strtoll(buf, &end, 0);
- if (end == buf) {
- result = defJ;
- }
- }
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return result;
+ auto handler = [](const std::string& key, T defV) {
+ return android::base::GetIntProperty<T>(key, defV);
+ };
+ return ConvertKeyAndForward(env, keyJ, defJ, handler);
}
-static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz,
- jstring keyJ, jboolean defJ)
+jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ,
+ jboolean defJ)
{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- jboolean result = defJ;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if (len == 1) {
- char ch = buf[0];
- if (ch == '0' || ch == 'n')
- result = false;
- else if (ch == '1' || ch == 'y')
- result = true;
- } else if (len > 1) {
- if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
- result = false;
- } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
- result = true;
- }
- }
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return result;
+ auto handler = [](const std::string& key, jboolean defV) -> jboolean {
+ bool result = android::base::GetBoolProperty(key, defV);
+ return result ? JNI_TRUE : JNI_FALSE;
+ };
+ return ConvertKeyAndForward(env, keyJ, defJ, handler);
}
-static void SystemProperties_set(JNIEnv *env, jobject clazz,
- jstring keyJ, jstring valJ)
+void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
+ jstring valJ)
{
- int err;
- const char* key;
- const char* val;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- return ;
- }
- key = env->GetStringUTFChars(keyJ, NULL);
-
- if (valJ == NULL) {
- val = ""; /* NULL pointer not allowed here */
- } else {
- val = env->GetStringUTFChars(valJ, NULL);
- }
-
- err = property_set(key, val);
-
- env->ReleaseStringUTFChars(keyJ, key);
-
- if (valJ != NULL) {
- env->ReleaseStringUTFChars(valJ, val);
- }
-
- if (err < 0) {
+ auto handler = [&](const std::string& key, bool) {
+ std::string val;
+ if (valJ != nullptr) {
+ ScopedUtfChars key_utf(env, valJ);
+ val = key_utf.c_str();
+ }
+ return android::base::SetProperty(key, val);
+ };
+ if (!ConvertKeyAndForward(env, keyJ, true, handler)) {
+ // Must have been a failure in SetProperty.
jniThrowException(env, "java/lang/RuntimeException",
"failed to set system property");
}
}
-static JavaVM* sVM = NULL;
-static jclass sClazz = NULL;
-static jmethodID sCallChangeCallbacks;
+JavaVM* sVM = nullptr;
+jclass sClazz = nullptr;
+jmethodID sCallChangeCallbacks;
-static void do_report_sysprop_change() {
+void do_report_sysprop_change() {
//ALOGI("Java SystemProperties: VM=%p, Clazz=%p", sVM, sClazz);
- if (sVM != NULL && sClazz != NULL) {
+ if (sVM != nullptr && sClazz != nullptr) {
JNIEnv* env;
if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) {
//ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks);
@@ -207,47 +128,49 @@ static void do_report_sysprop_change() {
}
}
-static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
+void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
{
// This is called with the Java lock held.
- if (sVM == NULL) {
+ if (sVM == nullptr) {
env->GetJavaVM(&sVM);
}
- if (sClazz == NULL) {
+ if (sClazz == nullptr) {
sClazz = (jclass) env->NewGlobalRef(clazz);
sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V");
add_sysprop_change_callback(do_report_sysprop_change, -10000);
}
}
-static void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
+void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
{
report_sysprop_change();
}
-static const JNINativeMethod method_table[] = {
- { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
- (void*) SystemProperties_getS },
- { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
- (void*) SystemProperties_getSS },
- { "native_get_int", "(Ljava/lang/String;I)I",
- (void*) SystemProperties_get_int },
- { "native_get_long", "(Ljava/lang/String;J)J",
- (void*) SystemProperties_get_long },
- { "native_get_boolean", "(Ljava/lang/String;Z)Z",
- (void*) SystemProperties_get_boolean },
- { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
- (void*) SystemProperties_set },
- { "native_add_change_callback", "()V",
- (void*) SystemProperties_add_change_callback },
- { "native_report_sysprop_change", "()V",
- (void*) SystemProperties_report_sysprop_change },
-};
+} // namespace
int register_android_os_SystemProperties(JNIEnv *env)
{
- return RegisterMethodsOrDie(env, "android/os/SystemProperties", method_table,
- NELEM(method_table));
+ const JNINativeMethod method_table[] = {
+ { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) SystemProperties_getS },
+ { "native_get",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) SystemProperties_getSS },
+ { "native_get_int", "(Ljava/lang/String;I)I",
+ (void*) SystemProperties_get_integral<jint> },
+ { "native_get_long", "(Ljava/lang/String;J)J",
+ (void*) SystemProperties_get_integral<jlong> },
+ { "native_get_boolean", "(Ljava/lang/String;Z)Z",
+ (void*) SystemProperties_get_boolean },
+ { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
+ (void*) SystemProperties_set },
+ { "native_add_change_callback", "()V",
+ (void*) SystemProperties_add_change_callback },
+ { "native_report_sysprop_change", "()V",
+ (void*) SystemProperties_report_sysprop_change },
+ };
+ return RegisterMethodsOrDie(env, "android/os/SystemProperties",
+ method_table, NELEM(method_table));
}
};
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 899551371f30..70c39afbc441 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -296,6 +296,17 @@
less than 0x600 -->
<bool translatable="false" name="config_apfDrop802_3Frames">true</bool>
+ <!-- An array of Black listed EtherType, packets with EtherTypes within this array
+ will be dropped
+ TODO: need to put proper values, these are for testing purposes only -->
+ <integer-array translatable="false" name="config_apfEthTypeBlackList">
+ <item>0x88A2</item>
+ <item>0x88A4</item>
+ <item>0x88B8</item>
+ <item>0x88CD</item>
+ <item>0x88E3</item>
+ </integer-array>
+
<!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE.
This is the default value of that setting. -->
@@ -1493,16 +1504,16 @@
<integer translatable="false" name="config_bluetooth_max_advertisers">0</integer>
<!-- Idle current for bluetooth controller. 0 by default-->
- <integer translatable="false" name="config_bluetooth_idle_cur_ma">1</integer>
+ <integer translatable="false" name="config_bluetooth_idle_cur_ma">0</integer>
<!-- Rx current for bluetooth controller. 0 by default-->
- <integer translatable="false" name="config_bluetooth_rx_cur_ma">2</integer>
+ <integer translatable="false" name="config_bluetooth_rx_cur_ma">0</integer>
<!-- Tx current for bluetooth controller. 0 by default-->
- <integer translatable="false" name="config_bluetooth_tx_cur_ma">3</integer>
+ <integer translatable="false" name="config_bluetooth_tx_cur_ma">0</integer>
<!-- Operating volatage for bluetooth controller. 0 by default-->
- <integer translatable="false" name="config_bluetooth_operating_voltage_mv">4</integer>
+ <integer translatable="false" name="config_bluetooth_operating_voltage_mv">0</integer>
<!-- Whether supported profiles should be reloaded upon enabling bluetooth -->
<bool name="config_bluetooth_reload_supported_profiles_when_enabled">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c5275017a7cf..600c82f87d90 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1837,6 +1837,7 @@
<java-symbol type="integer" name="config_networkWakeupPacketMark" />
<java-symbol type="integer" name="config_networkWakeupPacketMask" />
<java-symbol type="bool" name="config_apfDrop802_3Frames" />
+ <java-symbol type="array" name="config_apfEthTypeBlackList" />
<java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
<java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
<java-symbol type="integer" name="config_notificationsBatteryLedOff" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7e9f561e68d5..f5b350b053d4 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -181,7 +181,7 @@
<shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
<!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="46645|5050|26259|50025|50052|9963" />
+ <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="46645|5050|26259|50025|50052|9963|76551" />
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" />
diff --git a/core/tests/systemproperties/run_core_systemproperties_test.sh b/core/tests/systemproperties/run_core_systemproperties_test.sh
index d39adbbfa390..9b1fe4be666b 100755
--- a/core/tests/systemproperties/run_core_systemproperties_test.sh
+++ b/core/tests/systemproperties/run_core_systemproperties_test.sh
@@ -15,7 +15,7 @@ fi
if [[ $rebuild == true ]]; then
make -j4 FrameworksCoreSystemPropertiesTests
- TESTAPP=${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreSystemPropertiesTests.apk
+ TESTAPP=${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreSystemPropertiesTests/FrameworksCoreSystemPropertiesTests.apk
COMMAND="adb install -r $TESTAPP"
echo $COMMAND
$COMMAND
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 544a96727217..282b0011eede 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -51,6 +51,11 @@ public class SystemPropertiesTest extends TestCase {
value = SystemProperties.get(KEY, "default");
assertEquals("default", value);
+ // null default value is the same as "".
+ SystemProperties.set(KEY, null);
+ value = SystemProperties.get(KEY, "default");
+ assertEquals("default", value);
+
SystemProperties.set(KEY, "SA");
value = SystemProperties.get(KEY, "default");
assertEquals("SA", value);
@@ -62,7 +67,78 @@ public class SystemPropertiesTest extends TestCase {
value = SystemProperties.get(KEY, "default");
assertEquals("default", value);
+ // null value is the same as "".
+ SystemProperties.set(KEY, "SA");
+ SystemProperties.set(KEY, null);
+ value = SystemProperties.get(KEY, "default");
+ assertEquals("default", value);
+
value = SystemProperties.get(KEY);
assertEquals("", value);
}
+
+ private static void testInt(String setVal, int defValue, int expected) {
+ SystemProperties.set(KEY, setVal);
+ int value = SystemProperties.getInt(KEY, defValue);
+ assertEquals(expected, value);
+ }
+
+ private static void testLong(String setVal, long defValue, long expected) {
+ SystemProperties.set(KEY, setVal);
+ long value = SystemProperties.getLong(KEY, defValue);
+ assertEquals(expected, value);
+ }
+
+ @SmallTest
+ public void testIntegralProperties() throws Exception {
+ testInt("", 123, 123);
+ testInt("", 0, 0);
+ testInt("", -123, -123);
+
+ testInt("123", 124, 123);
+ testInt("0", 124, 0);
+ testInt("-123", 124, -123);
+
+ testLong("", 3147483647L, 3147483647L);
+ testLong("", 0, 0);
+ testLong("", -3147483647L, -3147483647L);
+
+ testLong("3147483647", 124, 3147483647L);
+ testLong("0", 124, 0);
+ testLong("-3147483647", 124, -3147483647L);
+ }
+
+ @SmallTest
+ @SuppressWarnings("null")
+ public void testNullKey() throws Exception {
+ try {
+ SystemProperties.get(null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.get(null, "default");
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.set(null, "value");
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.getInt(null, 0);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.getLong(null, 0);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 0cf890037f55..fe03fba5bfda 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -58,9 +58,19 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onSimStateChanged(int subId, int slotId, State simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
- resetState();
- };
+ if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ switch(simState) {
+ // If the SIM is removed, then we must remove the keyguard. It will be put up
+ // again when the PUK locked SIM is re-entered.
+ case ABSENT: {
+ KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(mSubId);
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ break;
+ }
+ default:
+ resetState();
+ }
+ }
};
public KeyguardSimPinView(Context context) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index fb3cee74ab68..826a03d1b658 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -60,9 +60,23 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onSimStateChanged(int subId, int slotId, State simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
- resetState();
- };
+ if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ switch(simState) {
+ // If the SIM is removed, then we must remove the keyguard. It will be put up
+ // again when the PUK locked SIM is re-entered.
+ case ABSENT:
+ // intentional fall-through
+ // If the SIM is unlocked via a key sequence through the emergency dialer, it will
+ // move into the READY state and the PUK lock keyguard should be removed.
+ case READY: {
+ KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(mSubId);
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ break;
+ }
+ default:
+ resetState();
+ }
+ }
};
public KeyguardSimPukView(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 2473335e6e15..cef7c8ac9a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -170,7 +170,8 @@ public class QSFooter extends FrameLayout implements
int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
mAnimator = new Builder()
- .addFloat(mSettingsContainer, "translationX", -(remaining - defSpace), 0)
+ .addFloat(mSettingsContainer, "translationX",
+ isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
.addFloat(mSettingsButton, "rotation", -120, 0)
.build();
if (mAlarmShowing) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 0a0d2ce00a1b..bdc5e7d75b48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -556,7 +556,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
@Override
public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
- if (viewHolder.getItemViewType() == TYPE_EDIT) {
+ if (viewHolder.getItemViewType() == TYPE_EDIT || viewHolder.getItemViewType() == TYPE_DIVIDER) {
return makeMovementFlags(0, 0);
}
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 7e82edaae3e5..b1ac5891dafa 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -690,6 +690,7 @@ class MagnificationGestureHandler implements EventStreamTransformation {
}
break;
case MotionEvent.ACTION_UP: {
+ mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
if (!mMagnificationController.magnificationRegionContains(
event.getX(), event.getY())) {
transitionToDelegatingState(!mShortcutTriggered);
@@ -703,7 +704,6 @@ class MagnificationGestureHandler implements EventStreamTransformation {
if (mLastDownEvent == null) {
return;
}
- mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
if (!GestureUtils.isTap(mLastDownEvent, event, mTapTimeSlop,
mTapDistanceSlop, 0)) {
transitionToDelegatingState(true);
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 7fca21f71a6a..f61fd550885b 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -4,7 +4,10 @@ include $(CLEAR_VARS)
LOCAL_MODULE := services.core
-LOCAL_AIDL_INCLUDES := system/netd/server/binder
+LOCAL_AIDL_INCLUDES := \
+ frameworks/native/aidl/binder \
+ system/netd/server/binder
+
LOCAL_SRC_FILES += \
$(call all-java-files-under,java) \
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index fb20533837af..60476447ca49 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -458,6 +458,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int MAX_WAKELOCK_LOGS = 20;
private final LocalLog mWakelockLogs = new LocalLog(MAX_WAKELOCK_LOGS);
+ private int mTotalWakelockAcquisitions = 0;
+ private int mTotalWakelockReleases = 0;
+ private long mTotalWakelockDurationMs = 0;
+ private long mMaxWakelockDurationMs = 0;
+ private long mLastWakeLockAcquireTimestamp = 0;
// Array of <Network,ReadOnlyLocalLogs> tracking network validation and results
private static final int MAX_VALIDATION_LOGS = 10;
@@ -1959,6 +1964,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.println();
pw.println("NetTransition WakeLock activity (most recent first):");
pw.increaseIndent();
+ pw.println("total acquisitions: " + mTotalWakelockAcquisitions);
+ pw.println("total releases: " + mTotalWakelockReleases);
+ pw.println("cumulative duration: " + (mTotalWakelockDurationMs / 1000) + "s");
+ pw.println("longest duration: " + (mMaxWakelockDurationMs / 1000) + "s");
+ if (mTotalWakelockAcquisitions > mTotalWakelockReleases) {
+ long duration = SystemClock.elapsedRealtime() - mLastWakeLockAcquireTimestamp;
+ pw.println("currently holding WakeLock for: " + (duration / 1000) + "s");
+ }
mWakelockLogs.reverseDump(fd, pw, args);
pw.decreaseIndent();
}
@@ -3012,6 +3025,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
mNetTransitionWakeLock.acquire();
+ mLastWakeLockAcquireTimestamp = SystemClock.elapsedRealtime();
+ mTotalWakelockAcquisitions++;
}
mWakelockLogs.log("ACQUIRE for " + forWhom);
Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
@@ -3044,6 +3059,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
mNetTransitionWakeLock.release();
+ long lockDuration = SystemClock.elapsedRealtime() - mLastWakeLockAcquireTimestamp;
+ mTotalWakelockDurationMs += lockDuration;
+ mMaxWakelockDurationMs = Math.max(mMaxWakelockDurationMs, lockDuration);
+ mTotalWakelockReleases++;
}
mWakelockLogs.log(String.format("RELEASE (%s)", event));
}
@@ -4616,6 +4635,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
+ if (mNetworkForNetId.get(nai.network.netId) != nai) {
+ // Ignore updates for disconnected networks
+ return;
+ }
+
if (VDBG) {
log("Update of LinkProperties for " + nai.name() +
"; created=" + nai.created +
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 3e4453204b14..caa2d5112bf0 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -76,6 +76,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
+import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
@@ -1897,38 +1898,34 @@ public class NetworkManagementService extends INetworkManagementService.Stub
return new NetworkStats(SystemClock.elapsedRealtime(), 0);
}
- final NativeDaemonEvent[] events;
+ final PersistableBundle bundle;
try {
- events = mConnector.executeForList("bandwidth", "gettetherstats");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ bundle = mNetdService.tetherGetStats();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException("problem parsing tethering stats: ", e);
}
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
- for (NativeDaemonEvent event : events) {
- if (event.getCode() != TetheringStatsListResult) continue;
- // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
- final StringTokenizer tok = new StringTokenizer(event.getMessage());
- try {
- final String ifaceIn = tok.nextToken();
- final String ifaceOut = tok.nextToken();
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(),
+ bundle.size());
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- entry.iface = ifaceOut;
+ for (String iface : bundle.keySet()) {
+ long[] statsArray = bundle.getLongArray(iface);
+ try {
+ entry.iface = iface;
entry.uid = UID_TETHERING;
entry.set = SET_DEFAULT;
entry.tag = TAG_NONE;
- entry.rxBytes = Long.parseLong(tok.nextToken());
- entry.rxPackets = Long.parseLong(tok.nextToken());
- entry.txBytes = Long.parseLong(tok.nextToken());
- entry.txPackets = Long.parseLong(tok.nextToken());
+ entry.rxBytes = statsArray[INetd.TETHER_STATS_RX_BYTES];
+ entry.rxPackets = statsArray[INetd.TETHER_STATS_RX_PACKETS];
+ entry.txBytes = statsArray[INetd.TETHER_STATS_TX_BYTES];
+ entry.txPackets = statsArray[INetd.TETHER_STATS_TX_PACKETS];
stats.combineValues(entry);
- } catch (NoSuchElementException e) {
- throw new IllegalStateException("problem parsing tethering stats: " + event);
- } catch (NumberFormatException e) {
- throw new IllegalStateException("problem parsing tethering stats: " + event);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalStateException("invalid tethering stats for " + iface, e);
}
}
+
return stats;
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 10c8b8b1e0aa..e6585ad194ec 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -33,7 +33,7 @@ import java.util.Objects;
/**
* Class to manage a 464xlat CLAT daemon. Nat464Xlat is not thread safe and should be manipulated
- * from a consistent and unique thread context. It is the responsability of ConnectivityService to
+ * from a consistent and unique thread context. It is the responsibility of ConnectivityService to
* call into this class from its own Handler thread.
*
* @hide
@@ -60,7 +60,9 @@ public class Nat464Xlat extends BaseNetworkObserver {
private enum State {
IDLE, // start() not called. Base iface and stacked iface names are null.
STARTING, // start() called. Base iface and stacked iface names are known.
- RUNNING; // start() called, and the stacked iface is known to be up.
+ RUNNING, // start() called, and the stacked iface is known to be up.
+ STOPPING; // stop() called, this Nat464Xlat is still registered as a network observer for
+ // the stacked interface.
}
private String mBaseIface;
@@ -81,6 +83,8 @@ public class Nat464Xlat extends BaseNetworkObserver {
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
final int netType = nai.networkInfo.getType();
final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
+ // TODO: this should also consider if the network is in SUSPENDED state to avoid stopping
+ // clatd in SUSPENDED state.
final boolean connected = nai.networkInfo.isConnected();
// We only run clat on networks that don't have a native IPv4 address.
final boolean hasIPv4Address =
@@ -111,18 +115,70 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
/**
- * Sets internal state.
+ * @return true if clatd has been stopped.
+ */
+ public boolean isStopping() {
+ return mState == State.STOPPING;
+ }
+
+ /**
+ * Start clatd, register this Nat464Xlat as a network observer for the stacked interface,
+ * and set internal state.
*/
private void enterStartingState(String baseIface) {
+ try {
+ mNMService.registerObserver(this);
+ } catch(RemoteException e) {
+ Slog.e(TAG,
+ "startClat: Can't register interface observer for clat on " + mNetwork.name());
+ return;
+ }
+ try {
+ mNMService.startClatd(baseIface);
+ } catch(RemoteException|IllegalStateException e) {
+ Slog.e(TAG, "Error starting clatd on " + baseIface, e);
+ }
mIface = CLAT_PREFIX + baseIface;
mBaseIface = baseIface;
mState = State.STARTING;
}
/**
- * Clears internal state.
+ * Enter running state just after getting confirmation that the stacked interface is up, and
+ * turn ND offload off if on WiFi.
+ */
+ private void enterRunningState() {
+ maybeSetIpv6NdOffload(mBaseIface, false);
+ mState = State.RUNNING;
+ }
+
+ /**
+ * Stop clatd, and turn ND offload on if it had been turned off.
+ */
+ private void enterStoppingState() {
+ if (isRunning()) {
+ maybeSetIpv6NdOffload(mBaseIface, true);
+ }
+
+ try {
+ mNMService.stopClatd(mBaseIface);
+ } catch(RemoteException|IllegalStateException e) {
+ Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
+ }
+
+ mState = State.STOPPING;
+ }
+
+ /**
+ * Unregister as a base observer for the stacked interface, and clear internal state.
*/
private void enterIdleState() {
+ try {
+ mNMService.unregisterObserver(this);
+ } catch(RemoteException|IllegalStateException e) {
+ Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface, e);
+ }
+
mIface = null;
mBaseIface = null;
mState = State.IDLE;
@@ -142,27 +198,14 @@ public class Nat464Xlat extends BaseNetworkObserver {
return;
}
- try {
- mNMService.registerObserver(this);
- } catch(RemoteException e) {
- Slog.e(TAG, "startClat: Can't register interface observer for clat on " + mNetwork);
- return;
- }
-
String baseIface = mNetwork.linkProperties.getInterfaceName();
if (baseIface == null) {
Slog.e(TAG, "startClat: Can't start clat on null interface");
return;
}
// TODO: should we only do this if mNMService.startClatd() succeeds?
+ Slog.i(TAG, "Starting clatd on " + baseIface);
enterStartingState(baseIface);
-
- Slog.i(TAG, "Starting clatd on " + mBaseIface);
- try {
- mNMService.startClatd(mBaseIface);
- } catch(RemoteException|IllegalStateException e) {
- Slog.e(TAG, "Error starting clatd on " + mBaseIface, e);
- }
}
/**
@@ -170,18 +213,15 @@ public class Nat464Xlat extends BaseNetworkObserver {
*/
public void stop() {
if (!isStarted()) {
- Slog.e(TAG, "stopClat: already stopped or not started");
return;
}
-
Slog.i(TAG, "Stopping clatd on " + mBaseIface);
- try {
- mNMService.stopClatd(mBaseIface);
- } catch(RemoteException|IllegalStateException e) {
- Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
+
+ boolean wasStarting = isStarting();
+ enterStoppingState();
+ if (wasStarting) {
+ enterIdleState();
}
- // When clatd stops and its interface is deleted, handleInterfaceRemoved() will trigger
- // ConnectivityService#handleUpdateLinkProperties and call enterIdleState().
}
/**
@@ -255,55 +295,52 @@ public class Nat464Xlat extends BaseNetworkObserver {
if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
return;
}
+
LinkAddress clatAddress = getLinkAddress(iface);
if (clatAddress == null) {
- Slog.e(TAG, "cladAddress was null for stacked iface " + iface);
+ Slog.e(TAG, "clatAddress was null for stacked iface " + iface);
return;
}
- mState = State.RUNNING;
+
Slog.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
mIface, mIface, mBaseIface));
-
- maybeSetIpv6NdOffload(mBaseIface, false);
+ enterRunningState();
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
lp.addStackedLink(makeLinkProperties(clatAddress));
- mNetwork.connService.handleUpdateLinkProperties(mNetwork, lp);
+ mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
}
/**
* Removes stacked link on base link and transitions to IDLE state.
*/
private void handleInterfaceRemoved(String iface) {
- if (!isRunning() || !Objects.equals(mIface, iface)) {
+ if (!Objects.equals(mIface, iface)) {
+ return;
+ }
+ if (!isRunning() && !isStopping()) {
return;
}
Slog.i(TAG, "interface " + iface + " removed");
- // The interface going away likely means clatd has crashed. Ask netd to stop it,
- // because otherwise when we try to start it again on the same base interface netd
- // will complain that it's already started.
- try {
- mNMService.unregisterObserver(this);
- // TODO: add STOPPING state to avoid calling stopClatd twice.
- mNMService.stopClatd(mBaseIface);
- } catch(RemoteException|IllegalStateException e) {
- Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
+ if (!isStopping()) {
+ // Ensure clatd is stopped if stop() has not been called: this likely means that clatd
+ // has crashed.
+ enterStoppingState();
}
- maybeSetIpv6NdOffload(mBaseIface, true);
- LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
- lp.removeStackedLink(mIface);
enterIdleState();
- mNetwork.connService.handleUpdateLinkProperties(mNetwork, lp);
+ LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
+ lp.removeStackedLink(iface);
+ mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
}
@Override
public void interfaceLinkStateChanged(String iface, boolean up) {
- mNetwork.handler.post(() -> { handleInterfaceLinkStateChanged(iface, up); });
+ mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); });
}
@Override
public void interfaceRemoved(String iface) {
- mNetwork.handler.post(() -> { handleInterfaceRemoved(iface); });
+ mNetwork.handler().post(() -> { handleInterfaceRemoved(iface); });
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 7c4ef0f0f3b9..e96f4b0383cb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -249,9 +249,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
private static final String TAG = ConnectivityService.class.getSimpleName();
private static final boolean VDBG = false;
- public final ConnectivityService connService;
+ private final ConnectivityService mConnService;
private final Context mContext;
- final Handler handler;
+ private final Handler mHandler;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
@@ -263,13 +263,21 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
linkProperties = lp;
networkCapabilities = nc;
currentScore = score;
- this.connService = connService;
+ mConnService = connService;
mContext = context;
- this.handler = handler;
- networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
+ mHandler = handler;
+ networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
networkMisc = misc;
}
+ public ConnectivityService connService() {
+ return mConnService;
+ }
+
+ public Handler handler() {
+ return mHandler;
+ }
+
// Functions for manipulating the requests satisfied by this network.
//
// These functions must only called on ConnectivityService's main thread.
@@ -432,7 +440,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
private boolean ignoreWifiUnvalidationPenalty() {
boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- boolean avoidBadWifi = connService.avoidBadWifi() || avoidUnvalidated;
+ boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
return isWifi && !avoidBadWifi && everValidated;
}
@@ -516,8 +524,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
}
if (newExpiry > 0) {
- mLingerMessage = connService.makeWakeupMessage(
- mContext, handler,
+ mLingerMessage = mConnService.makeWakeupMessage(
+ mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.netId,
EVENT_NETWORK_LINGER_COMPLETE, this);
mLingerMessage.schedule(newExpiry);
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 6d5c428e58f8..788867f9137e 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -63,6 +63,8 @@ import java.util.concurrent.TimeUnit;
*/
public class OffloadController {
private static final String TAG = OffloadController.class.getSimpleName();
+ private static final String ANYIP = "0.0.0.0";
+ private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
@@ -148,6 +150,14 @@ public class OffloadController {
public void onStoppedUnsupported() {
if (!started()) return;
mLog.log("onStoppedUnsupported");
+ // Poll for statistics and trigger a sweep of tethering
+ // stats by observers. This might not succeed, but it's
+ // worth trying anyway. We need to do this because from
+ // this point on we continue with software forwarding,
+ // and we need to synchronize stats and limits between
+ // software and hardware forwarding.
+ updateStatsForAllUpstreams();
+ forceTetherStatsPoll();
}
@Override
@@ -155,11 +165,15 @@ public class OffloadController {
if (!started()) return;
mLog.log("onSupportAvailable");
- // [1] Poll for statistics and notify NetworkStats
- // [2] (Re)Push all state:
- // [a] push local prefixes
- // [b] push downstreams
- // [c] push upstream parameters
+ // [1] Poll for statistics and trigger a sweep of stats
+ // by observers. We need to do this to ensure that any
+ // limits set take into account any software tethering
+ // traffic that has been happening in the meantime.
+ updateStatsForAllUpstreams();
+ forceTetherStatsPoll();
+ // [2] (Re)Push all state.
+ // TODO: computeAndPushLocalPrefixes()
+ // TODO: push all downstream state.
pushUpstreamParameters(null);
}
@@ -181,12 +195,7 @@ public class OffloadController {
// The stats for the previous upstream were already updated on this thread
// just after the upstream was changed, so they are also up-to-date.
updateStatsForCurrentUpstream();
-
- try {
- mNms.tetherLimitReached(mStatsProvider);
- } catch (RemoteException e) {
- mLog.e("Cannot report data limit reached: " + e);
- }
+ forceTetherStatsPoll();
}
@Override
@@ -305,13 +314,33 @@ public class OffloadController {
maybeUpdateStats(currentUpstreamInterface());
}
+ private void updateStatsForAllUpstreams() {
+ // In practice, there should only ever be a single digit number of
+ // upstream interfaces over the lifetime of an active tethering session.
+ // Roughly speaking, imagine a very ambitious one or two of each of the
+ // following interface types: [ "rmnet_data", "wlan", "eth", "rndis" ].
+ for (Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) {
+ maybeUpdateStats(kv.getKey());
+ }
+ }
+
+ private void forceTetherStatsPoll() {
+ try {
+ mNms.tetherLimitReached(mStatsProvider);
+ } catch (RemoteException e) {
+ mLog.e("Cannot report data limit reached: " + e);
+ }
+ }
+
public void setUpstreamLinkProperties(LinkProperties lp) {
if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
- String prevUpstream = (mUpstreamLinkProperties != null) ?
- mUpstreamLinkProperties.getInterfaceName() : null;
+ final String prevUpstream = currentUpstreamInterface();
mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
+ // Make sure we record this interface in the ForwardedStats map.
+ final String iface = currentUpstreamInterface();
+ if (!TextUtils.isEmpty(iface)) mForwardedStats.putIfAbsent(iface, EMPTY_STATS);
// TODO: examine return code and decide what to do if programming
// upstream parameters fails (probably just wait for a subsequent
@@ -378,16 +407,20 @@ public class OffloadController {
}
private boolean pushUpstreamParameters(String prevUpstream) {
- if (mUpstreamLinkProperties == null) {
+ final String iface = currentUpstreamInterface();
+
+ if (TextUtils.isEmpty(iface)) {
+ final boolean rval = mHwInterface.setUpstreamParameters("", ANYIP, ANYIP, null);
+ // Update stats after we've told the hardware to stop forwarding so
+ // we don't miss packets.
maybeUpdateStats(prevUpstream);
- return mHwInterface.setUpstreamParameters(null, null, null, null);
+ return rval;
}
// A stacked interface cannot be an upstream for hardware offload.
// Consequently, we examine only the primary interface name, look at
// getAddresses() rather than getAllAddresses(), and check getRoutes()
// rather than getAllRoutes().
- final String iface = mUpstreamLinkProperties.getInterfaceName();
final ArrayList<String> v6gateways = new ArrayList<>();
String v4addr = null;
String v4gateway = null;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 57d2502c6dc7..17adb1a74e30 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -27,6 +27,7 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.ip.InterfaceController;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.net.util.NetdService;
@@ -107,8 +108,10 @@ public class TetherInterfaceStateMachine extends StateMachine {
private final SharedLog mLog;
private final INetworkManagementService mNMService;
+ private final INetd mNetd;
private final INetworkStatsService mStatsService;
private final IControlsTethering mTetherController;
+ private final InterfaceController mInterfaceCtrl;
private final String mIfaceName;
private final int mInterfaceType;
@@ -136,8 +139,11 @@ public class TetherInterfaceStateMachine extends StateMachine {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
mNMService = nMService;
+ // TODO: This should be passed in for testability.
+ mNetd = NetdService.getInstance();
mStatsService = statsService;
mTetherController = tetherController;
+ mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
mIfaceName = ifaceName;
mInterfaceType = interfaceType;
mLinkProperties = new LinkProperties();
@@ -179,6 +185,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
private void stopIPv4() { configureIPv4(false); }
+ // TODO: Refactor this in terms of calls to InterfaceController.
private boolean configureIPv4(boolean enabled) {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
@@ -381,8 +388,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
private void configureLocalIPv6Dns(
HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
- final INetd netd = NetdService.getInstance();
- if (netd == null) {
+ // TODO: Is this really necessary? Can we not fail earlier if INetd cannot be located?
+ if (mNetd == null) {
if (newDnses != null) newDnses.clear();
mLog.e("No netd service instance available; not setting local IPv6 addresses");
return;
@@ -391,11 +398,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
// [1] Remove deprecated local DNS IP addresses.
if (!deprecatedDnses.isEmpty()) {
for (Inet6Address dns : deprecatedDnses) {
- final String dnsString = dns.getHostAddress();
- try {
- netd.interfaceDelAddress(mIfaceName, dnsString, RFC7421_PREFIX_LENGTH);
- } catch (ServiceSpecificException | RemoteException e) {
- mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
+ if (!mInterfaceCtrl.removeAddress(dns, RFC7421_PREFIX_LENGTH)) {
+ mLog.e("Failed to remove local dns IP " + dns);
}
mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
@@ -410,11 +414,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
}
for (Inet6Address dns : addedDnses) {
- final String dnsString = dns.getHostAddress();
- try {
- netd.interfaceAddAddress(mIfaceName, dnsString, RFC7421_PREFIX_LENGTH);
- } catch (ServiceSpecificException | RemoteException e) {
- mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
+ if (!mInterfaceCtrl.addAddress(dns, RFC7421_PREFIX_LENGTH)) {
+ mLog.e("Failed to add local dns IP " + dns);
newDnses.remove(dns);
}
@@ -423,7 +424,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
}
try {
- netd.tetherApplyDnsInterfaces();
+ mNetd.tetherApplyDnsInterfaces();
} catch (ServiceSpecificException | RemoteException e) {
mLog.e("Failed to update local DNS caching server");
if (newDnses != null) newDnses.clear();
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 04d91f882d04..807c343d0d10 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -92,26 +92,10 @@ class IdmapManager {
return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())).isFile();
}
- boolean isDangerous(@NonNull final PackageInfo overlayPackage, final int userId) {
- // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
- return isDangerous(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath()));
- }
-
private String getIdmapPath(@NonNull final String baseCodePath) {
final StringBuilder sb = new StringBuilder("/data/resource-cache/");
sb.append(baseCodePath.substring(1).replace('/', '@'));
sb.append("@idmap");
return sb.toString();
}
-
- private boolean isDangerous(@NonNull final String idmapPath) {
- try (DataInputStream dis = new DataInputStream(new FileInputStream(idmapPath))) {
- final int magic = dis.readInt();
- final int version = dis.readInt();
- final int dangerous = dis.readInt();
- return dangerous != 0;
- } catch (IOException e) {
- return true;
- }
- }
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index db6e9749535b..c3957f432f4c 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -169,8 +169,9 @@ final class OverlayManagerServiceImpl {
}
final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
- updateAllOverlaysForTarget(packageName, userId, targetPackage);
- mListener.onOverlaysChanged(packageName, userId);
+ if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
@@ -210,7 +211,9 @@ final class OverlayManagerServiceImpl {
Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, null);
+ if (updateAllOverlaysForTarget(packageName, userId, null)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
/**
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 8cb2df761fbe..190b3a613ca1 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -180,6 +180,7 @@ public class ApfFilter {
private static final int ETH_DEST_ADDR_OFFSET = 0;
private static final int ETH_ETHERTYPE_OFFSET = 12;
private static final int ETH_TYPE_MIN = 0x0600;
+ private static final int ETH_TYPE_MAX = 0xFFFF;
private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
// TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
@@ -232,6 +233,9 @@ public class ApfFilter {
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
// Do not log ApfProgramEvents whose actual lifetimes was less than this.
private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
+ // Limit on the Black List size to cap on program usage for this
+ // TODO: Select a proper max length
+ private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
private final ApfCapabilities mApfCapabilities;
private final IpManager.Callback mIpManagerCallback;
@@ -247,6 +251,8 @@ public class ApfFilter {
@GuardedBy("this")
private boolean mMulticastFilter;
private final boolean mDrop802_3Frames;
+ private final int[] mEthTypeBlackList;
+
// Our IPv4 address, if we have just one, otherwise null.
@GuardedBy("this")
private byte[] mIPv4Address;
@@ -257,12 +263,16 @@ public class ApfFilter {
@VisibleForTesting
ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
IpManager.Callback ipManagerCallback, boolean multicastFilter,
- boolean ieee802_3Filter, IpConnectivityLog log) {
+ boolean ieee802_3Filter, int[] ethTypeBlackList, IpConnectivityLog log) {
mApfCapabilities = apfCapabilities;
mIpManagerCallback = ipManagerCallback;
mNetworkInterface = networkInterface;
mMulticastFilter = multicastFilter;
mDrop802_3Frames = ieee802_3Filter;
+
+ // Now fill the black list from the passed array
+ mEthTypeBlackList = filterEthTypeBlackList(ethTypeBlackList);
+
mMetricsLog = log;
// TODO: ApfFilter should not generate programs until IpManager sends provisioning success.
@@ -278,6 +288,35 @@ public class ApfFilter {
return mUniqueCounter++;
}
+ @GuardedBy("this")
+ private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
+ ArrayList<Integer> bl = new ArrayList<Integer>();
+
+ for (int p : ethTypeBlackList) {
+ // Check if the protocol is a valid ether type
+ if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
+ continue;
+ }
+
+ // Check if the protocol is not repeated in the passed array
+ if (bl.contains(p)) {
+ continue;
+ }
+
+ // Check if list reach its max size
+ if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
+ Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
+ ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
+ break;
+ }
+
+ // Now add the protocol to the list
+ bl.add(p);
+ }
+
+ return bl.stream().mapToInt(Integer::intValue).toArray();
+ }
+
/**
* Attempt to start listening for RAs and, if RAs are received, generating and installing
* filters to ignore useless RAs.
@@ -891,6 +930,7 @@ public class ApfFilter {
* Begin generating an APF program to:
* <ul>
* <li>Drop/Pass 802.3 frames (based on policy)
+ * <li>Drop packets with EtherType within the Black List
* <li>Drop ARP requests not for us, if mIPv4Address is set,
* <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
* <li>Drop IPv4 multicast packets, if mMulticastFilter,
@@ -914,6 +954,8 @@ public class ApfFilter {
//
// if it's a 802.3 Frame (ethtype < 0x0600):
// drop or pass based on configurations
+ // if it has a ether-type that belongs to the black list
+ // drop
// if it's ARP:
// insert ARP filter to drop or pass these appropriately
// if it's IPv4:
@@ -931,6 +973,11 @@ public class ApfFilter {
gen.addJumpIfR0LessThan(ETH_TYPE_MIN, gen.DROP_LABEL);
}
+ // Handle ether-type black list
+ for (int p : mEthTypeBlackList) {
+ gen.addJumpIfR0Equals(p, gen.DROP_LABEL);
+ }
+
// Add ARP filters:
String skipArpFiltersLabel = "skipArpFilters";
gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
@@ -1115,7 +1162,7 @@ public class ApfFilter {
*/
public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
- boolean multicastFilter, boolean ieee802_3Filter) {
+ boolean multicastFilter, boolean ieee802_3Filter, int[] ethTypeBlackList) {
if (apfCapabilities == null || networkInterface == null) return null;
if (apfCapabilities.apfVersionSupported == 0) return null;
if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -1132,7 +1179,7 @@ public class ApfFilter {
return null;
}
return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback,
- multicastFilter, ieee802_3Filter, new IpConnectivityLog());
+ multicastFilter, ieee802_3Filter, ethTypeBlackList, new IpConnectivityLog());
}
public synchronized void shutdown() {
diff --git a/services/net/java/android/net/ip/InterfaceController.java b/services/net/java/android/net/ip/InterfaceController.java
new file mode 100644
index 000000000000..02e4f875230a
--- /dev/null
+++ b/services/net/java/android/net/ip/InterfaceController.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.net.ip;
+
+import android.net.INetd;
+import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
+import android.net.util.NetdService;
+import android.net.util.SharedLog;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.system.OsConstants;
+
+import java.net.InetAddress;
+
+
+/**
+ * Encapsulates the multiple IP configuration operations performed on an interface.
+ *
+ * TODO: refactor/eliminate the redundant ways to set and clear addresses.
+ *
+ * @hide
+ */
+public class InterfaceController {
+ private final static boolean DBG = false;
+
+ private final String mIfName;
+ private final INetworkManagementService mNMS;
+ private final INetd mNetd;
+ private final SharedLog mLog;
+
+ public InterfaceController(String ifname, INetworkManagementService nms, INetd netd,
+ SharedLog log) {
+ mIfName = ifname;
+ mNMS = nms;
+ mNetd = netd;
+ mLog = log;
+ }
+
+ public boolean setIPv4Address(LinkAddress address) {
+ final InterfaceConfiguration ifcg = new InterfaceConfiguration();
+ ifcg.setLinkAddress(address);
+ try {
+ mNMS.setInterfaceConfig(mIfName, ifcg);
+ if (DBG) mLog.log("IPv4 configuration succeeded");
+ } catch (IllegalStateException | RemoteException e) {
+ logError("IPv4 configuration failed: %s", e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean clearIPv4Address() {
+ try {
+ final InterfaceConfiguration ifcg = new InterfaceConfiguration();
+ ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
+ mNMS.setInterfaceConfig(mIfName, ifcg);
+ } catch (IllegalStateException | RemoteException e) {
+ logError("Failed to clear IPv4 address on interface %s: %s", mIfName, e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean enableIPv6() {
+ try {
+ mNMS.enableIpv6(mIfName);
+ } catch (IllegalStateException | RemoteException e) {
+ logError("enabling IPv6 failed: %s", e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean disableIPv6() {
+ try {
+ mNMS.disableIpv6(mIfName);
+ } catch (IllegalStateException | RemoteException e) {
+ logError("disabling IPv6 failed: %s", e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean setIPv6PrivacyExtensions(boolean enabled) {
+ try {
+ mNMS.setInterfaceIpv6PrivacyExtensions(mIfName, enabled);
+ } catch (IllegalStateException | RemoteException e) {
+ logError("error setting IPv6 privacy extensions: %s", e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean setIPv6AddrGenModeIfSupported(int mode) {
+ try {
+ mNMS.setIPv6AddrGenMode(mIfName, mode);
+ } catch (RemoteException e) {
+ logError("Unable to set IPv6 addrgen mode: %s", e);
+ return false;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode != OsConstants.EOPNOTSUPP) {
+ logError("Unable to set IPv6 addrgen mode: %s", e);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean addAddress(LinkAddress addr) {
+ return addAddress(addr.getAddress(), addr.getPrefixLength());
+ }
+
+ public boolean addAddress(InetAddress ip, int prefixLen) {
+ try {
+ mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen);
+ } catch (ServiceSpecificException | RemoteException e) {
+ logError("failed to add %s/%d: %s", ip, prefixLen, e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean removeAddress(InetAddress ip, int prefixLen) {
+ try {
+ mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen);
+ } catch (ServiceSpecificException | RemoteException e) {
+ logError("failed to remove %s/%d: %s", ip, prefixLen, e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean clearAllAddresses() {
+ try {
+ mNMS.clearInterfaceAddresses(mIfName);
+ } catch (Exception e) {
+ logError("Failed to clear addresses: %s", e);
+ return false;
+ }
+ return true;
+ }
+
+ private void logError(String fmt, Object... args) {
+ mLog.e(String.format(fmt, args));
+ }
+}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index facdb8510759..b1eb0854e334 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -22,7 +22,6 @@ import com.android.internal.util.WakeupMessage;
import android.content.Context;
import android.net.DhcpResults;
import android.net.INetd;
-import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties.ProvisioningChange;
@@ -43,9 +42,7 @@ import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
import android.os.SystemClock;
-import android.system.OsConstants;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
@@ -94,7 +91,6 @@ import java.util.stream.Collectors;
*/
public class IpManager extends StateMachine {
private static final boolean DBG = false;
- private static final boolean VDBG = false;
// For message logging.
private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
@@ -526,17 +522,18 @@ public class IpManager extends StateMachine {
public static final String DUMP_ARG = "ipmanager";
public static final String DUMP_ARG_CONFIRM = "confirm";
- private static final int CMD_STOP = 1;
- private static final int CMD_START = 2;
- private static final int CMD_CONFIRM = 3;
- private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 4;
+ private static final int CMD_TERMINATE_AFTER_STOP = 1;
+ private static final int CMD_STOP = 2;
+ private static final int CMD_START = 3;
+ private static final int CMD_CONFIRM = 4;
+ private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 5;
// Sent by NetlinkTracker to communicate netlink events.
- private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
- private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
- private static final int CMD_UPDATE_HTTP_PROXY = 7;
- private static final int CMD_SET_MULTICAST_FILTER = 8;
- private static final int EVENT_PROVISIONING_TIMEOUT = 9;
- private static final int EVENT_DHCPACTION_TIMEOUT = 10;
+ private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
+ private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 7;
+ private static final int CMD_UPDATE_HTTP_PROXY = 8;
+ private static final int CMD_SET_MULTICAST_FILTER = 9;
+ private static final int EVENT_PROVISIONING_TIMEOUT = 10;
+ private static final int EVENT_DHCPACTION_TIMEOUT = 11;
private static final int MAX_LOG_RECORDS = 500;
private static final int MAX_PACKET_RECORDS = 100;
@@ -568,7 +565,7 @@ public class IpManager extends StateMachine {
private final LocalLog mConnectivityPacketLog;
private final MessageHandlingLogger mMsgStateLogger;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
- private final INetd mNetd;
+ private final InterfaceController mInterfaceCtrl;
private NetworkInterface mNetworkInterface;
@@ -612,12 +609,13 @@ public class IpManager extends StateMachine {
mClatInterfaceName = CLAT_PREFIX + ifName;
mCallback = new LoggingCallbackWrapper(callback);
mNwService = nwService;
- mNetd = netd;
mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS);
mMsgStateLogger = new MessageHandlingLogger();
+ mInterfaceCtrl = new InterfaceController(mInterfaceName, mNwService, netd, mLog);
+
mNetlinkTracker = new NetlinkTracker(
mInterfaceName,
new NetlinkTracker.Callback() {
@@ -704,6 +702,16 @@ public class IpManager extends StateMachine {
mMultinetworkPolicyTracker.start();
}
+ private void stopStateMachineUpdaters() {
+ try {
+ mNwService.unregisterObserver(mNetlinkTracker);
+ } catch (RemoteException e) {
+ logError("Couldn't unregister NetlinkTracker: %s", e);
+ }
+
+ mMultinetworkPolicyTracker.shutdown();
+ }
+
@Override
protected void onQuitting() {
mCallback.onQuit();
@@ -712,8 +720,7 @@ public class IpManager extends StateMachine {
// Shut down this IpManager instance altogether.
public void shutdown() {
stop();
- mMultinetworkPolicyTracker.shutdown();
- quit();
+ sendMessage(CMD_TERMINATE_AFTER_STOP);
}
public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
@@ -858,7 +865,7 @@ public class IpManager extends StateMachine {
final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
mLog.log(richerLogLine);
- if (VDBG) {
+ if (DBG) {
Log.d(mTag, richerLogLine);
}
@@ -1013,19 +1020,19 @@ public class IpManager extends StateMachine {
private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
switch (delta) {
case GAINED_PROVISIONING:
- if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+ if (DBG) { Log.d(mTag, "onProvisioningSuccess()"); }
recordMetric(IpManagerEvent.PROVISIONING_OK);
mCallback.onProvisioningSuccess(newLp);
break;
case LOST_PROVISIONING:
- if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ if (DBG) { Log.d(mTag, "onProvisioningFailure()"); }
recordMetric(IpManagerEvent.PROVISIONING_FAIL);
mCallback.onProvisioningFailure(newLp);
break;
default:
- if (VDBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
+ if (DBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
mCallback.onLinkPropertiesChange(newLp);
break;
}
@@ -1113,7 +1120,7 @@ public class IpManager extends StateMachine {
addAllReachableDnsServers(newLp, config.dnsServers);
}
final LinkProperties oldLp = mLinkProperties;
- if (VDBG) {
+ if (DBG) {
Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
netlinkLinkProperties, newLp, oldLp));
}
@@ -1148,35 +1155,12 @@ public class IpManager extends StateMachine {
return (delta != ProvisioningChange.LOST_PROVISIONING);
}
- private boolean setIPv4Address(LinkAddress address) {
- final InterfaceConfiguration ifcg = new InterfaceConfiguration();
- ifcg.setLinkAddress(address);
- try {
- mNwService.setInterfaceConfig(mInterfaceName, ifcg);
- if (VDBG) Log.d(mTag, "IPv4 configuration succeeded");
- } catch (IllegalStateException | RemoteException e) {
- logError("IPv4 configuration failed: %s", e);
- return false;
- }
- return true;
- }
-
- private void clearIPv4Address() {
- try {
- final InterfaceConfiguration ifcg = new InterfaceConfiguration();
- ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
- mNwService.setInterfaceConfig(mInterfaceName, ifcg);
- } catch (IllegalStateException | RemoteException e) {
- logError("Failed to clear IPv4 address on interface %s: %s", mInterfaceName, e);
- }
- }
-
private void handleIPv4Success(DhcpResults dhcpResults) {
mDhcpResults = new DhcpResults(dhcpResults);
final LinkProperties newLp = assembleLinkProperties();
final ProvisioningChange delta = setLinkProperties(newLp);
- if (VDBG) {
+ if (DBG) {
Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
}
mCallback.onNewDhcpResults(dhcpResults);
@@ -1190,9 +1174,9 @@ public class IpManager extends StateMachine {
// that could trigger a call to this function. If we missed handling
// that message in StartedState for some reason we would still clear
// any addresses upon entry to StoppedState.
- clearIPv4Address();
+ mInterfaceCtrl.clearIPv4Address();
mDhcpResults = null;
- if (VDBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
+ if (DBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
mCallback.onNewDhcpResults(null);
handleProvisioningFailure();
@@ -1229,7 +1213,7 @@ public class IpManager extends StateMachine {
// If we have a StaticIpConfiguration attempt to apply it and
// handle the result accordingly.
if (mConfiguration.mStaticIpConfig != null) {
- if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
+ if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else {
return false;
@@ -1244,46 +1228,16 @@ public class IpManager extends StateMachine {
return true;
}
- private void setIPv6AddrGenModeIfSupported() throws RemoteException {
- try {
- mNwService.setIPv6AddrGenMode(mInterfaceName, mConfiguration.mIPv6AddrGenMode);
- } catch (ServiceSpecificException e) {
- if (e.errorCode != OsConstants.EOPNOTSUPP) {
- logError("Unable to set IPv6 addrgen mode: %s", e);
- }
- }
- }
-
private boolean startIPv6() {
- // Set privacy extensions.
- try {
- mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
-
- setIPv6AddrGenModeIfSupported();
- mNwService.enableIpv6(mInterfaceName);
- } catch (IllegalStateException | RemoteException | ServiceSpecificException e) {
- logError("Unable to change interface settings: %s", e);
- return false;
- }
-
- return true;
+ return mInterfaceCtrl.setIPv6PrivacyExtensions(true) &&
+ mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode) &&
+ mInterfaceCtrl.enableIPv6();
}
private boolean applyInitialConfig(InitialConfiguration config) {
- if (mNetd == null) {
- logError("tried to add %s to %s but INetd was null", config, mInterfaceName);
- return false;
- }
-
// TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIPv6)) {
- try {
- mNetd.interfaceAddAddress(
- mInterfaceName, addr.getAddress().getHostAddress(), addr.getPrefixLength());
- } catch (ServiceSpecificException | RemoteException e) {
- logError("failed to add %s to %s: %s", addr, mInterfaceName, e);
- return false;
- }
+ if (!mInterfaceCtrl.addAddress(addr)) return false;
}
return true;
@@ -1320,17 +1274,8 @@ public class IpManager extends StateMachine {
// - we don't get IPv4 routes from netlink
// so we neither react to nor need to wait for changes in either.
- try {
- mNwService.disableIpv6(mInterfaceName);
- } catch (Exception e) {
- logError("Failed to disable IPv6: %s", e);
- }
-
- try {
- mNwService.clearInterfaceAddresses(mInterfaceName);
- } catch (Exception e) {
- logError("Failed to clear addresses: %s", e);
- }
+ mInterfaceCtrl.disableIPv6();
+ mInterfaceCtrl.clearAllAddresses();
}
class StoppedState extends State {
@@ -1348,6 +1293,11 @@ public class IpManager extends StateMachine {
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
+ case CMD_TERMINATE_AFTER_STOP:
+ stopStateMachineUpdaters();
+ quit();
+ break;
+
case CMD_STOP:
break;
@@ -1404,7 +1354,7 @@ public class IpManager extends StateMachine {
break;
case DhcpClient.CMD_CLEAR_LINKADDRESS:
- clearIPv4Address();
+ mInterfaceCtrl.clearIPv4Address();
break;
case DhcpClient.CMD_ON_QUIT:
@@ -1494,8 +1444,11 @@ public class IpManager extends StateMachine {
boolean filter802_3Frames =
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
+ int[] ethTypeBlackList = mContext.getResources().getIntArray(
+ R.array.config_apfEthTypeBlackList);
+
mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
- mCallback, mMulticastFiltering, filter802_3Frames);
+ mCallback, mMulticastFiltering, filter802_3Frames, ethTypeBlackList);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
if (mApfFilter == null) {
@@ -1657,12 +1610,12 @@ public class IpManager extends StateMachine {
break;
case DhcpClient.CMD_CLEAR_LINKADDRESS:
- clearIPv4Address();
+ mInterfaceCtrl.clearIPv4Address();
break;
case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
final LinkAddress ipAddress = (LinkAddress) msg.obj;
- if (setIPv4Address(ipAddress)) {
+ if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
} else {
logError("Failed to set IPv4 address.");
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fe8774fa1f62..2b528101d5d3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -199,7 +199,7 @@ public class CarrierConfigManager {
/** Display carrier settings menu if true */
public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
- /** Does not display additional call seting for IMS phone based on GSM Phone */
+ /** Does not display additional call setting for IMS phone based on GSM Phone */
public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
/** Show APN Settings for some CDMA carriers */
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index e7b22bdfadcc..cf4c47bf541f 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -524,6 +524,7 @@ public class ImsConfig {
* Defines IMS feature value.
*/
public static class FeatureValueConstants {
+ public static final int ERROR = -1;
public static final int OFF = 0;
public static final int ON = 1;
}
diff --git a/telephony/java/com/android/internal/telephony/ExponentialBackoff.java b/telephony/java/com/android/internal/telephony/ExponentialBackoff.java
new file mode 100644
index 000000000000..80958c077d6a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ExponentialBackoff.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.internal.telephony;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.Looper;
+
+/** The implementation of exponential backoff with jitter applied. */
+public class ExponentialBackoff {
+ private int mRetryCounter;
+ private long mStartDelayMs;
+ private long mMaximumDelayMs;
+ private long mCurrentDelayMs;
+ private int mMultiplier;
+ private Runnable mRunnable;
+ private Handler mHandler;
+
+ public ExponentialBackoff(
+ long initialDelayMs,
+ long maximumDelayMs,
+ int multiplier,
+ @NonNull Looper looper,
+ @NonNull Runnable runnable) {
+ this(initialDelayMs, maximumDelayMs, multiplier, new Handler(looper), runnable);
+ }
+
+ public ExponentialBackoff(
+ long initialDelayMs,
+ long maximumDelayMs,
+ int multiplier,
+ @NonNull Handler handler,
+ @NonNull Runnable runnable) {
+ mRetryCounter = 0;
+ mStartDelayMs = initialDelayMs;
+ mMaximumDelayMs = maximumDelayMs;
+ mMultiplier = multiplier;
+ mHandler = handler;
+ mRunnable = runnable;
+ }
+
+ /** Starts the backoff, the runnable will be executed after {@link #mStartDelayMs}. */
+ public void start() {
+ mRetryCounter = 0;
+ mCurrentDelayMs = mStartDelayMs;
+ mHandler.removeCallbacks(mRunnable);
+ mHandler.postDelayed(mRunnable, mCurrentDelayMs);
+ }
+
+ /** Stops the backoff, all pending messages will be removed from the message queue. */
+ public void stop() {
+ mRetryCounter = 0;
+ mHandler.removeCallbacks(mRunnable);
+ }
+
+ /** Should call when the retry action has failed and we want to retry after a longer delay. */
+ public void notifyFailed() {
+ mRetryCounter++;
+ long temp = Math.min(
+ mMaximumDelayMs, (long) (mStartDelayMs * Math.pow(mMultiplier, mRetryCounter)));
+ mCurrentDelayMs = (long) (((1 + Math.random()) / 2) * temp);
+ mHandler.removeCallbacks(mRunnable);
+ mHandler.postDelayed(mRunnable, mCurrentDelayMs);
+ }
+
+ /** Returns the delay for the most recently posted message. */
+ public long getCurrentDelay() {
+ return mCurrentDelayMs;
+ }
+}
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 3af0adc36bde..677585cc0c0f 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -42,6 +42,7 @@ LOCAL_JNI_SHARED_LIBRARIES := libframeworksnettestsjni \
libui \
libunwind \
libutils \
+ libvndksupport \
libcrypto \
libhidl-gen-utils \
libhidlbase \
@@ -52,6 +53,7 @@ LOCAL_JNI_SHARED_LIBRARIES := libframeworksnettestsjni \
libtinyxml2 \
libvintf \
libhwbinder \
+ libunwindstack \
android.hidl.token@1.0
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index bfbb8cc541d7..5008a4188905 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -614,9 +614,10 @@ public class ApfTest extends AndroidTestCase {
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
- boolean ieee802_3Filter, IpConnectivityLog log) throws Exception {
+ boolean ieee802_3Filter, int[] ethTypeBlackList,
+ IpConnectivityLog log) throws Exception {
super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
- ipManagerCallback, multicastFilter, ieee802_3Filter, log);
+ ipManagerCallback, multicastFilter, ieee802_3Filter, ethTypeBlackList, log);
}
// Pretend an RA packet has been received and show it to ApfFilter.
@@ -744,9 +745,10 @@ public class ApfTest extends AndroidTestCase {
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
+ final int[] ethTypeBlackList = {};
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- ALLOW_802_3_FRAMES, mLog);
+ ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -796,9 +798,10 @@ public class ApfTest extends AndroidTestCase {
@SmallTest
public void testApfFilterIPv6() throws Exception {
+ final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, mLog);
+ ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty IPv6 packet is passed
@@ -833,6 +836,7 @@ public class ApfTest extends AndroidTestCase {
final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
+ final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
@@ -840,7 +844,7 @@ public class ApfTest extends AndroidTestCase {
lp.addLinkAddress(link);
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, mLog);
+ DROP_802_3_FRAMES, ethTypeBlackList, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -903,7 +907,7 @@ public class ApfTest extends AndroidTestCase {
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- DROP_802_3_FRAMES, mLog);
+ DROP_802_3_FRAMES, ethTypeBlackList, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
@@ -924,9 +928,10 @@ public class ApfTest extends AndroidTestCase {
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
+ final int[] ethTypeBlackList = {};
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, mLog);
+ ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -948,7 +953,7 @@ public class ApfTest extends AndroidTestCase {
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, mLog);
+ DROP_802_3_FRAMES, ethTypeBlackList, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
@@ -968,6 +973,70 @@ public class ApfTest extends AndroidTestCase {
apfFilter.shutdown();
}
+ @SmallTest
+ public void testApfFilterEthTypeBL() throws Exception {
+ MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+ LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(link);
+ final int[] emptyBlackList = {};
+ final int[] ipv4BlackList = {ETH_P_IP};
+ final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
+
+ ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
+ ALLOW_802_3_FRAMES, emptyBlackList, mLog);
+ apfFilter.setLinkProperties(lp);
+
+ byte[] program = ipManagerCallback.getApfProgram();
+
+ // Verify empty packet of 100 zero bytes is passed
+ // Note that eth-type = 0 makes it an IEEE802.3 frame
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ assertPass(program, packet.array());
+
+ // Verify empty packet with IPv4 is passed
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ assertPass(program, packet.array());
+
+ // Verify empty IPv6 packet is passed
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ assertPass(program, packet.array());
+
+ // Now add IPv4 to the black list
+ ipManagerCallback.resetApfProgramWait();
+ apfFilter.shutdown();
+ apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
+ ALLOW_802_3_FRAMES, ipv4BlackList, mLog);
+ apfFilter.setLinkProperties(lp);
+ program = ipManagerCallback.getApfProgram();
+
+ // Verify that IPv4 frame will be dropped
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ assertDrop(program, packet.array());
+
+ // Verify that IPv6 frame will pass
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ assertPass(program, packet.array());
+
+ // Now let us have both IPv4 and IPv6 in the black list
+ ipManagerCallback.resetApfProgramWait();
+ apfFilter.shutdown();
+ apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
+ ALLOW_802_3_FRAMES, ipv4Ipv6BlackList, mLog);
+ apfFilter.setLinkProperties(lp);
+ program = ipManagerCallback.getApfProgram();
+
+ // Verify that IPv4 frame will be dropped
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ assertDrop(program, packet.array());
+
+ // Verify that IPv6 frame will be dropped
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ assertDrop(program, packet.array());
+
+ apfFilter.shutdown();
+ }
+
private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
cb.resetApfProgramWait();
filter.setLinkProperties(lp);
@@ -991,9 +1060,10 @@ public class ApfTest extends AndroidTestCase {
@SmallTest
public void testApfFilterArp() throws Exception {
+ final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, mLog);
+ DROP_802_3_FRAMES, ethTypeBlackList, mLog);
// Verify initially ARP request filter is off, and GARP filter is on.
verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1114,8 +1184,9 @@ public class ApfTest extends AndroidTestCase {
@SmallTest
public void testApfFilterRa() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ final int[] ethTypeBlackList = {};
TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- DROP_802_3_FRAMES, mLog);
+ DROP_802_3_FRAMES, ethTypeBlackList, mLog);
byte[] program = ipManagerCallback.getApfProgram();
final int ROUTER_LIFETIME = 1000;
@@ -1256,9 +1327,10 @@ public class ApfTest extends AndroidTestCase {
public void testRaParsing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
+ final int[] ethTypeBlackList = {};
MockIpManagerCallback cb = new MockIpManagerCallback();
TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
- DROP_802_3_FRAMES, mLog);
+ DROP_802_3_FRAMES, ethTypeBlackList, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
@@ -1275,9 +1347,10 @@ public class ApfTest extends AndroidTestCase {
public void testRaProcessing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
+ final int[] ethTypeBlackList = {};
MockIpManagerCallback cb = new MockIpManagerCallback();
TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
- DROP_802_3_FRAMES, mLog);
+ DROP_802_3_FRAMES, ethTypeBlackList, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
index f77608f95b3e..9115378969ca 100644
--- a/tests/net/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/net/java/android/net/nsd/NsdManagerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static com.android.internal.util.TestUtils.waitForIdleHandler;
import android.os.HandlerThread;
import android.os.Handler;
@@ -38,6 +39,7 @@ import android.support.test.runner.AndroidJUnit4;
import android.os.Message;
import android.os.Messenger;
import com.android.internal.util.AsyncChannel;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,6 +58,8 @@ public class NsdManagerTest {
@Mock INsdManager mService;
MockServiceHandler mServiceHandler;
+ NsdManager mManager;
+
long mTimeoutMs = 100; // non-final so that tests can adjust the value.
@Before
@@ -64,11 +68,23 @@ public class NsdManagerTest {
mServiceHandler = spy(MockServiceHandler.create(mContext));
when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
+
+ mManager = makeManager();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ waitForIdleHandler(mServiceHandler, mTimeoutMs);
+ mServiceHandler.chan.disconnect();
+ mServiceHandler.stop();
+ if (mManager != null) {
+ mManager.disconnect();
+ }
}
@Test
public void testResolveService() {
- NsdManager manager = makeManager();
+ NsdManager manager = mManager;
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
@@ -88,7 +104,7 @@ public class NsdManagerTest {
@Test
public void testParallelResolveService() {
- NsdManager manager = makeManager();
+ NsdManager manager = mManager;
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
@@ -111,7 +127,7 @@ public class NsdManagerTest {
@Test
public void testRegisterService() {
- NsdManager manager = makeManager();
+ NsdManager manager = mManager;
NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
@@ -170,7 +186,7 @@ public class NsdManagerTest {
@Test
public void testDiscoverService() {
- NsdManager manager = makeManager();
+ NsdManager manager = mManager;
NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
@@ -248,7 +264,7 @@ public class NsdManagerTest {
@Test
public void testInvalidCalls() {
- NsdManager manager = new NsdManager(mContext, mService);
+ NsdManager manager = mManager;
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
@@ -351,6 +367,10 @@ public class NsdManagerTest {
}
}
+ public void stop() {
+ getLooper().quitSafely();
+ }
+
public static MockServiceHandler create(Context context) {
HandlerThread t = new HandlerThread("mock-service-handler");
t.start();
diff --git a/tests/net/java/com/android/server/NsdServiceTest.java b/tests/net/java/com/android/server/NsdServiceTest.java
index 68cb251cf87e..2e49c98ca9b6 100644
--- a/tests/net/java/com/android/server/NsdServiceTest.java
+++ b/tests/net/java/com/android/server/NsdServiceTest.java
@@ -95,6 +95,9 @@ public class NsdServiceTest {
client2.disconnect();
verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
+
+ client1.disconnect();
+ client2.disconnect();
}
@Test
@@ -131,6 +134,8 @@ public class NsdServiceTest {
// checks that request are cleaned
verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
+
+ client.disconnect();
}
NsdService makeService() {
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
new file mode 100644
index 000000000000..e3f46a40e2b1
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.server.connectivity;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.net.ConnectivityManager;
+import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkInfo;
+import android.os.Handler;
+import android.os.INetworkManagementService;
+import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.ConnectivityService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class Nat464XlatTest {
+
+ static final String BASE_IFACE = "test0";
+ static final String STACKED_IFACE = "v4-test0";
+ static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
+
+ @Mock ConnectivityService mConnectivity;
+ @Mock INetworkManagementService mNms;
+ @Mock InterfaceConfiguration mConfig;
+ @Mock NetworkAgentInfo mNai;
+
+ TestLooper mLooper;
+ Handler mHandler;
+
+ Nat464Xlat makeNat464Xlat() {
+ return new Nat464Xlat(mNms, mNai);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mLooper = new TestLooper();
+ mHandler = new Handler(mLooper.getLooper());
+
+ MockitoAnnotations.initMocks(this);
+
+ mNai.linkProperties = new LinkProperties();
+ mNai.linkProperties.setInterfaceName(BASE_IFACE);
+ mNai.networkInfo = new NetworkInfo(null);
+ mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
+ when(mNai.connService()).thenReturn(mConnectivity);
+ when(mNai.handler()).thenReturn(mHandler);
+
+ when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
+ when(mConfig.getLinkAddress()).thenReturn(ADDR);
+ }
+
+ @Test
+ public void testNormalStartAndStop() throws Exception {
+ Nat464Xlat nat = makeNat464Xlat();
+ ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
+
+ // ConnectivityService starts clat.
+ nat.start();
+
+ verify(mNms).registerObserver(eq(nat));
+ verify(mNms).startClatd(eq(BASE_IFACE));
+
+ // Stacked interface up notification arrives.
+ nat.interfaceLinkStateChanged(STACKED_IFACE, true);
+ mLooper.dispatchNext();
+
+ verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
+ verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
+ verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
+ assertFalse(c.getValue().getStackedLinks().isEmpty());
+ assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
+ assertRunning(nat);
+
+ // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
+ nat.stop();
+
+ verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
+
+ // Stacked interface removed notification arrives.
+ nat.interfaceRemoved(STACKED_IFACE);
+ mLooper.dispatchNext();
+
+ verify(mNms).unregisterObserver(eq(nat));
+ verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
+ assertTrue(c.getValue().getStackedLinks().isEmpty());
+ assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
+ assertIdle(nat);
+
+ verifyNoMoreInteractions(mNms, mConnectivity);
+ }
+
+ @Test
+ public void testClatdCrashWhileRunning() throws Exception {
+ Nat464Xlat nat = makeNat464Xlat();
+ ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
+
+ // ConnectivityService starts clat.
+ nat.start();
+
+ verify(mNms).registerObserver(eq(nat));
+ verify(mNms).startClatd(eq(BASE_IFACE));
+
+ // Stacked interface up notification arrives.
+ nat.interfaceLinkStateChanged(STACKED_IFACE, true);
+ mLooper.dispatchNext();
+
+ verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
+ verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(false));
+ verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
+ assertFalse(c.getValue().getStackedLinks().isEmpty());
+ assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
+ assertRunning(nat);
+
+ // Stacked interface removed notification arrives (clatd crashed, ...).
+ nat.interfaceRemoved(STACKED_IFACE);
+ mLooper.dispatchNext();
+
+ verify(mNms).unregisterObserver(eq(nat));
+ verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNms).setInterfaceIpv6NdOffload(eq(BASE_IFACE), eq(true));
+ verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
+ assertTrue(c.getValue().getStackedLinks().isEmpty());
+ assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
+ assertIdle(nat);
+
+ // ConnectivityService stops clat: no-op.
+ nat.stop();
+
+ verifyNoMoreInteractions(mNms, mConnectivity);
+ }
+
+ @Test
+ public void testStopBeforeClatdStarts() throws Exception {
+ Nat464Xlat nat = makeNat464Xlat();
+
+ // ConnectivityService starts clat.
+ nat.start();
+
+ verify(mNms).registerObserver(eq(nat));
+ verify(mNms).startClatd(eq(BASE_IFACE));
+
+ // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
+ nat.stop();
+
+ verify(mNms).unregisterObserver(eq(nat));
+ verify(mNms).stopClatd(eq(BASE_IFACE));
+ assertIdle(nat);
+
+ // In-flight interface up notification arrives: no-op
+ nat.interfaceLinkStateChanged(STACKED_IFACE, true);
+ mLooper.dispatchNext();
+
+
+ // Interface removed notification arrives after stopClatd() takes effect: no-op.
+ nat.interfaceRemoved(STACKED_IFACE);
+ mLooper.dispatchNext();
+
+ assertIdle(nat);
+
+ verifyNoMoreInteractions(mNms, mConnectivity);
+ }
+
+ @Test
+ public void testStopAndClatdNeverStarts() throws Exception {
+ Nat464Xlat nat = makeNat464Xlat();
+
+ // ConnectivityService starts clat.
+ nat.start();
+
+ verify(mNms).registerObserver(eq(nat));
+ verify(mNms).startClatd(eq(BASE_IFACE));
+
+ // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
+ nat.stop();
+
+ verify(mNms).unregisterObserver(eq(nat));
+ verify(mNms).stopClatd(eq(BASE_IFACE));
+ assertIdle(nat);
+
+ verifyNoMoreInteractions(mNms, mConnectivity);
+ }
+
+ static void assertIdle(Nat464Xlat nat) {
+ assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
+ }
+
+ static void assertRunning(Nat464Xlat nat) {
+ assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index d7739518ef2d..2199a134d657 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -32,12 +32,13 @@ import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -68,6 +69,7 @@ import java.util.Set;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -144,8 +146,8 @@ public class OffloadControllerTest {
return offload;
}
- // TODO: Restore when FakeSettingsProvider.clearSettingsProvider() is available.
- // @Test
+ @Test
+ @Ignore("Restore when FakeSettingsProvider.clearSettingsProvider() is available.")
public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
@@ -165,8 +167,8 @@ public class OffloadControllerTest {
inOrder.verifyNoMoreInteractions();
}
- // TODO: Restore when FakeSettingsProvider.clearSettingsProvider() is available.
- // @Test
+ @Test
+ @Ignore("Restore when FakeSettingsProvider.clearSettingsProvider() is available.")
public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
@@ -440,6 +442,9 @@ public class OffloadControllerTest {
ethernetStats.txBytes = 100000;
when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
offload.setUpstreamLinkProperties(null);
+ // Expect that we first clear the HAL's upstream parameters.
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(""), eq("0.0.0.0"), eq("0.0.0.0"), eq(null));
// Expect that we fetch stats from the previous upstream.
inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface));
@@ -449,8 +454,6 @@ public class OffloadControllerTest {
waitForIdle();
// There is no current upstream, so no stats are fetched.
inOrder.verify(mHardware, never()).getForwardedStats(any());
- inOrder.verify(mHardware, times(1)).setUpstreamParameters(
- eq(null), eq(null), eq(null), eq(null));
inOrder.verifyNoMoreInteractions();
assertEquals(2, stats.size());
@@ -625,6 +628,73 @@ public class OffloadControllerTest {
inOrder.verifyNoMoreInteractions();
}
+ @Test
+ public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ // Pretend to set a few different upstreams (only the interface name
+ // matters for this test; we're ignoring IP and route information).
+ final LinkProperties upstreamLp = new LinkProperties();
+ for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) {
+ upstreamLp.setInterfaceName(ifname);
+ offload.setUpstreamLinkProperties(upstreamLp);
+ }
+
+ // Clear invocation history, especially the getForwardedStats() calls
+ // that happen with setUpstreamParameters().
+ clearInvocations(mHardware);
+
+ OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
+ callback.onStoppedUnsupported();
+
+ // Verify forwarded stats behaviour.
+ verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
+ verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
+ verifyNoMoreInteractions(mHardware);
+ verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
+ verifyNoMoreInteractions(mNMService);
+ }
+
+ @Test
+ public void testControlCallbackOnSupportAvailableFetchesAllStatsAndPushesAllParameters()
+ throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ // Pretend to set a few different upstreams (only the interface name
+ // matters for this test; we're ignoring IP and route information).
+ final LinkProperties upstreamLp = new LinkProperties();
+ for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) {
+ upstreamLp.setInterfaceName(ifname);
+ offload.setUpstreamLinkProperties(upstreamLp);
+ }
+
+ // Clear invocation history, especially the getForwardedStats() calls
+ // that happen with setUpstreamParameters().
+ clearInvocations(mHardware);
+
+ OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
+ callback.onSupportAvailable();
+
+ // Verify forwarded stats behaviour.
+ verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
+ verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
+ verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
+ verifyNoMoreInteractions(mNMService);
+
+ // TODO: verify local prefixes and downstreams are also pushed to the HAL.
+ verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any());
+ verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong());
+ verifyNoMoreInteractions(mHardware);
+ }
+
private static void assertArrayListContains(ArrayList<String> list, String... elems) {
for (String element : elems) {
assertTrue(list.contains(element));
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 53c66a628568..f0ac467bdd18 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -293,6 +293,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
manifest_action["instrumentation"]["meta-data"] = meta_data_action;
manifest_action["original-package"];
+ manifest_action["overlay"];
manifest_action["protected-broadcast"];
manifest_action["uses-permission"];
manifest_action["uses-permission-sdk-23"];