Merge "Copy preload2.jar to build artifacts"
diff --git a/Android.mk b/Android.mk
index c0bb724..1412155 100644
--- a/Android.mk
+++ b/Android.mk
@@ -45,6 +45,7 @@
core/java/android/app/admin/SecurityLogTags.logtags \
core/java/android/content/EventLogTags.logtags \
core/java/android/speech/tts/EventLogTags.logtags \
+ core/java/android/net/EventLogTags.logtags \
core/java/android/webkit/EventLogTags.logtags \
core/java/com/android/internal/logging/EventLogTags.logtags \
@@ -502,7 +503,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(framework_res_R_stamp)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp legacy-test bouncycastle ext
+LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp bouncycastle ext
LOCAL_STATIC_JAVA_LIBRARIES := framework-protos
LOCAL_MODULE := framework
@@ -729,6 +730,7 @@
# Search through the base framework dirs for these packages.
# The result will be relative to frameworks/base.
fwbase_dirs_to_document := \
+ legacy-test/src \
test-runner/src \
$(patsubst $(LOCAL_PATH)/%,%, \
$(wildcard \
diff --git a/api/current.txt b/api/current.txt
index 2788f36..164a15b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6447,6 +6447,7 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
+ method public int getMetered();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6456,6 +6457,9 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
+ field public static final int METERED_ALL = -1; // 0xffffffff
+ field public static final int METERED_NO = 1; // 0x1
+ field public static final int METERED_YES = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_NO = 1; // 0x1
field public static final int ROAMING_YES = 2; // 0x2
@@ -62045,13 +62049,13 @@
ctor public Attributes.Name(java.lang.String);
field public static final java.util.jar.Attributes.Name CLASS_PATH;
field public static final java.util.jar.Attributes.Name CONTENT_TYPE;
- field public static final java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
+ field public static final deprecated java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
field public static final java.util.jar.Attributes.Name EXTENSION_LIST;
field public static final java.util.jar.Attributes.Name EXTENSION_NAME;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_TITLE;
- field public static final java.util.jar.Attributes.Name IMPLEMENTATION_URL;
+ field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_URL;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR;
- field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
+ field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VERSION;
field public static final java.util.jar.Attributes.Name MAIN_CLASS;
field public static final java.util.jar.Attributes.Name MANIFEST_VERSION;
@@ -62118,11 +62122,11 @@
}
public static abstract interface Pack200.Packer {
- method public abstract void addPropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract void pack(java.util.jar.JarFile, java.io.OutputStream) throws java.io.IOException;
method public abstract void pack(java.util.jar.JarInputStream, java.io.OutputStream) throws java.io.IOException;
method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
- method public abstract void removePropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
field public static final java.lang.String CLASS_ATTRIBUTE_PFX = "pack.class.attribute.";
field public static final java.lang.String CODE_ATTRIBUTE_PFX = "pack.code.attribute.";
field public static final java.lang.String DEFLATE_HINT = "pack.deflate.hint";
@@ -62145,9 +62149,9 @@
}
public static abstract interface Pack200.Unpacker {
- method public abstract void addPropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
- method public abstract void removePropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract void unpack(java.io.InputStream, java.util.jar.JarOutputStream) throws java.io.IOException;
method public abstract void unpack(java.io.File, java.util.jar.JarOutputStream) throws java.io.IOException;
field public static final java.lang.String DEFLATE_HINT = "unpack.deflate.hint";
diff --git a/api/system-current.txt b/api/system-current.txt
index 74b1af3..67baaaa 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6739,6 +6739,7 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
+ method public int getMetered();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6748,6 +6749,9 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
+ field public static final int METERED_ALL = -1; // 0xffffffff
+ field public static final int METERED_NO = 1; // 0x1
+ field public static final int METERED_YES = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_NO = 1; // 0x1
field public static final int ROAMING_YES = 2; // 0x2
@@ -65606,13 +65610,13 @@
ctor public Attributes.Name(java.lang.String);
field public static final java.util.jar.Attributes.Name CLASS_PATH;
field public static final java.util.jar.Attributes.Name CONTENT_TYPE;
- field public static final java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
+ field public static final deprecated java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
field public static final java.util.jar.Attributes.Name EXTENSION_LIST;
field public static final java.util.jar.Attributes.Name EXTENSION_NAME;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_TITLE;
- field public static final java.util.jar.Attributes.Name IMPLEMENTATION_URL;
+ field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_URL;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR;
- field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
+ field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VERSION;
field public static final java.util.jar.Attributes.Name MAIN_CLASS;
field public static final java.util.jar.Attributes.Name MANIFEST_VERSION;
@@ -65679,11 +65683,11 @@
}
public static abstract interface Pack200.Packer {
- method public abstract void addPropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract void pack(java.util.jar.JarFile, java.io.OutputStream) throws java.io.IOException;
method public abstract void pack(java.util.jar.JarInputStream, java.io.OutputStream) throws java.io.IOException;
method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
- method public abstract void removePropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
field public static final java.lang.String CLASS_ATTRIBUTE_PFX = "pack.class.attribute.";
field public static final java.lang.String CODE_ATTRIBUTE_PFX = "pack.code.attribute.";
field public static final java.lang.String DEFLATE_HINT = "pack.deflate.hint";
@@ -65706,9 +65710,9 @@
}
public static abstract interface Pack200.Unpacker {
- method public abstract void addPropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
- method public abstract void removePropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract void unpack(java.io.InputStream, java.util.jar.JarOutputStream) throws java.io.IOException;
method public abstract void unpack(java.io.File, java.util.jar.JarOutputStream) throws java.io.IOException;
field public static final java.lang.String DEFLATE_HINT = "unpack.deflate.hint";
diff --git a/api/test-current.txt b/api/test-current.txt
index 8e3d4ef..c1f289e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6456,6 +6456,7 @@
public static class NetworkStats.Bucket {
ctor public NetworkStats.Bucket();
method public long getEndTimeStamp();
+ method public int getMetered();
method public int getRoaming();
method public long getRxBytes();
method public long getRxPackets();
@@ -6465,6 +6466,9 @@
method public long getTxBytes();
method public long getTxPackets();
method public int getUid();
+ field public static final int METERED_ALL = -1; // 0xffffffff
+ field public static final int METERED_NO = 1; // 0x1
+ field public static final int METERED_YES = 2; // 0x2
field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_NO = 1; // 0x1
field public static final int ROAMING_YES = 2; // 0x2
@@ -62136,13 +62140,13 @@
ctor public Attributes.Name(java.lang.String);
field public static final java.util.jar.Attributes.Name CLASS_PATH;
field public static final java.util.jar.Attributes.Name CONTENT_TYPE;
- field public static final java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
+ field public static final deprecated java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
field public static final java.util.jar.Attributes.Name EXTENSION_LIST;
field public static final java.util.jar.Attributes.Name EXTENSION_NAME;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_TITLE;
- field public static final java.util.jar.Attributes.Name IMPLEMENTATION_URL;
+ field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_URL;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR;
- field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
+ field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VERSION;
field public static final java.util.jar.Attributes.Name MAIN_CLASS;
field public static final java.util.jar.Attributes.Name MANIFEST_VERSION;
@@ -62209,11 +62213,11 @@
}
public static abstract interface Pack200.Packer {
- method public abstract void addPropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract void pack(java.util.jar.JarFile, java.io.OutputStream) throws java.io.IOException;
method public abstract void pack(java.util.jar.JarInputStream, java.io.OutputStream) throws java.io.IOException;
method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
- method public abstract void removePropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
field public static final java.lang.String CLASS_ATTRIBUTE_PFX = "pack.class.attribute.";
field public static final java.lang.String CODE_ATTRIBUTE_PFX = "pack.code.attribute.";
field public static final java.lang.String DEFLATE_HINT = "pack.deflate.hint";
@@ -62236,9 +62240,9 @@
}
public static abstract interface Pack200.Unpacker {
- method public abstract void addPropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
- method public abstract void removePropertyChangeListener(java.beans.PropertyChangeListener);
+ method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
method public abstract void unpack(java.io.InputStream, java.util.jar.JarOutputStream) throws java.io.IOException;
method public abstract void unpack(java.io.File, java.util.jar.JarOutputStream) throws java.io.IOException;
field public static final java.lang.String DEFLATE_HINT = "unpack.deflate.hint";
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 226aa8f..3670b91 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -164,6 +164,29 @@
public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
/** @hide */
+ @IntDef({METERED_ALL, METERED_NO, METERED_YES})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Metered {}
+
+ /**
+ * Combined usage across all metered states. Covers metered and unmetered usage.
+ */
+ public static final int METERED_ALL = -1;
+
+ /**
+ * Usage that occurs on an unmetered network.
+ */
+ public static final int METERED_NO = 0x1;
+
+ /**
+ * Usage that occurs on a metered network.
+ *
+ * <p>A network is classified as metered when the user is sensitive to heavy data usage on
+ * that connection.
+ */
+ public static final int METERED_YES = 0x2;
+
+ /** @hide */
@IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES})
@Retention(RetentionPolicy.SOURCE)
public @interface Roaming {}
@@ -200,6 +223,7 @@
private int mUid;
private int mTag;
private int mState;
+ private int mMetered;
private int mRoaming;
private long mBeginTimeStamp;
private long mEndTimeStamp;
@@ -232,6 +256,15 @@
return tag;
}
+ private static @Metered int convertMetered(int metered) {
+ switch (metered) {
+ case android.net.NetworkStats.METERED_ALL : return METERED_ALL;
+ case android.net.NetworkStats.METERED_NO: return METERED_NO;
+ case android.net.NetworkStats.METERED_YES: return METERED_YES;
+ }
+ return 0;
+ }
+
private static @Roaming int convertRoaming(int roaming) {
switch (roaming) {
case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL;
@@ -279,6 +312,21 @@
}
/**
+ * Metered state. One of the following values:<p/>
+ * <ul>
+ * <li>{@link #METERED_ALL}</li>
+ * <li>{@link #METERED_NO}</li>
+ * <li>{@link #METERED_YES}</li>
+ * </ul>
+ * <p>A network is classified as metered when the user is sensitive to heavy data usage on
+ * that connection. Apps may warn before using these networks for large downloads. The
+ * metered state can be set by the user within data usage network restrictions.
+ */
+ public @Metered int getMetered() {
+ return mMetered;
+ }
+
+ /**
* Roaming state. One of the following values:<p/>
* <ul>
* <li>{@link #ROAMING_ALL}</li>
@@ -491,6 +539,7 @@
bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag);
bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
+ bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered);
bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
bucketOut.mBeginTimeStamp = mStartTimeStamp;
bucketOut.mEndTimeStamp = mEndTimeStamp;
@@ -539,6 +588,7 @@
bucketOut.mUid = Bucket.convertUid(getUid());
bucketOut.mTag = Bucket.convertTag(mTag);
bucketOut.mState = Bucket.STATE_ALL;
+ bucketOut.mMetered = Bucket.METERED_ALL;
bucketOut.mRoaming = Bucket.ROAMING_ALL;
bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 7961a72..840413a 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -51,16 +51,17 @@
* {@link #querySummaryForUser} <p />
* {@link #querySummary} <p />
* These queries aggregate network usage across the whole interval. Therefore there will be only one
- * bucket for a particular key and state and roaming combination. In case of the user-wide and
- * device-wide summaries a single bucket containing the totalised network usage is returned.
+ * bucket for a particular key, state, metered and roaming combination. In case of the user-wide
+ * and device-wide summaries a single bucket containing the totalised network usage is returned.
* <h3>
* History queries
* </h3>
* {@link #queryDetailsForUid} <p />
* {@link #queryDetails} <p />
- * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there
- * can be multiple buckets for a particular key but all Bucket's state is going to be
- * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be
+ * These queries do not aggregate over time but do aggregate over state, metered and roaming.
+ * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to
+ * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be
+ * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be
* {@link NetworkStats.Bucket#ROAMING_ALL}.
* <p />
* <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
@@ -103,10 +104,11 @@
/**
* Query network usage statistics summaries. Result is summarised data usage for the whole
- * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This
- * means the bucket's start and end timestamp are going to be the same as the 'startTime' and
- * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
- * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}
+ * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
+ * roaming. This means the bucket's start and end timestamp are going to be the same as the
+ * 'startTime' and 'endTime' parameters. State is going to be
+ * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
+ * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL},
* and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
@@ -142,8 +144,10 @@
* Query network usage statistics summaries. Result is summarised data usage for all uids
* belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
* This means the bucket's start and end timestamp are going to be the same as the 'startTime'
- * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
- * {@link NetworkStats.Bucket#UID_ALL}.
+ * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL},
+ * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
+ * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
+ * {@link NetworkStats.Bucket#ROAMING_ALL}.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -177,9 +181,10 @@
/**
* Query network usage statistics summaries. Result filtered to include only uids belonging to
* calling user. Result is aggregated over time, hence all buckets will have the same start and
- * end timestamps. Not aggregated over state or uid. This means buckets' start and end
- * timestamps are going to be the same as the 'startTime' and 'endTime' parameters.
- * State and uid are going to vary, and tag is going to be the same.
+ * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL},
+ * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
+ * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
+ * {@link NetworkStats.Bucket#ROAMING_ALL}.
*
* @param networkType As defined in {@link ConnectivityManager}, e.g.
* {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -262,10 +267,12 @@
/**
* Query network usage statistics details. Result filtered to include only uids belonging to
- * calling user. Result is aggregated over state but not aggregated over time or uid. This means
- * buckets' start and end timestamps are going to be between 'startTime' and 'endTime'
- * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
- * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be
+ * calling user. Result is aggregated over state but not aggregated over time, uid, tag,
+ * metered, nor roaming. This means buckets' start and end timestamps are going to be between
+ * 'startTime' and 'endTime' parameters. State is going to be
+ * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
+ * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be
+ * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be
* {@link NetworkStats.Bucket#ROAMING_ALL}.
* <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
* interpolate across partial buckets. Since bucket length is in the order of hours, this
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0afb546..51431ebf 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2079,6 +2079,8 @@
@SystemApi
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
+ checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
+
ResultReceiver wrappedCallback = new ResultReceiver(handler) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -2089,6 +2091,7 @@
}
}
};
+
try {
mService.startTethering(type, wrappedCallback, showProvisioningUi);
} catch (RemoteException e) {
@@ -2592,7 +2595,8 @@
/**
* Called if no network is found in the given timeout time. If no timeout is given,
- * this will not be called.
+ * this will not be called. The associated {@link NetworkRequest} will have already
+ * been removed and released, as if {@link #unregisterNetworkCallback} had been called.
* @hide
*/
public void onUnavailable() {}
@@ -2656,6 +2660,7 @@
public static final int CALLBACK_IP_CHANGED = BASE + 7;
/** @hide */
public static final int CALLBACK_RELEASED = BASE + 8;
+ // TODO: consider deleting CALLBACK_EXIT and shifting following enum codes down by 1.
/** @hide */
public static final int CALLBACK_EXIT = BASE + 9;
/** @hide obj = NetworkCapabilities, arg1 = seq number */
@@ -2665,25 +2670,38 @@
/** @hide */
public static final int CALLBACK_RESUMED = BASE + 12;
+ /** @hide */
+ public static String getCallbackName(int whichCallback) {
+ switch (whichCallback) {
+ case CALLBACK_PRECHECK: return "CALLBACK_PRECHECK";
+ case CALLBACK_AVAILABLE: return "CALLBACK_AVAILABLE";
+ case CALLBACK_LOSING: return "CALLBACK_LOSING";
+ case CALLBACK_LOST: return "CALLBACK_LOST";
+ case CALLBACK_UNAVAIL: return "CALLBACK_UNAVAIL";
+ case CALLBACK_CAP_CHANGED: return "CALLBACK_CAP_CHANGED";
+ case CALLBACK_IP_CHANGED: return "CALLBACK_IP_CHANGED";
+ case CALLBACK_RELEASED: return "CALLBACK_RELEASED";
+ case CALLBACK_EXIT: return "CALLBACK_EXIT";
+ case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
+ case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED";
+ case CALLBACK_RESUMED: return "CALLBACK_RESUMED";
+ default:
+ return Integer.toString(whichCallback);
+ }
+ }
+
private class CallbackHandler extends Handler {
- private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
- private final AtomicInteger mRefCount;
private static final String TAG = "ConnectivityManager.CallbackHandler";
- private final ConnectivityManager mCm;
private static final boolean DBG = false;
- CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallback>callbackMap,
- AtomicInteger refCount, ConnectivityManager cm) {
+ CallbackHandler(Looper looper) {
super(looper);
- mCallbackMap = callbackMap;
- mRefCount = refCount;
- mCm = cm;
}
@Override
public void handleMessage(Message message) {
- NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class);
- Network network = (Network) getObject(message, Network.class);
+ NetworkRequest request = getObject(message, NetworkRequest.class);
+ Network network = getObject(message, Network.class);
if (DBG) {
Log.d(TAG, whatToString(message.what) + " for network " + network);
}
@@ -2726,9 +2744,7 @@
case CALLBACK_CAP_CHANGED: {
NetworkCallback callback = getCallback(request, "CAP_CHANGED");
if (callback != null) {
- NetworkCapabilities cap = (NetworkCapabilities)getObject(message,
- NetworkCapabilities.class);
-
+ NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
callback.onCapabilitiesChanged(network, cap);
}
break;
@@ -2736,9 +2752,7 @@
case CALLBACK_IP_CHANGED: {
NetworkCallback callback = getCallback(request, "IP_CHANGED");
if (callback != null) {
- LinkProperties lp = (LinkProperties)getObject(message,
- LinkProperties.class);
-
+ LinkProperties lp = getObject(message, LinkProperties.class);
callback.onLinkPropertiesChanged(network, lp);
}
break;
@@ -2758,24 +2772,16 @@
break;
}
case CALLBACK_RELEASED: {
- NetworkCallback callback = null;
- synchronized(mCallbackMap) {
- callback = mCallbackMap.remove(request);
+ final NetworkCallback callback;
+ synchronized(sCallbacks) {
+ callback = sCallbacks.remove(request);
}
- if (callback != null) {
- synchronized(mRefCount) {
- if (mRefCount.decrementAndGet() == 0) {
- getLooper().quit();
- }
- }
- } else {
+ if (callback == null) {
Log.e(TAG, "callback not found for RELEASED message");
}
break;
}
case CALLBACK_EXIT: {
- Log.d(TAG, "Listener quitting");
- getLooper().quit();
break;
}
case EXPIRE_LEGACY_REQUEST: {
@@ -2785,14 +2791,14 @@
}
}
- private Object getObject(Message msg, Class c) {
- return msg.getData().getParcelable(c.getSimpleName());
+ private <T> T getObject(Message msg, Class<T> c) {
+ return (T) msg.getData().getParcelable(c.getSimpleName());
}
private NetworkCallback getCallback(NetworkRequest req, String name) {
NetworkCallback callback;
- synchronized(mCallbackMap) {
- callback = mCallbackMap.get(req);
+ synchronized(sCallbacks) {
+ callback = sCallbacks.get(req);
}
if (callback == null) {
Log.e(TAG, "callback not found for " + name + " message");
@@ -2801,63 +2807,56 @@
}
}
- private void incCallbackHandlerRefCount() {
- synchronized(sCallbackRefCount) {
- if (sCallbackRefCount.incrementAndGet() == 1) {
- // TODO: switch this to ConnectivityThread
- HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
- callbackThread.start();
- sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
- sNetworkCallback, sCallbackRefCount, this);
+ private CallbackHandler getHandler() {
+ synchronized (sCallbacks) {
+ if (sCallbackHandler == null) {
+ sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper());
}
+ return sCallbackHandler;
}
}
- private void decCallbackHandlerRefCount() {
- synchronized(sCallbackRefCount) {
- if (sCallbackRefCount.decrementAndGet() == 0) {
- sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget();
- sCallbackHandler = null;
- }
- }
- }
-
- static final HashMap<NetworkRequest, NetworkCallback> sNetworkCallback =
- new HashMap<NetworkRequest, NetworkCallback>();
- static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
- static CallbackHandler sCallbackHandler = null;
+ static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
+ static CallbackHandler sCallbackHandler;
private final static int LISTEN = 1;
private final static int REQUEST = 2;
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
- NetworkCallback networkCallback, int timeoutSec, int action,
- int legacyType) {
- if (networkCallback == null) {
+ NetworkCallback callback, int timeoutMs, int action, int legacyType) {
+ return sendRequestForNetwork(need, callback, getHandler(), timeoutMs, action, legacyType);
+ }
+
+ private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
+ NetworkCallback callback, Handler handler, int timeoutMs, int action, int legacyType) {
+ if (callback == null) {
throw new IllegalArgumentException("null NetworkCallback");
}
if (need == null && action != REQUEST) {
throw new IllegalArgumentException("null NetworkCapabilities");
}
+ // TODO: throw an exception if callback.networkRequest is not null.
+ // http://b/20701525
+ final NetworkRequest request;
try {
- incCallbackHandlerRefCount();
- synchronized(sNetworkCallback) {
+ synchronized(sCallbacks) {
+ Messenger messenger = new Messenger(handler);
+ Binder binder = new Binder();
if (action == LISTEN) {
- networkCallback.networkRequest = mService.listenForNetwork(need,
- new Messenger(sCallbackHandler), new Binder());
+ request = mService.listenForNetwork(need, messenger, binder);
} else {
- networkCallback.networkRequest = mService.requestNetwork(need,
- new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
+ request = mService.requestNetwork(
+ need, messenger, timeoutMs, binder, legacyType);
}
- if (networkCallback.networkRequest != null) {
- sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
+ if (request != null) {
+ sCallbacks.put(request, callback);
}
+ callback.networkRequest = request;
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- if (networkCallback.networkRequest == null) decCallbackHandlerRefCount();
- return networkCallback.networkRequest;
+ return request;
}
/**
diff --git a/core/java/android/net/ConnectivityThread.java b/core/java/android/net/ConnectivityThread.java
index 55c3402..0b218e7 100644
--- a/core/java/android/net/ConnectivityThread.java
+++ b/core/java/android/net/ConnectivityThread.java
@@ -27,25 +27,30 @@
* @hide
*/
public final class ConnectivityThread extends HandlerThread {
- private static ConnectivityThread sInstance;
+
+ // A class implementing the lazy holder idiom: the unique static instance
+ // of ConnectivityThread is instantiated in a thread-safe way (guaranteed by
+ // the language specs) the first time that Singleton is referenced in get()
+ // or getInstanceLooper().
+ private static class Singleton {
+ private static final ConnectivityThread INSTANCE = createInstance();
+ }
private ConnectivityThread() {
super("ConnectivityThread");
}
- private static synchronized ConnectivityThread getInstance() {
- if (sInstance == null) {
- sInstance = new ConnectivityThread();
- sInstance.start();
- }
- return sInstance;
+ private static ConnectivityThread createInstance() {
+ ConnectivityThread t = new ConnectivityThread();
+ t.start();
+ return t;
}
public static ConnectivityThread get() {
- return getInstance();
+ return Singleton.INSTANCE;
}
public static Looper getInstanceLooper() {
- return getInstance().getLooper();
+ return Singleton.INSTANCE.getLooper();
}
}
diff --git a/core/java/android/net/EventLogTags.logtags b/core/java/android/net/EventLogTags.logtags
new file mode 100644
index 0000000..d5ed014
--- /dev/null
+++ b/core/java/android/net/EventLogTags.logtags
@@ -0,0 +1,6 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.net
+
+50080 ntp_success (server|3),(rtt|2),(offset|2)
+50081 ntp_failure (server|3),(msg|3)
diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
index 8f634bb..d36b766 100644
--- a/core/java/android/net/IIpConnectivityMetrics.aidl
+++ b/core/java/android/net/IIpConnectivityMetrics.aidl
@@ -23,7 +23,8 @@
interface IIpConnectivityMetrics {
/**
- * @return number of remaining available slots in buffer.
+ * @return the number of remaining available slots in buffer,
+ * or -1 if the event was dropped due to rate limiting.
*/
int logEvent(in ConnectivityMetricsEvent event);
}
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 59cbf6e..24f4504 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -56,15 +56,26 @@
void disableScoring();
/**
- * Register a network subsystem for scoring.
+ * Register a cache to receive scoring updates.
+ *
+ * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
+ * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
+ * @param filterType the {@link CacheUpdateFilter} to apply
+ * @throws SecurityException if the caller is not the system
+ * @throws IllegalArgumentException if a score cache is already registed for this type
+ * @hide
+ */
+ void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache, int filterType);
+
+ /**
+ * Unregister a cache to receive scoring updates.
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
* @throws SecurityException if the caller is not the system.
- * @throws IllegalArgumentException if a score cache is already registed for this type.
* @hide
*/
- void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
+ void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
/**
* Request a recommendation for the best network to connect to
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index d570e66..c704ef0 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -171,7 +171,8 @@
String subscriberId = null;
String networkId = null;
boolean roaming = false;
- boolean metered = false;
+ boolean metered = !state.networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
if (isNetworkTypeMobile(type)) {
if (state.subscriberId == null) {
@@ -185,9 +186,6 @@
subscriberId = state.subscriberId;
roaming = state.networkInfo.isRoaming();
- metered = !state.networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-
} else if (type == TYPE_WIFI) {
if (state.networkId != null) {
networkId = state.networkId;
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index c301fe3..e08767c 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -17,6 +17,7 @@
package android.net;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -28,6 +29,9 @@
import android.os.ServiceManager;
import android.os.UserHandle;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Class that manages communication between network subsystems and a network scorer.
*
@@ -131,6 +135,29 @@
*/
public static final String EXTRA_NEW_SCORER = "newScorer";
+ /** @hide */
+ @IntDef({CACHE_FILTER_NONE, CACHE_FILTER_CURRENT_NETWORK, CACHE_FILTER_SCAN_RESULTS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CacheUpdateFilter {}
+
+ /**
+ * Do not filter updates sent to the cache.
+ * @hide
+ */
+ public static final int CACHE_FILTER_NONE = 0;
+
+ /**
+ * Only send cache updates when the network matches the connected network.
+ * @hide
+ */
+ public static final int CACHE_FILTER_CURRENT_NETWORK = 1;
+
+ /**
+ * Only send cache updates when the network is part of the current scan result set.
+ * @hide
+ */
+ public static final int CACHE_FILTER_SCAN_RESULTS = 2;
+
private final Context mContext;
private final INetworkScoreService mService;
@@ -268,11 +295,47 @@
* @throws SecurityException if the caller does not hold the
* {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
+ * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE.
* @hide
*/
+ @Deprecated // migrate to registerNetworkScoreCache(int, INetworkScoreCache, int)
public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+ registerNetworkScoreCache(networkType, scoreCache, CACHE_FILTER_NONE);
+ }
+
+ /**
+ * Register a network score cache.
+ *
+ * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
+ * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
+ * @param filterType the {@link CacheUpdateFilter} to apply
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+ * @throws IllegalArgumentException if a score cache is already registered for this type.
+ * @hide
+ */
+ public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache,
+ @CacheUpdateFilter int filterType) {
try {
- mService.registerNetworkScoreCache(networkType, scoreCache);
+ mService.registerNetworkScoreCache(networkType, scoreCache, filterType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregister a network score cache.
+ *
+ * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
+ * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+ * @throws IllegalArgumentException if a score cache is already registered for this type.
+ * @hide
+ */
+ public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+ try {
+ mService.unregisterNetworkScoreCache(networkType, scoreCache);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 25806fa..77ce65b 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -68,11 +68,18 @@
// TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
- /** {@link #set} value for all roaming values. */
+ /** {@link #metered} value to account for all metered states. */
+ public static final int METERED_ALL = -1;
+ /** {@link #metered} value where native, unmetered data is accounted. */
+ public static final int METERED_NO = 0;
+ /** {@link #metered} value where metered data is accounted. */
+ public static final int METERED_YES = 1;
+
+ /** {@link #roaming} value to account for all roaming states. */
public static final int ROAMING_ALL = -1;
- /** {@link #set} value where native, non-roaming data is accounted. */
+ /** {@link #roaming} value where native, non-roaming data is accounted. */
public static final int ROAMING_NO = 0;
- /** {@link #set} value where roaming data is accounted. */
+ /** {@link #roaming} value where roaming data is accounted. */
public static final int ROAMING_YES = 1;
// TODO: move fields to "mVariable" notation
@@ -88,6 +95,7 @@
private int[] uid;
private int[] set;
private int[] tag;
+ private int[] metered;
private int[] roaming;
private long[] rxBytes;
private long[] rxPackets;
@@ -105,6 +113,12 @@
* to disk. We merge in the correct value when reporting this value to clients of
* getSummary().
*/
+ public int metered;
+ /**
+ * Note that this is only populated w/ the default value when read from /proc or written
+ * to disk. We merge in the correct value when reporting this value to clients of
+ * getSummary().
+ */
public int roaming;
public long rxBytes;
public long rxPackets;
@@ -123,16 +137,17 @@
public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
- this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets,
- operations);
+ this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes,
+ txPackets, operations);
}
- public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes,
- long rxPackets, long txBytes, long txPackets, long operations) {
+ public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
+ long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
this.iface = iface;
this.uid = uid;
this.set = set;
this.tag = tag;
+ this.metered = metered;
this.roaming = roaming;
this.rxBytes = rxBytes;
this.rxPackets = rxPackets;
@@ -165,6 +180,7 @@
builder.append(" uid=").append(uid);
builder.append(" set=").append(setToString(set));
builder.append(" tag=").append(tagToString(tag));
+ builder.append(" metered=").append(meteredToString(metered));
builder.append(" roaming=").append(roamingToString(roaming));
builder.append(" rxBytes=").append(rxBytes);
builder.append(" rxPackets=").append(rxPackets);
@@ -178,13 +194,18 @@
public boolean equals(Object o) {
if (o instanceof Entry) {
final Entry e = (Entry) o;
- return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming
- && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes
- && txPackets == e.txPackets && operations == e.operations
- && iface.equals(e.iface);
+ return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered
+ && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets
+ && txBytes == e.txBytes && txPackets == e.txPackets
+ && operations == e.operations && iface.equals(e.iface);
}
return false;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uid, set, tag, metered, roaming, iface);
+ }
}
public NetworkStats(long elapsedRealtime, int initialSize) {
@@ -196,6 +217,7 @@
this.uid = new int[initialSize];
this.set = new int[initialSize];
this.tag = new int[initialSize];
+ this.metered = new int[initialSize];
this.roaming = new int[initialSize];
this.rxBytes = new long[initialSize];
this.rxPackets = new long[initialSize];
@@ -209,6 +231,7 @@
this.uid = EmptyArray.INT;
this.set = EmptyArray.INT;
this.tag = EmptyArray.INT;
+ this.metered = EmptyArray.INT;
this.roaming = EmptyArray.INT;
this.rxBytes = EmptyArray.LONG;
this.rxPackets = EmptyArray.LONG;
@@ -226,6 +249,7 @@
uid = parcel.createIntArray();
set = parcel.createIntArray();
tag = parcel.createIntArray();
+ metered = parcel.createIntArray();
roaming = parcel.createIntArray();
rxBytes = parcel.createLongArray();
rxPackets = parcel.createLongArray();
@@ -243,6 +267,7 @@
dest.writeIntArray(uid);
dest.writeIntArray(set);
dest.writeIntArray(tag);
+ dest.writeIntArray(metered);
dest.writeIntArray(roaming);
dest.writeLongArray(rxBytes);
dest.writeLongArray(rxPackets);
@@ -277,10 +302,11 @@
}
@VisibleForTesting
- public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming,
+ public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming,
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
return addValues(new Entry(
- iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations));
+ iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets,
+ operations));
}
/**
@@ -294,6 +320,7 @@
uid = Arrays.copyOf(uid, newLength);
set = Arrays.copyOf(set, newLength);
tag = Arrays.copyOf(tag, newLength);
+ metered = Arrays.copyOf(metered, newLength);
roaming = Arrays.copyOf(roaming, newLength);
rxBytes = Arrays.copyOf(rxBytes, newLength);
rxPackets = Arrays.copyOf(rxPackets, newLength);
@@ -307,6 +334,7 @@
uid[size] = entry.uid;
set[size] = entry.set;
tag[size] = entry.tag;
+ metered[size] = entry.metered;
roaming[size] = entry.roaming;
rxBytes[size] = entry.rxBytes;
rxPackets[size] = entry.rxPackets;
@@ -327,6 +355,7 @@
entry.uid = uid[i];
entry.set = set[i];
entry.tag = tag[i];
+ entry.metered = metered[i];
entry.roaming = roaming[i];
entry.rxBytes = rxBytes[i];
entry.rxPackets = rxPackets[i];
@@ -381,7 +410,8 @@
* also be used to subtract values from existing rows.
*/
public NetworkStats combineValues(Entry entry) {
- final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming);
+ final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
+ entry.roaming);
if (i == -1) {
// only create new entry when positive contribution
addValues(entry);
@@ -409,10 +439,11 @@
/**
* Find first stats index that matches the requested parameters.
*/
- public int findIndex(String iface, int uid, int set, int tag, int roaming) {
+ public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) {
for (int i = 0; i < size; i++) {
if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
- && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) {
+ && metered == this.metered[i] && roaming == this.roaming[i]
+ && Objects.equals(iface, this.iface[i])) {
return i;
}
}
@@ -424,7 +455,7 @@
* search around the hinted index as an optimization.
*/
@VisibleForTesting
- public int findIndexHinted(String iface, int uid, int set, int tag, int roaming,
+ public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
int hintIndex) {
for (int offset = 0; offset < size; offset++) {
final int halfOffset = offset / 2;
@@ -438,7 +469,8 @@
}
if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
- && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) {
+ && metered == this.metered[i] && roaming == this.roaming[i]
+ && Objects.equals(iface, this.iface[i])) {
return i;
}
}
@@ -452,7 +484,7 @@
*/
public void spliceOperationsFrom(NetworkStats stats) {
for (int i = 0; i < size; i++) {
- final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]);
+ final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]);
if (j == -1) {
operations[i] = 0;
} else {
@@ -542,6 +574,7 @@
entry.uid = limitUid;
entry.set = SET_ALL;
entry.tag = TAG_NONE;
+ entry.metered = METERED_ALL;
entry.roaming = ROAMING_ALL;
entry.rxBytes = 0;
entry.rxPackets = 0;
@@ -637,11 +670,12 @@
entry.uid = left.uid[i];
entry.set = left.set[i];
entry.tag = left.tag[i];
+ entry.metered = left.metered[i];
entry.roaming = left.roaming[i];
// find remote row that matches, and subtract
final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag,
- entry.roaming, i);
+ entry.metered, entry.roaming, i);
if (j == -1) {
// newly appearing row, return entire value
entry.rxBytes = left.rxBytes[i];
@@ -687,6 +721,7 @@
entry.uid = UID_ALL;
entry.set = SET_ALL;
entry.tag = TAG_NONE;
+ entry.metered = METERED_ALL;
entry.roaming = ROAMING_ALL;
entry.operations = 0L;
@@ -716,6 +751,7 @@
entry.iface = IFACE_ALL;
entry.set = SET_ALL;
entry.tag = TAG_NONE;
+ entry.metered = METERED_ALL;
entry.roaming = ROAMING_ALL;
for (int i = 0; i < size; i++) {
@@ -762,6 +798,7 @@
pw.print(" uid="); pw.print(uid[i]);
pw.print(" set="); pw.print(setToString(set[i]));
pw.print(" tag="); pw.print(tagToString(tag[i]));
+ pw.print(" metered="); pw.print(meteredToString(metered[i]));
pw.print(" roaming="); pw.print(roamingToString(roaming[i]));
pw.print(" rxBytes="); pw.print(rxBytes[i]);
pw.print(" rxPackets="); pw.print(rxPackets[i]);
@@ -830,6 +867,22 @@
}
/**
+ * Return text description of {@link #metered} value.
+ */
+ public static String meteredToString(int metered) {
+ switch (metered) {
+ case METERED_ALL:
+ return "ALL";
+ case METERED_NO:
+ return "NO";
+ case METERED_YES:
+ return "YES";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ /**
* Return text description of {@link #roaming} value.
*/
public static String roamingToString(int roaming) {
@@ -904,7 +957,8 @@
if (pool.isEmpty()) {
return true;
}
- Entry moved = addTrafficToApplications(tunIface, underlyingIface, tunIfaceTotal, pool);
+ Entry moved =
+ addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool);
deductTrafficFromVpnApp(tunUid, underlyingIface, moved);
if (!moved.isEmpty()) {
@@ -919,9 +973,9 @@
* Initializes the data used by the migrateTun() method.
*
* This is the first pass iteration which does the following work:
- * (1) Adds up all the traffic through tun0.
- * (2) Adds up all the traffic through the tunUid's underlyingIface
+ * (1) Adds up all the traffic through the tunUid's underlyingIface
* (both foreground and background).
+ * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself.
*/
private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface,
Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
@@ -941,8 +995,9 @@
underlyingIfaceTotal.add(recycle);
}
- if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) {
- // Add up all tunIface traffic.
+ if (recycle.uid != tunUid && recycle.tag == TAG_NONE
+ && Objects.equals(tunIface, recycle.iface)) {
+ // Add up all tunIface traffic excluding traffic from the vpn app itself.
tunIfaceTotal.add(recycle);
}
}
@@ -958,13 +1013,15 @@
return pool;
}
- private Entry addTrafficToApplications(String tunIface, String underlyingIface,
+ private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface,
Entry tunIfaceTotal, Entry pool) {
Entry moved = new Entry();
Entry tmpEntry = new Entry();
tmpEntry.iface = underlyingIface;
for (int i = 0; i < size; i++) {
- if (Objects.equals(iface[i], tunIface)) {
+ // the vpn app is excluded from the redistribution but all moved traffic will be
+ // deducted from the vpn app (see deductTrafficFromVpnApp below).
+ if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) {
if (tunIfaceTotal.rxBytes > 0) {
tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
} else {
@@ -994,6 +1051,7 @@
tmpEntry.uid = uid[i];
tmpEntry.tag = tag[i];
tmpEntry.set = set[i];
+ tmpEntry.metered = metered[i];
tmpEntry.roaming = roaming[i];
combineValues(tmpEntry);
if (tag[i] == TAG_NONE) {
@@ -1013,24 +1071,25 @@
moved.set = SET_DBG_VPN_OUT;
moved.tag = TAG_NONE;
moved.iface = underlyingIface;
+ moved.metered = METERED_ALL;
moved.roaming = ROAMING_ALL;
combineValues(moved);
// Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
// the TAG_NONE traffic.
//
- // Relies on the fact that the underlying traffic only has state ROAMING_NO, which
- // should be the case as it comes directly from the /proc file. We only blend in the
+ // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO,
+ // which should be the case as it comes directly from the /proc file. We only blend in the
// roaming data after applying these adjustments, by checking the NetworkIdentity of the
// underlying iface.
int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
- ROAMING_NO);
+ METERED_NO, ROAMING_NO);
if (idxVpnBackground != -1) {
tunSubtract(idxVpnBackground, this, moved);
}
int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
- ROAMING_NO);
+ METERED_NO, ROAMING_NO);
if (idxVpnForeground != -1) {
tunSubtract(idxVpnForeground, this, moved);
}
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index cf9243f..cea56b5 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -36,8 +36,7 @@
* }
* </pre>
*/
-public class SntpClient
-{
+public class SntpClient {
private static final String TAG = "SntpClient";
private static final boolean DBG = true;
@@ -88,6 +87,7 @@
try {
address = InetAddress.getByName(host);
} catch (Exception e) {
+ EventLogTags.writeNtpFailure(host, e.toString());
if (DBG) Log.d(TAG, "request time failed: " + e);
return false;
}
@@ -142,6 +142,7 @@
// = (transit + skew - transit + skew)/2
// = (2 * skew)/2 = skew
long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
+ EventLogTags.writeNtpSuccess(address.toString(), roundTripTime, clockOffset);
if (DBG) {
Log.d(TAG, "round trip: " + roundTripTime + "ms, " +
"clock offset: " + clockOffset + "ms");
@@ -153,6 +154,7 @@
mNtpTimeReference = responseTicks;
mRoundTripTime = roundTripTime;
} catch (Exception e) {
+ EventLogTags.writeNtpFailure(address.toString(), e.toString());
if (DBG) Log.d(TAG, "request time failed: " + e);
return false;
} finally {
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 3b3fa69..0667495 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -42,6 +42,15 @@
public static final int NETWORK_DISCONNECTED = 7;
/** {@hide} */
+ public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8;
+ /** {@hide} */
+ public static final int NETWORK_REVALIDATION_SUCCESS = 9;
+ /** {@hide} */
+ public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10;
+ /** {@hide} */
+ public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11;
+
+ /** {@hide} */
@IntDef(value = {
NETWORK_CONNECTED,
NETWORK_VALIDATED,
@@ -50,6 +59,10 @@
NETWORK_LINGER,
NETWORK_UNLINGER,
NETWORK_DISCONNECTED,
+ NETWORK_FIRST_VALIDATION_SUCCESS,
+ NETWORK_REVALIDATION_SUCCESS,
+ NETWORK_FIRST_VALIDATION_PORTAL_FOUND,
+ NETWORK_REVALIDATION_PORTAL_FOUND,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 1a31b56f..a724ec1 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -44,10 +44,8 @@
public static final int DNS_FAILURE = 0;
public static final int DNS_SUCCESS = 1;
- /** {@hide} */
- @IntDef(value = {PROBE_DNS, PROBE_HTTP, PROBE_HTTPS, PROBE_PAC})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ProbeType {}
+ private static final int FIRST_VALIDATION = 1 << 8;
+ private static final int REVALIDATION = 2 << 8;
/** {@hide} */
@IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
@@ -56,12 +54,17 @@
public final int netId;
public final long durationMs;
- public final @ProbeType int probeType;
+ // probeType byte format (MSB to LSB):
+ // byte 0: unused
+ // byte 1: unused
+ // byte 2: 0 = UNKNOWN, 1 = FIRST_VALIDATION, 2 = REVALIDATION
+ // byte 3: PROBE_* constant
+ public final int probeType;
public final @ReturnCode int returnCode;
/** {@hide} */
public ValidationProbeEvent(
- int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) {
+ int netId, long durationMs, int probeType, @ReturnCode int returnCode) {
this.netId = netId;
this.durationMs = durationMs;
this.probeType = probeType;
@@ -100,8 +103,18 @@
};
/** @hide */
+ public static int makeProbeType(int probeType, boolean firstValidation) {
+ return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
+ }
+
+ /** @hide */
public static String getProbeName(int probeType) {
- return Decoder.constants.get(probeType, "PROBE_???");
+ return Decoder.constants.get(probeType & 0xff, "PROBE_???");
+ }
+
+ /** @hide */
+ public static String getValidationStage(int probeType) {
+ return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
}
public static void logEvent(int netId, long durationMs, int probeType, int returnCode) {
@@ -109,12 +122,13 @@
@Override
public String toString() {
- return String.format("ValidationProbeEvent(%d, %s:%d, %dms)",
- netId, getProbeName(probeType), returnCode, durationMs);
+ return String.format("ValidationProbeEvent(%d, %s:%d %s, %dms)", netId,
+ getProbeName(probeType), returnCode, getValidationStage(probeType), durationMs);
}
final static class Decoder {
static final SparseArray<String> constants = MessageUtils.findMessageNames(
- new Class[]{ValidationProbeEvent.class}, new String[]{"PROBE_"});
+ new Class[]{ValidationProbeEvent.class},
+ new String[]{"PROBE_", "FIRST_", "REVALIDATION"});
}
}
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 86bd502..33d12a3 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -103,11 +103,11 @@
* to {@link DiscoveryListener#onServiceFound} and a service lost is notified on
* {@link DiscoveryListener#onServiceLost}.
*
- * <p> Once the peer application discovers the "Example" http srevice, and needs to receive data
- * from the "Example" application, it can initiate a resolve with {@link #resolveService} to
- * resolve the host and port details for the purpose of establishing a connection. A successful
- * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified
- * on {@link ResolveListener#onResolveFailed}.
+ * <p> Once the peer application discovers the "Example" http service, and either needs to read the
+ * attributes of the service or wants to receive data from the "Example" application, it can
+ * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port
+ * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a
+ * failure is notified on {@link ResolveListener#onResolveFailed}.
*
* Applications can reserve for a service type at
* http://www.iana.org/form/ports-service. Existing services can be found at
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 4a06fb1..7b845be 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -250,7 +250,8 @@
}
/**
- * Retrive attributes as a map of String keys to byte[] values.
+ * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only
+ * valid for a resolved service.
*
* <p> The returned map is unmodifiable; changes must be made through {@link #setAttribute} and
* {@link #removeAttribute}.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1350bfa..e52983e 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7172,6 +7172,13 @@
*/
public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
+ /**
+ * Size of the event buffer for IP connectivity metrics.
+ * @hide
+ */
+ public static final String CONNECTIVITY_METRICS_BUFFER_SIZE =
+ "connectivity_metrics_buffer_size";
+
/** {@hide} */
public static final String NETSTATS_ENABLED = "netstats_enabled";
/** {@hide} */
@@ -8028,11 +8035,45 @@
public static final String PAC_CHANGE_DELAY = "pac_change_delay";
/**
- * Setting to turn off captive portal detection. Feature is enabled by
- * default and the setting needs to be set to 0 to disable it.
+ * Don't attempt to detect captive portals.
*
* @hide
*/
+ public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
+
+ /**
+ * When detecting a captive portal, display a notification that
+ * prompts the user to sign in.
+ *
+ * @hide
+ */
+ public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
+
+ /**
+ * When detecting a captive portal, immediately disconnect from the
+ * network and do not reconnect to that network in the future.
+ *
+ * @hide
+ */
+ public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
+
+ /**
+ * What to do when connecting a network that presents a captive portal.
+ * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
+ *
+ * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
+
+ /**
+ * Setting to turn off captive portal detection. Feature is enabled by
+ * default and the setting needs to be set to 0 to disable it.
+ *
+ * @deprecated use CAPTIVE_PORTAL_MODE_IGNORE to disable captive portal detection
+ * @hide
+ */
+ @Deprecated
public static final String
CAPTIVE_PORTAL_DETECTION_ENABLED = "captive_portal_detection_enabled";
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 419c3d8..62f674c 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -134,13 +134,6 @@
return resRaw;
}
- public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
- int dexFlags, String compilerFilter, String volumeUuid, String sharedLibraries)
- throws InstallerException {
- dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, null /*outputPath*/, dexFlags,
- compilerFilter, volumeUuid, sharedLibraries);
- }
-
public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter,
String volumeUuid, String sharedLibraries) throws InstallerException {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index e1118d8..5b46a09 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -31,6 +31,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.ZygoteProcess;
+import android.os.storage.StorageManager;
import android.security.keystore.AndroidKeyStoreProvider;
import android.system.ErrnoException;
import android.system.Os;
@@ -522,10 +523,15 @@
}
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+ final String packageName = "*";
+ final String outputPath = null;
+ final int dexFlags = 0;
+ final String compilerFilter = "speed";
+ final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
try {
- installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
- dexoptNeeded, 0 /*dexFlags*/, "speed", null /*volumeUuid*/,
- sharedLibraries);
+ installer.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
+ instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
+ uuid, sharedLibraries);
} catch (InstallerException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
diff --git a/core/java/com/android/internal/util/TokenBucket.java b/core/java/com/android/internal/util/TokenBucket.java
new file mode 100644
index 0000000..effb82ba
--- /dev/null
+++ b/core/java/com/android/internal/util/TokenBucket.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 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.util;
+
+import android.os.SystemClock;
+
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
+import static com.android.internal.util.Preconditions.checkArgumentPositive;
+
+/**
+ * A class useful for rate-limiting or throttling that stores and distributes tokens.
+ *
+ * A TokenBucket starts with a fixed capacity of tokens, an initial amount of tokens, and
+ * a fixed filling period (in milliseconds).
+ *
+ * For every filling period, the bucket gains one token, up to its maximum capacity from
+ * which point tokens simply overflow and are lost. Tokens can be obtained one by one or n by n.
+ *
+ * The available amount of tokens is computed lazily when the bucket state is inspected.
+ * Therefore it is purely synchronous and does not involve any asynchronous activity.
+ * It is not synchronized in any way and not a thread-safe object.
+ */
+public class TokenBucket {
+
+ private final int mFillDelta; // Time in ms it takes to generate one token.
+ private final int mCapacity; // Maximum number of tokens that can be stored.
+ private long mLastFill; // Last time in ms the bucket generated tokens.
+ private int mAvailable; // Current number of available tokens.
+
+ /**
+ * Create a new TokenBucket.
+ * @param deltaMs the time in milliseconds it takes to generate a new token.
+ * Must be strictly positive.
+ * @param capacity the maximum token capacity. Must be strictly positive.
+ * @param tokens the starting amount of token. Must be positive or zero.
+ */
+ public TokenBucket(int deltaMs, int capacity, int tokens) {
+ mFillDelta = checkArgumentPositive(deltaMs, "deltaMs must be strictly positive");
+ mCapacity = checkArgumentPositive(capacity, "capacity must be strictly positive");
+ mAvailable = Math.min(checkArgumentNonnegative(tokens), mCapacity);
+ mLastFill = scaledTime();
+ }
+
+ /**
+ * Create a new TokenBucket that starts completely filled.
+ * @param deltaMs the time in milliseconds it takes to generate a new token.
+ * Must be strictly positive.
+ * @param capacity the maximum token capacity. Must be strictly positive.
+ */
+ public TokenBucket(int deltaMs, int capacity) {
+ this(deltaMs, capacity, capacity);
+ }
+
+ /** Reset this TokenBucket and set its number of available tokens. */
+ public void reset(int tokens) {
+ checkArgumentNonnegative(tokens);
+ mAvailable = Math.min(tokens, mCapacity);
+ mLastFill = scaledTime();
+ }
+
+ /** Returns this TokenBucket maximum token capacity. */
+ public int capacity() {
+ return mCapacity;
+ }
+
+ /** Returns this TokenBucket currently number of available tokens. */
+ public int available() {
+ fill();
+ return mAvailable;
+ }
+
+ /** Returns true if this TokenBucket as one or more tokens available. */
+ public boolean has() {
+ fill();
+ return mAvailable > 0;
+ }
+
+ /** Consumes a token from this TokenBucket and returns true if a token is available. */
+ public boolean get() {
+ return (get(1) == 1);
+ }
+
+ /**
+ * Try to consume many tokens from this TokenBucket.
+ * @param n the number of tokens to consume.
+ * @return the number of tokens that were actually consumed.
+ */
+ public int get(int n) {
+ fill();
+ if (n <= 0) {
+ return 0;
+ }
+ if (n > mAvailable) {
+ int got = mAvailable;
+ mAvailable = 0;
+ return got;
+ }
+ mAvailable -= n;
+ return n;
+ }
+
+ private void fill() {
+ final long now = scaledTime();
+ final int diff = (int) (now - mLastFill);
+ mAvailable = Math.min(mCapacity, mAvailable + diff);
+ mLastFill = now;
+ }
+
+ private long scaledTime() {
+ return SystemClock.elapsedRealtime() / mFillDelta;
+ }
+}
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 9fa90ac..4a2b881 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -43,6 +43,7 @@
jfieldID uid;
jfieldID set;
jfieldID tag;
+ jfieldID metered;
jfieldID roaming;
jfieldID rxBytes;
jfieldID rxPackets;
@@ -239,6 +240,9 @@
ScopedIntArrayRW tag(env, get_int_array(env, stats,
gNetworkStatsClassInfo.tag, size, grow));
if (tag.get() == NULL) return -1;
+ ScopedIntArrayRW metered(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.metered, size, grow));
+ if (metered.get() == NULL) return -1;
ScopedIntArrayRW roaming(env, get_int_array(env, stats,
gNetworkStatsClassInfo.roaming, size, grow));
if (roaming.get() == NULL) return -1;
@@ -265,7 +269,7 @@
uid[i] = lines[i].uid;
set[i] = lines[i].set;
tag[i] = lines[i].tag;
- // Roaming is populated in Java-land by inspecting the iface properties.
+ // Metered and Roaming are populated in Java-land by inspecting the iface properties.
rxBytes[i] = lines[i].rxBytes;
rxPackets[i] = lines[i].rxPackets;
txBytes[i] = lines[i].txBytes;
@@ -279,6 +283,7 @@
env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
@@ -311,6 +316,7 @@
gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I");
gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I");
gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I");
+ gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I");
gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I");
gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J");
gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J");
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 22255b4..25021b8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1681,7 +1681,7 @@
<bool name="config_actionMenuItemAllCaps">true</bool>
<!-- Remote server that can provide NTP responses. -->
- <string translatable="false" name="config_ntpServer">2.android.pool.ntp.org</string>
+ <string translatable="false" name="config_ntpServer">time.android.com</string>
<!-- Normal polling frequency in milliseconds -->
<integer name="config_ntpPollingInterval">86400000</integer>
<!-- Try-again polling interval in milliseconds, in case the network request failed -->
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 9074f8a..eb85eb4 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -16,6 +16,9 @@
package android.net;
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
@@ -45,103 +48,124 @@
private static final long TEST_START = 1194220800000L;
public void testFindIndex() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 4)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L,
- 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L,
- 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
- 1024L, 8L, 12)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L,
- 1024L, 8L, 12);
+ final NetworkStats stats = new NetworkStats(TEST_START, 5)
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+ 8L, 0L, 0L, 10)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+ 1024L, 8L, 11)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 0L, 0L,
+ 1024L, 8L, 11)
+ .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+ 8L, 1024L, 8L, 12)
+ .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L,
+ 8L, 1024L, 8L, 12);
- assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES));
- assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO));
- assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO));
- assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO));
- assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, ROAMING_NO));
+ assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES,
+ ROAMING_YES));
+ assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO));
+ assertEquals(2, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES,
+ ROAMING_NO));
+ assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO));
+ assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO));
+ assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO));
}
public void testFindIndexHinted() {
final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L, 0L,
- 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 1024L,
- 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
- 1024L, 8L, 12)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 1024L, 8L,
- 0L, 0L, 10)
- .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 0L, 0L, 1024L,
- 8L, 11)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
- 1024L, 8L, 12)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_YES, 1024L, 8L,
- 1024L, 8L, 12);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+ 8L, 0L, 0L, 10)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+ 1024L, 8L, 11)
+ .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+ 8L, 1024L, 8L, 12)
+ .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ 1024L, 8L, 0L, 0L, 10)
+ .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 0L, 0L,
+ 1024L, 8L, 11)
+ .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 0L, 0L,
+ 1024L, 8L, 11)
+ .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
+ 8L, 1024L, 8L, 12)
+ .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L,
+ 8L, 1024L, 8L, 12);
// verify that we correctly find across regardless of hinting
for (int hint = 0; hint < stats.size(); hint++) {
assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE,
- ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, hint));
assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE,
- ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, hint));
assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE,
- ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, hint));
assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE,
- ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, hint));
assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
- ROAMING_NO, hint));
- assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, hint));
+ assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
+ METERED_YES, ROAMING_NO, hint));
assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- ROAMING_YES, hint));
+ METERED_NO, ROAMING_NO, hint));
+ assertEquals(7, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
+ METERED_YES, ROAMING_YES, hint));
assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE,
- ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, hint));
}
}
public void testAddEntryGrow() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 3);
+ final NetworkStats stats = new NetworkStats(TEST_START, 4);
assertEquals(0, stats.size());
- assertEquals(3, stats.internalSize());
+ assertEquals(4, stats.internalSize());
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L,
- 2L, 3);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L, 2L,
- 2L, 4);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L, 2L,
- 2L, 5);
-
- assertEquals(3, stats.size());
- assertEquals(3, stats.internalSize());
-
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L, 40L, 4L,
- 40L, 7);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L, 50L, 4L,
- 40L, 8);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L, 60L, 5L,
- 50L, 10);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L, 70L, 5L,
- 50L, 11);
-
- assertEquals(7, stats.size());
- assertTrue(stats.internalSize() >= 7);
-
- assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L,
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L, 1L,
2L, 2L, 3);
- assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2L, 2L,
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 2L, 2L,
2L, 2L, 4);
- assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 3L, 3L,
- 2L, 2L, 5);
- assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 4L,
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 3L,
+ 3L, 2L, 2L, 5);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 3L,
+ 3L, 2L, 2L, 5);
+
+ assertEquals(4, stats.size());
+ assertEquals(4, stats.internalSize());
+
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4L,
40L, 4L, 40L, 7);
- assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 5L,
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5L,
50L, 4L, 40L, 8);
- assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_NO, 6L,
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 6L,
60L, 5L, 50L, 10);
- assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_YES, 7L,
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 7L,
70L, 5L, 50L, 11);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 7L,
+ 70L, 5L, 50L, 11);
+
+ assertEquals(9, stats.size());
+ assertTrue(stats.internalSize() >= 9);
+
+ assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 1L, 1L, 2L, 2L, 3);
+ assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 2L, 2L, 2L, 2L, 4);
+ assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ 3L, 3L, 2L, 2L, 5);
+ assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
+ ROAMING_YES, 3L, 3L, 2L, 2L, 5);
+ assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 4L, 40L, 4L, 40L, 7);
+ assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 5L, 50L, 4L, 40L, 8);
+ assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 6L, 60L, 5L, 50L, 10);
+ assertValues(stats, 7, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ 7L, 70L, 5L, 50L, 11);
+ assertValues(stats, 8, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
+ ROAMING_YES, 7L, 70L, 5L, 50L, 11);
}
public void testCombineExisting() throws Exception {
@@ -152,20 +176,18 @@
stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
-128L, -1L, -1);
- assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, ROAMING_NO, 384L, 3L,
- 128L, 1L, 9);
- assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, ROAMING_NO, 128L, 1L, 128L,
- 1L, 2);
+ assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 384L, 3L, 128L, 1L, 9);
+ assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, METERED_NO, ROAMING_NO, 128L,
+ 1L, 128L, 1L, 2);
// now try combining that should create row
- stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L,
- 128L, 1L, 3);
- assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 1L,
- 128L, 1L, 3);
- stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L,
- 128L, 1L, 3);
- assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, ROAMING_NO, 256L, 2L,
- 256L, 2L, 6);
+ stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
+ assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 128L, 1L, 128L, 1L, 3);
+ stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
+ assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 256L, 2L, 256L, 2L, 6);
}
public void testSubtractIdenticalData() throws Exception {
@@ -180,10 +202,10 @@
final NetworkStats result = after.subtract(before);
// identical data should result in zero delta
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
- 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
- 0L, 0);
+ assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+ 0L, 0L, 0L, 0);
+ assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+ 0L, 0L, 0L, 0);
}
public void testSubtractIdenticalRows() throws Exception {
@@ -198,10 +220,10 @@
final NetworkStats result = after.subtract(before);
// expect delta between measurements
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L, 1L, 2L,
- 1L, 4);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 3L, 1L, 4L,
- 1L, 8);
+ assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L,
+ 1L, 2L, 1L, 4);
+ assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 3L,
+ 1L, 4L, 1L, 8);
}
public void testSubtractNewRows() throws Exception {
@@ -217,12 +239,12 @@
final NetworkStats result = after.subtract(before);
// its okay to have new rows
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
- 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 0L, 0L, 0L,
- 0L, 0);
- assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
- 1024L, 8L, 20);
+ assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+ 0L, 0L, 0L, 0);
+ assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+ 0L, 0L, 0L, 0);
+ assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 1024L, 8L, 1024L, 8L, 20);
}
public void testSubtractMissingRows() throws Exception {
@@ -237,8 +259,8 @@
// should silently drop omitted rows
assertEquals(1, result.size());
- assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1L,
- 2L, 3L, 4L, 0);
+ assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, 1L, 2L, 3L, 4L, 0);
assertEquals(4L, result.getTotalBytes());
}
@@ -263,13 +285,22 @@
.addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
assertEquals(64L, uidTag.getTotalBytes());
+ final NetworkStats uidMetered = new NetworkStats(TEST_START, 3)
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+ 0L, 0L, 0L);
+ assertEquals(96L, uidMetered.getTotalBytes());
+
final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 32L, 0L, 0L, 0L,
- 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 32L, 0L,
+ 0L, 0L, 0L);
assertEquals(96L, uidRoaming.getTotalBytes());
}
@@ -283,95 +314,95 @@
public void testGroupedByIfaceAll() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
- .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, ROAMING_NO, 128L, 8L, 0L, 2L,
- 20L)
- .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
+ .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, 0L,
2L, 20L)
- .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, ROAMING_YES, 128L, 8L, 0L, 2L,
- 20L);
+ .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, 128L,
+ 8L, 0L, 2L, 20L)
+ .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, 128L, 8L, 0L,
+ 2L, 20L);
final NetworkStats grouped = uidStats.groupedByIface();
assertEquals(3, uidStats.size());
assertEquals(1, grouped.size());
- assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L,
- 6L, 0L);
+ assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+ 384L, 24L, 0L, 6L, 0L);
}
public void testGroupedByIface() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
- 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L,
- 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L,
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
+ 0L, 2L, 20L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+ 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L,
0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
- 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L,
- 0L, 0L);
+ .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+ 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 128L, 8L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L,
+ 8L, 0L, 0L, 0L);
final NetworkStats grouped = uidStats.groupedByIface();
assertEquals(7, uidStats.size());
assertEquals(2, grouped.size());
- assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L,
- 2L, 0L);
- assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 1024L, 64L,
- 0L, 0L, 0L);
+ assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+ 384L, 24L, 0L, 2L, 0L);
+ assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+ 1024L, 64L, 0L, 0L, 0L);
}
public void testAddAllValues() {
final NetworkStats first = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L, 0L,
- 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L,
- 0L, 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 32L,
+ 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L,
+ 0L, 0L, 0L, 0L);
final NetworkStats second = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L, 0L,
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 32L, 0L, 0L,
- 0L, 0L);
+ .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L,
+ 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L,
+ 0L, 0L, 0L, 0L);
first.combineAllValues(second);
assertEquals(4, first.size());
- assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 64L, 0L, 0L,
- 0L, 0L);
- assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L);
- assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_YES, 64L, 0L,
- 0L, 0L, 0L);
- assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, 32L,
+ assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 64L,
0L, 0L, 0L, 0L);
+ assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ 32L, 0L, 0L, 0L, 0L);
+ assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+ 64L, 0L, 0L, 0L, 0L);
+ assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 32L, 0L, 0L, 0L, 0L);
}
public void testGetTotal() {
final NetworkStats stats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
- 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 512L, 32L, 0L,
- 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 4L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 512L, 32L,
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
+ 0L, 2L, 20L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+ 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L,
0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L, 0L,
- 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L, 0L,
- 0L)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 8L, 0L,
- 0L, 0L);
+ .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
+ 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 128L,
+ 8L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L, 8L,
+ 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L,
+ 8L, 0L, 0L, 0L);
assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
assertValues(stats.getTotal(null, 100), 1280L, 80L, 0L, 2L, 20L);
@@ -396,10 +427,10 @@
final NetworkStats after = before.withoutUids(new int[] { 100 });
assertEquals(6, before.size());
assertEquals(2, after.size());
- assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 8L,
- 0L, 0L, 0L);
- assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_NO, 128L, 8L, 0L,
- 0L, 0L);
+ assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 128L, 8L, 0L, 0L, 0L);
+ assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L,
+ 8L, 0L, 0L, 0L);
}
public void testClone() throws Exception {
@@ -434,105 +465,175 @@
final String underlyingIface = "wlan0";
final int testTag1 = 8888;
NetworkStats delta = new NetworkStats(TEST_START, 17)
- .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 39605L, 46L, 12259L, 55L, 0L)
- .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
- .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, 72667L, 197L, 43909L, 241L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, 9297L, 17L, 4128L, 21L, 0L)
+ .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 39605L, 46L,
+ 12259L, 55L, 0L)
+ .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+ 0L, 0L, 0L)
+ .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 72667L, 197L,
+ 43909L, 241L, 0L)
+ .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 9297L,
+ 17L, 4128L, 21L, 0L)
// VPN package also uses some traffic through unprotected network.
- .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 4983L, 10L, 1801L, 12L, 0L)
- .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
+ .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4983L, 10L,
+ 1801L, 12L, 0L)
+ .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
+ 0L, 0L, 0L)
// Tag entries
- .addValues(tunIface, 10120, SET_DEFAULT, testTag1, 21691L, 41L, 13820L, 51L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, 1281L, 2L, 665L, 2L, 0L)
+ .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, 21691L, 41L,
+ 13820L, 51L, 0L)
+ .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, 1281L, 2L,
+ 665L, 2L, 0L)
// Irrelevant entries
- .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, 1685L, 5L, 2070L, 6L, 0L)
+ .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1685L, 5L,
+ 2070L, 6L, 0L)
// Underlying Iface entries
- .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 5178L, 8L, 2139L, 11L, 0L)
- .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
- .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, 149873L, 287L,
- 59217L /* smaller than sum(tun0) */, 299L /* smaller than sum(tun0) */, 0L)
- .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+ .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5178L,
+ 8L, 2139L, 11L, 0L)
+ .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
+ 0L, 0L, 0L, 0L)
+ .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 149873L, 287L, 59217L /* smaller than sum(tun0) */,
+ 299L /* smaller than sum(tun0) */, 0L)
+ .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ 0L, 0L, 0L, 0L, 0L);
assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
- assertEquals(21, delta.size());
+ assertEquals(20, delta.size());
// tunIface and TEST_IFACE entries are not changed.
- assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
39605L, 46L, 12259L, 55L, 0L);
- assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L,
- 0L, 0L, 0L);
- assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ 0L, 0L, 0L, 0L, 0L);
+ assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
72667L, 197L, 43909L, 241L, 0L);
- assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
+ assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
9297L, 17L, 4128L, 21L, 0L);
- assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
4983L, 10L, 1801L, 12L, 0L);
- assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 0L, 0L,
- 0L, 0L, 0L);
- assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
+ assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ 0L, 0L, 0L, 0L, 0L);
+ assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
21691L, 41L, 13820L, 51L, 0L);
- assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO, 1281L,
- 2L, 665L, 2L, 0L);
- assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1685L, 5L,
- 2070L, 6L, 0L);
+ assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
+ 1281L, 2L, 665L, 2L, 0L);
+ assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 1685L, 5L, 2070L, 6L, 0L);
// Existing underlying Iface entries are updated
- assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
- 44783L, 54L, 13829L, 60L, 0L);
- assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
- 0L, 0L, 0L, 0L, 0L);
+ assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, 44783L, 54L, 14178L, 62L, 0L);
+ assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO,
+ ROAMING_NO, 0L, 0L, 0L, 0L, 0L);
// VPN underlying Iface entries are updated
- assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
- 28304L, 27L, 1719L, 12L, 0L);
- assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
- 0L, 0L, 0L, 0L, 0L);
+ assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, 28304L, 27L, 1L, 2L, 0L);
+ assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO,
+ ROAMING_NO, 0L, 0L, 0L, 0L, 0L);
// New entries are added for new application's underlying Iface traffic
- assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
- 72667L, 197L, 41872L, 219L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
- 9297L, 17L, 3936, 19L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
- 21691L, 41L, 13179L, 46L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO,
- 1281L, 2L, 634L, 1L, 0L);
+ assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, 72667L, 197L, 43123L, 227L, 0L);
+ assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO,
+ ROAMING_NO, 9297L, 17L, 4054, 19L, 0L);
+ assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, METERED_NO,
+ ROAMING_NO, 21691L, 41L, 13572L, 48L, 0L);
+ assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, METERED_NO,
+ ROAMING_NO, 1281L, 2L, 653L, 1L, 0L);
// New entries are added for debug purpose
- assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
- 39605L, 46L, 11690, 49, 0);
- assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
- 81964, 214, 45808, 238, 0);
- assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
- 4983, 10, 1717, 10, 0);
- assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
- 126552, 270, 59215, 297, 0);
+ assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+ ROAMING_NO, 39605L, 46L, 12039, 51, 0);
+ assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+ ROAMING_NO, 81964, 214, 47177, 246, 0);
+ assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
+ ROAMING_ALL, 121569, 260, 59216, 297, 0);
}
+ // Tests a case where all of the data received by the tun0 interface is echo back into the tun0
+ // interface by the vpn app before it's sent out of the underlying interface. The VPN app should
+ // not be charged for the echoed data but it should still be charged for any extra data it sends
+ // via the underlying interface.
+ public void testMigrateTun_VpnAsLoopback() {
+ final int tunUid = 10030;
+ final String tunIface = "tun0";
+ final String underlyingIface = "wlan0";
+ NetworkStats delta = new NetworkStats(TEST_START, 9)
+ // 2 different apps sent/receive data via tun0.
+ .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50000L, 25L,
+ 100000L, 50L, 0L)
+ .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 500L, 2L,
+ 200L, 5L, 0L)
+ // VPN package resends data through the tunnel (with exaggerated overhead)
+ .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 240000,
+ 100L, 120000L, 60L, 0L)
+ // 1 app already has some traffic on the underlying interface, the other doesn't yet
+ .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1000L,
+ 10L, 2000L, 20L, 0L)
+ // Traffic through the underlying interface via the vpn app.
+ // This test should redistribute this data correctly.
+ .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 75500L, 37L, 130000L, 70L, 0L);
+
+ assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
+ assertEquals(9, delta.size());
+
+ // tunIface entries should not be changed.
+ assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 50000L, 25L, 100000L, 50L, 0L);
+ assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 500L, 2L, 200L, 5L, 0L);
+ assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 240000L, 100L, 120000L, 60L, 0L);
+
+ // Existing underlying Iface entries are updated
+ assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, 51000L, 35L, 102000L, 70L, 0L);
+
+ // VPN underlying Iface entries are updated
+ assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, 25000L, 10L, 29800L, 15L, 0L);
+
+ // New entries are added for new application's underlying Iface traffic
+ assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, 500L, 2L, 200L, 5L, 0L);
+
+ // New entries are added for debug purpose
+ assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+ ROAMING_NO, 50000L, 25L, 100000L, 50L, 0L);
+ assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
+ ROAMING_NO, 500, 2L, 200L, 5L, 0L);
+ assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
+ ROAMING_ALL, 50500L, 27L, 100200L, 55, 0);
+ }
+
private static void assertContains(NetworkStats stats, String iface, int uid, int set,
- int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
- long operations) {
- int index = stats.findIndex(iface, uid, set, tag, roaming);
+ int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
+ long txPackets, long operations) {
+ int index = stats.findIndex(iface, uid, set, tag, metered, roaming);
assertTrue(index != -1);
- assertValues(stats, index, iface, uid, set, tag, roaming,
+ assertValues(stats, index, iface, uid, set, tag, metered, roaming,
rxBytes, rxPackets, txBytes, txPackets, operations);
}
private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
- int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
- long operations) {
+ int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
+ long txPackets, long operations) {
final NetworkStats.Entry entry = stats.getValues(index, null);
- assertValues(entry, iface, uid, set, tag, roaming);
+ assertValues(entry, iface, uid, set, tag, metered, roaming);
assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations);
}
private static void assertValues(
- NetworkStats.Entry entry, String iface, int uid, int set, int tag, int roaming) {
+ NetworkStats.Entry entry, String iface, int uid, int set, int tag, int metered,
+ int roaming) {
assertEquals(iface, entry.iface);
assertEquals(uid, entry.uid);
assertEquals(set, entry.set);
assertEquals(tag, entry.tag);
+ assertEquals(metered, entry.metered);
assertEquals(roaming, entry.roaming);
}
diff --git a/core/tests/coretests/src/android/util/TokenBucketTest.java b/core/tests/coretests/src/android/util/TokenBucketTest.java
new file mode 100644
index 0000000..f7ac20c
--- /dev/null
+++ b/core/tests/coretests/src/android/util/TokenBucketTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 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.util;
+
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+import junit.framework.TestCase;
+
+public class TokenBucketTest extends TestCase {
+
+ static final int FILL_DELTA_VERY_SHORT = 1;
+ static final int FILL_DELTA_VERY_LONG = Integer.MAX_VALUE;
+
+ public void testArgumentValidation() {
+ assertThrow(() -> new TokenBucket(0, 1, 1));
+ assertThrow(() -> new TokenBucket(1, 0, 1));
+ assertThrow(() -> new TokenBucket(1, 1, 0));
+ assertThrow(() -> new TokenBucket(0, 1));
+ assertThrow(() -> new TokenBucket(1, 0));
+ assertThrow(() -> new TokenBucket(-1, 1, 1));
+ assertThrow(() -> new TokenBucket(1, -1, 1));
+ assertThrow(() -> new TokenBucket(1, 1, -1));
+ assertThrow(() -> new TokenBucket(-1, 1));
+ assertThrow(() -> new TokenBucket(1, -1));
+
+ new TokenBucket(1000, 100, 0);
+ new TokenBucket(1000, 100, 10);
+ new TokenBucket(5000, 50);
+ new TokenBucket(5000, 1);
+ }
+
+ public void testInitialCapacity() {
+ drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1), 1);
+ drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10), 10);
+ drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1000), 1000);
+
+ drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 0), 0);
+ drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 3), 3);
+ drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 10), 10);
+
+ drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 100), 10);
+
+ drain(new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50), 50);
+ drain(new TokenBucket((int)DateUtils.HOUR_IN_MILLIS, 10), 10);
+ drain(new TokenBucket((int)DateUtils.DAY_IN_MILLIS, 200), 200);
+ }
+
+ public void testReset() {
+ TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_LONG, 100, 10);
+ drain(tb, 10);
+
+ tb.reset(50);
+ drain(tb, 50);
+
+ tb.reset(50);
+ getOneByOne(tb, 10);
+ assertTrue(tb.has());
+
+ tb.reset(30);
+ drain(tb, 30);
+ }
+
+ public void testFill() throws Exception {
+ int delta = 50;
+ TokenBucket tb = new TokenBucket(delta, 10, 0);
+
+ assertEmpty(tb);
+
+ Thread.sleep(3 * delta / 2);
+
+ assertTrue(tb.has());
+ }
+
+ public void testRefill() throws Exception {
+ TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_SHORT, 10, 10);
+
+ assertEquals(5, tb.get(5));
+ assertEquals(5, tb.get(5));
+
+ while (tb.available() < 10) {
+ Thread.sleep(2);
+ }
+
+ assertEquals(10, tb.get(10));
+
+ while (tb.available() < 10) {
+ Thread.sleep(2);
+ }
+
+ assertEquals(10, tb.get(100));
+ }
+
+ public void testAverage() throws Exception {
+ final int delta = 3;
+ final int want = 60;
+
+ long start = SystemClock.elapsedRealtime();
+ TokenBucket tb = new TokenBucket(delta, 20, 0);
+
+ for (int i = 0; i < want; i++) {
+ while (!tb.has()) {
+ Thread.sleep(5 * delta);
+ }
+ tb.get();
+ }
+
+ assertDuration(want * delta, SystemClock.elapsedRealtime() - start);
+ }
+
+ public void testBurst() throws Exception {
+ final int delta = 2;
+ final int capacity = 20;
+ final int want = 100;
+
+ long start = SystemClock.elapsedRealtime();
+ TokenBucket tb = new TokenBucket(delta, capacity, 0);
+
+ int total = 0;
+ while (total < want) {
+ while (!tb.has()) {
+ Thread.sleep(capacity * delta - 2);
+ }
+ total += tb.get(tb.available());
+ }
+
+ assertDuration(total * delta, SystemClock.elapsedRealtime() - start);
+ }
+
+ static void getOneByOne(TokenBucket tb, int n) {
+ while (n > 0) {
+ assertTrue(tb.has());
+ assertTrue(tb.available() >= n);
+ assertTrue(tb.get());
+ assertTrue(tb.available() >= n - 1);
+ n--;
+ }
+ }
+
+ void assertEmpty(TokenBucket tb) {
+ assertFalse(tb.has());
+ assertEquals(0, tb.available());
+ assertFalse(tb.get());
+ }
+
+ void drain(TokenBucket tb, int n) {
+ getOneByOne(tb, n);
+ assertEmpty(tb);
+ }
+
+ void assertDuration(long expected, long elapsed) {
+ String msg = String.format(
+ "expected elapsed time at least %d ms, but was %d ms", expected, elapsed);
+ elapsed += 1; // one millisecond extra guard
+ assertTrue(msg, elapsed >= expected);
+ }
+
+ void assertThrow(Fn fn) {
+ try {
+ fn.call();
+ fail("expected n exception to be thrown.");
+ } catch (Throwable t) {}
+ }
+
+ interface Fn { void call(); }
+}
diff --git a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
index 327f3fd..7f13abc 100644
--- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -16,6 +16,7 @@
package com.android.internal.net;
+import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
@@ -101,12 +102,14 @@
final NetworkStats stats = mFactory.readNetworkStatsDetail();
assertEquals(70, stats.size());
- assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L, 676L);
+ assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L,
+ 676L);
assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L);
}
public void testNetworkStatsSingle() throws Exception {
- stageFile(R.raw.xt_qtaguid_iface_typical, new File(mTestProc, "net/xt_qtaguid/iface_stat_all"));
+ stageFile(R.raw.xt_qtaguid_iface_typical,
+ new File(mTestProc, "net/xt_qtaguid/iface_stat_all"));
final NetworkStats stats = mFactory.readNetworkStatsSummaryDev();
assertEquals(6, stats.size());
@@ -122,7 +125,8 @@
final NetworkStats stats = mFactory.readNetworkStatsSummaryXt();
assertEquals(3, stats.size());
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L);
- assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L, 2468L);
+ assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L,
+ 2468L);
assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L);
}
@@ -157,7 +161,7 @@
private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
int tag, long rxBytes, long txBytes) {
- final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO);
+ final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO);
final NetworkStats.Entry entry = stats.getValues(i, null);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
@@ -165,7 +169,7 @@
private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- final int i = stats.findIndex(iface, uid, set, tag, ROAMING_NO);
+ final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO);
final NetworkStats.Entry entry = stats.getValues(i, null);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index 6d1ebb4..981be11 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -14,6 +14,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
+ frameworks-base-testutils \
mockito-target
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java b/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java
similarity index 97%
rename from services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
rename to core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java
index 05de0a5..f2be109 100644
--- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.util;
+package com.android.internal.util.test;
import android.content.ContentResolver;
import android.database.ContentObserver;
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 0011002..7bab189 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -21,10 +21,11 @@
# This contains the junit.framework classes that were in Android API level 25.
include $(CLEAR_VARS)
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_STATIC_JAVA_LIBRARIES := core-junit-static
-
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE := legacy-test
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+LOCAL_STATIC_JAVA_LIBRARIES := core-junit-static
include $(BUILD_JAVA_LIBRARY)
@@ -34,7 +35,7 @@
# This contains the android.test.PerformanceTestCase class only
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ../core/java/android/test/PerformanceTestCase.java
+LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
LOCAL_MODULE := legacy-performance-test-hostdex
include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
diff --git a/core/java/android/test/AndroidTestCase.java b/legacy-test/src/android/test/AndroidTestCase.java
similarity index 100%
rename from core/java/android/test/AndroidTestCase.java
rename to legacy-test/src/android/test/AndroidTestCase.java
diff --git a/core/java/android/test/FlakyTest.java b/legacy-test/src/android/test/FlakyTest.java
similarity index 100%
rename from core/java/android/test/FlakyTest.java
rename to legacy-test/src/android/test/FlakyTest.java
diff --git a/core/java/android/test/InstrumentationTestCase.java b/legacy-test/src/android/test/InstrumentationTestCase.java
similarity index 100%
rename from core/java/android/test/InstrumentationTestCase.java
rename to legacy-test/src/android/test/InstrumentationTestCase.java
diff --git a/core/java/android/test/InstrumentationTestSuite.java b/legacy-test/src/android/test/InstrumentationTestSuite.java
similarity index 100%
rename from core/java/android/test/InstrumentationTestSuite.java
rename to legacy-test/src/android/test/InstrumentationTestSuite.java
diff --git a/core/java/android/test/PerformanceTestCase.java b/legacy-test/src/android/test/PerformanceTestCase.java
similarity index 100%
rename from core/java/android/test/PerformanceTestCase.java
rename to legacy-test/src/android/test/PerformanceTestCase.java
diff --git a/core/java/android/test/RepetitiveTest.java b/legacy-test/src/android/test/RepetitiveTest.java
similarity index 100%
rename from core/java/android/test/RepetitiveTest.java
rename to legacy-test/src/android/test/RepetitiveTest.java
diff --git a/core/java/android/test/UiThreadTest.java b/legacy-test/src/android/test/UiThreadTest.java
similarity index 100%
rename from core/java/android/test/UiThreadTest.java
rename to legacy-test/src/android/test/UiThreadTest.java
diff --git a/core/java/android/test/package.html b/legacy-test/src/android/test/package.html
similarity index 100%
rename from core/java/android/test/package.html
rename to legacy-test/src/android/test/package.html
diff --git a/core/java/android/test/suitebuilder/annotation/LargeTest.java b/legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java
similarity index 100%
rename from core/java/android/test/suitebuilder/annotation/LargeTest.java
rename to legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java
diff --git a/core/java/android/test/suitebuilder/annotation/MediumTest.java b/legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java
similarity index 100%
rename from core/java/android/test/suitebuilder/annotation/MediumTest.java
rename to legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java
diff --git a/core/java/android/test/suitebuilder/annotation/SmallTest.java b/legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java
similarity index 100%
rename from core/java/android/test/suitebuilder/annotation/SmallTest.java
rename to legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java
diff --git a/core/java/android/test/suitebuilder/annotation/Smoke.java b/legacy-test/src/android/test/suitebuilder/annotation/Smoke.java
similarity index 100%
rename from core/java/android/test/suitebuilder/annotation/Smoke.java
rename to legacy-test/src/android/test/suitebuilder/annotation/Smoke.java
diff --git a/core/java/android/test/suitebuilder/annotation/Suppress.java b/legacy-test/src/android/test/suitebuilder/annotation/Suppress.java
similarity index 100%
rename from core/java/android/test/suitebuilder/annotation/Suppress.java
rename to legacy-test/src/android/test/suitebuilder/annotation/Suppress.java
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index b58c87a..bb8eb2c 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -115,6 +115,7 @@
myWebView.clearCache(true);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
+ webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
mWebViewClient = new MyWebViewClient();
myWebView.setWebViewClient(mWebViewClient);
myWebView.setWebChromeClient(new MyWebChromeClient());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 70642ed..f0bbac8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -392,7 +392,7 @@
RecentsActivityLaunchState launchState = config.getLaunchState();
if (!loadPlan.hasTasks()) {
loader.preloadTasks(loadPlan, launchState.launchedToTaskId,
- !launchState.launchedFromHome);
+ !launchState.launchedFromHome && !launchState.launchedViaDockGesture);
}
RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
@@ -519,12 +519,14 @@
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
- // Workaround for b/22542869, if the RecentsActivity is started again, but without going
- // through SystemUI, we need to reset the config launch flags to ensure that we do not
- // wait on the system to send a signal that was never queued.
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- launchState.reset();
+ if (!isChangingConfigurations()) {
+ // Workaround for b/22542869, if the RecentsActivity is started again, but without going
+ // through SystemUI, we need to reset the config launch flags to ensure that we do not
+ // wait on the system to send a signal that was never queued.
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ launchState.reset();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 30edd9f..090c744 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1813,11 +1813,14 @@
private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
final String iface = newLp.getInterfaceName();
final int mtu = newLp.getMtu();
+ if (oldLp == null && mtu == 0) {
+ // Silently ignore unset MTU value.
+ return;
+ }
if (oldLp != null && newLp.isIdenticalMtu(oldLp)) {
if (VDBG) log("identical MTU - not setting");
return;
}
-
if (LinkProperties.isValidMtu(mtu, newLp.hasGlobalIPv6Address()) == false) {
if (mtu != 0) loge("Unexpected mtu value: " + mtu + ", " + iface);
return;
@@ -2263,11 +2266,19 @@
synchronized (mNetworkForNetId) {
nai = mNetworkForNetId.get(netId);
}
- // If captive portal status has changed, update capabilities.
+ // If captive portal status has changed, update capabilities or disconnect.
if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
final int oldScore = nai.getCurrentScore();
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
+ if (nai.lastCaptivePortalDetected &&
+ Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
+ if (DBG) log("Avoiding captive portal network: " + nai.name());
+ nai.asyncChannel.sendMessage(
+ NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
+ teardownUnneededNetwork(nai);
+ break;
+ }
updateCapabilities(oldScore, nai, nai.networkCapabilities);
}
if (!visible) {
@@ -2288,6 +2299,12 @@
return true;
}
+ private int getCaptivePortalMode() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.CAPTIVE_PORTAL_MODE,
+ Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+ }
+
private boolean maybeHandleNetworkAgentInfoMessage(Message msg) {
switch (msg.what) {
default:
@@ -2597,14 +2614,28 @@
"request NetworkCapabilities", ConnectivityManager.CALLBACK_CAP_CHANGED);
}
+ private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
+ if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
+ nri.request.requestId) == null) {
+ handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL);
+ }
+ }
+
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
final NetworkRequestInfo nri = getNriForAppRequest(
request, callingUid, "release NetworkRequest");
- if (nri == null) return;
+ if (nri != null) {
+ handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED);
+ }
+ }
- if (VDBG || (DBG && nri.request.isRequest())) log("releasing " + request);
+ private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) {
+ final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
+ if (VDBG || (DBG && nri.request.isRequest())) {
+ log("releasing " + nri.request + " (" + logCallbackType + ")");
+ }
nri.unlinkDeathRecipient();
- mNetworkRequests.remove(request);
+ mNetworkRequests.remove(nri.request);
synchronized (mUidToNetworkRequestCount) {
int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
if (requests < 1) {
@@ -2698,7 +2729,7 @@
}
}
}
- callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
+ callCallbackForRequest(nri, null, whichCallback, 0);
}
@Override
@@ -2935,6 +2966,11 @@
handleRegisterNetworkRequestWithIntent(msg);
break;
}
+ case EVENT_TIMEOUT_NETWORK_REQUEST: {
+ NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj;
+ handleTimedOutNetworkRequest(nri);
+ break;
+ }
case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: {
handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1);
break;
@@ -5315,6 +5351,7 @@
// notify only this one new request of the current state
protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) {
int notifyType = ConnectivityManager.CALLBACK_AVAILABLE;
+ mHandler.removeMessages(EVENT_TIMEOUT_NETWORK_REQUEST, nri);
if (nri.mPendingIntent == null) {
callCallbackForRequest(nri, nai, notifyType, 0);
} else {
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 4c9ea58..27e4aa4 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -36,10 +36,12 @@
import android.net.wifi.WifiConfiguration;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.R;
@@ -52,11 +54,11 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+import java.util.function.Consumer;
/**
* Backing service for {@link android.net.NetworkScoreManager}.
@@ -68,7 +70,8 @@
private final Context mContext;
private final NetworkScorerAppManager mNetworkScorerAppManager;
- private final Map<Integer, INetworkScoreCache> mScoreCaches;
+ @GuardedBy("mScoreCaches")
+ private final Map<Integer, RemoteCallbackList<INetworkScoreCache>> mScoreCaches;
/** Lock used to update mPackageMonitor when scorer package changes occur. */
private final Object mPackageMonitorLock = new Object[0];
@@ -166,7 +169,7 @@
NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
mContext = context;
mNetworkScorerAppManager = networkScoreAppManager;
- mScoreCaches = new HashMap<>();
+ mScoreCaches = new ArrayMap<>();
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
// TODO: Need to update when we support per-user scorers. http://b/23422763
mContext.registerReceiverAsUser(
@@ -276,7 +279,7 @@
}
// Separate networks by type.
- Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>();
+ Map<Integer, List<ScoredNetwork>> networksByType = new ArrayMap<>();
for (ScoredNetwork network : networks) {
List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
if (networkList == null) {
@@ -287,19 +290,32 @@
}
// Pass the scores of each type down to the appropriate network scorer.
- for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
- INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey());
- if (scoreCache != null) {
- try {
- scoreCache.updateScores(entry.getValue());
- } catch (RemoteException e) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
+ for (final Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
+ final RemoteCallbackList<INetworkScoreCache> callbackList;
+ final boolean isEmpty;
+ synchronized (mScoreCaches) {
+ callbackList = mScoreCaches.get(entry.getKey());
+ isEmpty = callbackList == null || callbackList.getRegisteredCallbackCount() == 0;
+ }
+ if (isEmpty) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
+ }
+ continue;
+ }
+
+ sendCallback(new Consumer<INetworkScoreCache>() {
+ @Override
+ public void accept(INetworkScoreCache networkScoreCache) {
+ try {
+ networkScoreCache.updateScores(entry.getValue());
+ } catch (RemoteException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
+ }
}
}
- } else if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
- }
+ }, Collections.singleton(callbackList));
}
return true;
@@ -394,28 +410,54 @@
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
private void clearInternal() {
- Set<INetworkScoreCache> cachesToClear = getScoreCaches();
+ sendCallback(new Consumer<INetworkScoreCache>() {
+ @Override
+ public void accept(INetworkScoreCache networkScoreCache) {
+ try {
+ networkScoreCache.clearScores();
+ } catch (RemoteException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Unable to clear scores", e);
+ }
+ }
+ }
+ }, getScoreCacheLists());
+ }
- for (INetworkScoreCache scoreCache : cachesToClear) {
- try {
- scoreCache.clearScores();
- } catch (RemoteException e) {
+ @Override
+ public void registerNetworkScoreCache(int networkType,
+ INetworkScoreCache scoreCache,
+ int filterType) {
+ mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+ synchronized (mScoreCaches) {
+ RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
+ if (callbackList == null) {
+ callbackList = new RemoteCallbackList<>();
+ mScoreCaches.put(networkType, callbackList);
+ }
+ if (!callbackList.register(scoreCache, filterType)) {
+ if (callbackList.getRegisteredCallbackCount() == 0) {
+ mScoreCaches.remove(networkType);
+ }
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Unable to clear scores", e);
+ Log.v(TAG, "Unable to register NetworkScoreCache for type " + networkType);
}
}
}
}
@Override
- public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+ public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
synchronized (mScoreCaches) {
- if (mScoreCaches.containsKey(networkType)) {
- throw new IllegalArgumentException(
- "Score cache already registered for type " + networkType);
+ RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
+ if (callbackList == null || !callbackList.unregister(scoreCache)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Unable to unregister NetworkScoreCache for type " + networkType);
+ }
+ } else if (callbackList.getRegisteredCallbackCount() == 0) {
+ mScoreCaches.remove(networkType);
}
- mScoreCaches.put(networkType, scoreCache);
}
}
@@ -430,7 +472,7 @@
}
@Override
- protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ protected void dump(final FileDescriptor fd, final PrintWriter writer, final String[] args) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
if (currentScorer == null) {
@@ -439,13 +481,17 @@
}
writer.println("Current scorer: " + currentScorer.mPackageName);
- for (INetworkScoreCache scoreCache : getScoreCaches()) {
- try {
- TransferPipe.dumpAsync(scoreCache.asBinder(), fd, args);
- } catch (IOException | RemoteException e) {
- writer.println("Failed to dump score cache: " + e);
+ sendCallback(new Consumer<INetworkScoreCache>() {
+ @Override
+ public void accept(INetworkScoreCache networkScoreCache) {
+ try {
+ TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ writer.println("Failed to dump score cache: " + e);
+ }
}
- }
+ }, getScoreCacheLists());
+
if (mServiceConnection != null) {
mServiceConnection.dump(fd, writer, args);
} else {
@@ -455,14 +501,30 @@
}
/**
- * Returns a set of all score caches that are currently active.
+ * Returns a {@link Collection} of all {@link RemoteCallbackList}s that are currently active.
*
* <p>May be used to perform an action on all score caches without potentially strange behavior
* if a new scorer is registered during that action's execution.
*/
- private Set<INetworkScoreCache> getScoreCaches() {
+ private Collection<RemoteCallbackList<INetworkScoreCache>> getScoreCacheLists() {
synchronized (mScoreCaches) {
- return new HashSet<>(mScoreCaches.values());
+ return new ArrayList<>(mScoreCaches.values());
+ }
+ }
+
+ private void sendCallback(Consumer<INetworkScoreCache> consumer,
+ Collection<RemoteCallbackList<INetworkScoreCache>> remoteCallbackLists) {
+ for (RemoteCallbackList<INetworkScoreCache> callbackList : remoteCallbackLists) {
+ synchronized (callbackList) { // Ensure only one active broadcast per RemoteCallbackList
+ final int count = callbackList.beginBroadcast();
+ try {
+ for (int i = 0; i < count; i++) {
+ consumer.accept(callbackList.getBroadcastItem(i));
+ }
+ } finally {
+ callbackList.finishBroadcast();
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index f1ef947..f1d01e0 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -48,6 +48,10 @@
final IpConnectivityLog log = new IpConnectivityLog();
log.events = toProto(events);
log.droppedEvents = dropped;
+ if ((log.events.length > 0) || (dropped > 0)) {
+ // Only write version number if log has some information at all.
+ log.version = IpConnectivityMetrics.VERSION;
+ }
return IpConnectivityLog.toByteArray(log);
}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 28e724c..be68173 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -19,19 +19,25 @@
import android.content.Context;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
+import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
import android.os.IBinder;
import android.os.Parcelable;
+import android.provider.Settings;
import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.Base64;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.TokenBucket;
import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.function.ToIntFunction;
import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
@@ -40,10 +46,21 @@
private static final String TAG = IpConnectivityMetrics.class.getSimpleName();
private static final boolean DBG = false;
+ // The logical version numbers of ipconnectivity.proto, corresponding to the
+ // "version" field of IpConnectivityLog.
+ private static final int NYC = 0;
+ private static final int NYC_MR1 = 1;
+ private static final int NYC_MR2 = 2;
+ public static final int VERSION = NYC_MR2;
+
private static final String SERVICE_NAME = IpConnectivityLog.SERVICE_NAME;
// Default size of the event buffer. Once the buffer is full, incoming events are dropped.
private static final int DEFAULT_BUFFER_SIZE = 2000;
+ // Maximum size of the event buffer.
+ private static final int MAXIMUM_BUFFER_SIZE = DEFAULT_BUFFER_SIZE * 10;
+
+ private static final int ERROR_RATE_LIMITED = -1;
// Lock ensuring that concurrent manipulations of the event buffer are correct.
// There are three concurrent operations to synchronize:
@@ -62,10 +79,19 @@
private int mDropped;
@GuardedBy("mLock")
private int mCapacity;
+ @GuardedBy("mLock")
+ private final ArrayMap<Class<?>, TokenBucket> mBuckets = makeRateLimitingBuckets();
+
+ private final ToIntFunction<Context> mCapacityGetter;
+
+ public IpConnectivityMetrics(Context ctx, ToIntFunction<Context> capacityGetter) {
+ super(ctx);
+ mCapacityGetter = capacityGetter;
+ initBuffer();
+ }
public IpConnectivityMetrics(Context ctx) {
- super(ctx);
- initBuffer();
+ this(ctx, READ_BUFFER_SIZE);
}
@Override
@@ -86,7 +112,7 @@
@VisibleForTesting
public int bufferCapacity() {
- return DEFAULT_BUFFER_SIZE; // TODO: read from config
+ return mCapacityGetter.applyAsInt(getContext());
}
private void initBuffer() {
@@ -104,6 +130,10 @@
if (event == null) {
return left;
}
+ if (isRateLimited(event)) {
+ // Do not count as a dropped event. TODO: consider adding separate counter
+ return ERROR_RATE_LIMITED;
+ }
if (left == 0) {
mDropped++;
return 0;
@@ -113,6 +143,11 @@
}
}
+ private boolean isRateLimited(ConnectivityMetricsEvent event) {
+ TokenBucket tb = mBuckets.get(event.data.getClass());
+ return (tb != null) && !tb.get();
+ }
+
private String flushEncodedOutput() {
final ArrayList<ConnectivityMetricsEvent> events;
final int dropped;
@@ -186,6 +221,7 @@
static final String CMD_FLUSH = "flush";
static final String CMD_LIST = "list";
static final String CMD_STATS = "stats";
+ static final String CMD_DUMPSYS = "-a"; // dumpsys.cpp dumps services with "-a" as arguments
static final String CMD_DEFAULT = CMD_STATS;
@Override
@@ -203,6 +239,8 @@
case CMD_FLUSH:
cmdFlush(fd, pw, args);
return;
+ case CMD_DUMPSYS:
+ // Fallthrough to CMD_LIST when dumpsys.cpp dumps services states (bug reports)
case CMD_LIST:
cmdList(fd, pw, args);
return;
@@ -226,4 +264,20 @@
getContext().enforceCallingOrSelfPermission(what, "IpConnectivityMetrics");
}
};
+
+ private static final ToIntFunction<Context> READ_BUFFER_SIZE = (ctx) -> {
+ int size = Settings.Global.getInt(ctx.getContentResolver(),
+ Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
+ if (size <= 0) {
+ return DEFAULT_BUFFER_SIZE;
+ }
+ return Math.min(size, MAXIMUM_BUFFER_SIZE);
+ };
+
+ private static ArrayMap<Class<?>, TokenBucket> makeRateLimitingBuckets() {
+ ArrayMap<Class<?>, TokenBucket> map = new ArrayMap<>();
+ // one token every minute, 50 tokens max: burst of ~50 events every hour.
+ map.put(ApfProgramEvent.class, new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50));
+ return map;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 4b175d7..f8638c5 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -24,6 +24,7 @@
import android.net.metrics.DnsEvent;
import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
+import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -44,7 +45,7 @@
public static final String SERVICE_NAME = "netd_listener";
private static final String TAG = NetdEventListenerService.class.getSimpleName();
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false;
// TODO: read this constant from system property
@@ -86,7 +87,7 @@
byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount);
int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount);
mMetricsLog.log(new DnsEvent(mNetId, eventTypes, returnCodes, latenciesMs));
- maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId));
+ maybeLog("Logging %d results for netId %d", mEventCount, mNetId);
mEventCount = 0;
}
@@ -136,9 +137,9 @@
// Called concurrently by multiple binder threads.
// This method must not block or perform long-running operations.
public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
- String hostname, String[] ipAddresses, int ipAddressesCount, int uid) {
- maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)",
- netId, eventType, returnCode, latencyMs));
+ String hostname, String[] ipAddresses, int ipAddressesCount, int uid)
+ throws RemoteException {
+ maybeVerboseLog("onDnsEvent(%d, %d, %d, %dms)", netId, eventType, returnCode, latencyMs);
DnsEventBatch batch = mEventBatches.get(netId);
if (batch == null) {
@@ -151,9 +152,9 @@
@Override
// Called concurrently by multiple binder threads.
// This method must not block or perform long-running operations.
- public synchronized void onConnectEvent(int netId, int latencyMs, String ipAddr, int port,
- int uid) {
- maybeVerboseLog(String.format("onConnectEvent(%d, %d)", netId, latencyMs));
+ public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port,
+ int uid) throws RemoteException {
+ maybeVerboseLog("onConnectEvent(%d, %d, %dms)", netId, error, latencyMs);
}
public synchronized void dump(PrintWriter writer) {
@@ -166,11 +167,11 @@
pw.decreaseIndent();
}
- private static void maybeLog(String s) {
- if (DBG) Log.d(TAG, s);
+ private static void maybeLog(String s, Object... args) {
+ if (DBG) Log.d(TAG, String.format(s, args));
}
- private static void maybeVerboseLog(String s) {
- if (VDBG) Log.d(TAG, s);
+ private static void maybeVerboseLog(String s, Object... args) {
+ if (VDBG) Log.d(TAG, String.format(s, args));
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 6eb89fa..ea2cf5f 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -96,6 +96,24 @@
private static final int SOCKET_TIMEOUT_MS = 10000;
private static final int PROBE_TIMEOUT_MS = 3000;
+ static enum EvaluationResult {
+ VALIDATED(true),
+ CAPTIVE_PORTAL(false);
+ final boolean isValidated;
+ EvaluationResult(boolean isValidated) {
+ this.isValidated = isValidated;
+ }
+ }
+
+ static enum ValidationStage {
+ FIRST_VALIDATION(true),
+ REVALIDATION(false);
+ final boolean isFirstValidation;
+ ValidationStage(boolean isFirstValidation) {
+ this.isFirstValidation = isFirstValidation;
+ }
+ }
+
public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
"android.net.conn.NETWORK_CONDITIONS_MEASURED";
public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
@@ -211,8 +229,12 @@
private final NetworkRequest mDefaultRequest;
private final IpConnectivityLog mMetricsLog;
- private boolean mIsCaptivePortalCheckEnabled;
+ @VisibleForTesting
+ protected boolean mIsCaptivePortalCheckEnabled;
+
private boolean mUseHttps;
+ // The total number of captive portal detection attempts for this NetworkMonitor instance.
+ private int mValidations = 0;
// Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
private boolean mUserDoesNotWant = false;
@@ -265,7 +287,8 @@
setInitialState(mDefaultState);
mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
+ Settings.Global.CAPTIVE_PORTAL_MODE, Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT)
+ != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
mUseHttps = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
@@ -286,6 +309,10 @@
return validationLogs.readOnlyLocalLog();
}
+ private ValidationStage validationStage() {
+ return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION;
+ }
+
// DefaultState is the parent of all States. It exists only to handle CMD_* messages but
// does not entail any real state (hence no enter() or exit() routines).
private class DefaultState extends State {
@@ -362,9 +389,11 @@
private class ValidatedState extends State {
@Override
public void enter() {
- maybeLogEvaluationResult(NetworkEvent.NETWORK_VALIDATED);
+ maybeLogEvaluationResult(
+ networkEventType(validationStage(), EvaluationResult.VALIDATED));
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
+ mValidations++;
}
@Override
@@ -580,7 +609,8 @@
@Override
public void enter() {
- maybeLogEvaluationResult(NetworkEvent.NETWORK_CAPTIVE_PORTAL_FOUND);
+ maybeLogEvaluationResult(
+ networkEventType(validationStage(), EvaluationResult.CAPTIVE_PORTAL));
// Don't annoy user with sign-in notifications.
if (mDontDisplaySigninNotification) return;
// Create a CustomIntentReceiver that sends us a
@@ -600,6 +630,7 @@
// Retest for captive portal occasionally.
sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
+ mValidations++;
}
@Override
@@ -632,7 +663,10 @@
@VisibleForTesting
protected CaptivePortalProbeResult isCaptivePortal() {
- if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204);
+ if (!mIsCaptivePortalCheckEnabled) {
+ validationLog("Validation disabled.");
+ return new CaptivePortalProbeResult(204);
+ }
URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null;
@@ -672,48 +706,13 @@
long startTime = SystemClock.elapsedRealtime();
- // Pre-resolve the captive portal server host so we can log it.
- // Only do this if HttpURLConnection is about to, to avoid any potentially
- // unnecessary resolution.
- String hostToResolve = null;
+ final CaptivePortalProbeResult result;
if (pacUrl != null) {
- hostToResolve = pacUrl.getHost();
- } else if (proxyInfo != null) {
- hostToResolve = proxyInfo.getHost();
- } else {
- hostToResolve = httpUrl.getHost();
- }
-
- if (!TextUtils.isEmpty(hostToResolve)) {
- String probeName = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
- final Stopwatch dnsTimer = new Stopwatch().start();
- int dnsResult;
- long dnsLatency;
- try {
- InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(hostToResolve);
- dnsResult = ValidationProbeEvent.DNS_SUCCESS;
- dnsLatency = dnsTimer.stop();
- final StringBuffer connectInfo = new StringBuffer(", " + hostToResolve + "=");
- for (InetAddress address : addresses) {
- connectInfo.append(address.getHostAddress());
- if (address != addresses[addresses.length-1]) connectInfo.append(",");
- }
- validationLog(probeName + " OK " + dnsLatency + "ms" + connectInfo);
- } catch (UnknownHostException e) {
- dnsResult = ValidationProbeEvent.DNS_FAILURE;
- dnsLatency = dnsTimer.stop();
- validationLog(probeName + " FAIL " + dnsLatency + "ms, " + hostToResolve);
- }
- logValidationProbe(dnsLatency, ValidationProbeEvent.PROBE_DNS, dnsResult);
- }
-
- CaptivePortalProbeResult result;
- if (pacUrl != null) {
- result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC);
+ result = sendDnsAndHttpProbes(null, pacUrl, ValidationProbeEvent.PROBE_PAC);
} else if (mUseHttps) {
- result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl);
+ result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl, fallbackUrl);
} else {
- result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
+ result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_HTTP);
}
long endTime = SystemClock.elapsedRealtime();
@@ -726,8 +725,50 @@
}
/**
- * Do a URL fetch on a known server to see if we get the data we expect.
- * Returns HTTP response code.
+ * Do a DNS resolution and URL fetch on a known web server to see if we get the data we expect.
+ * @return a CaptivePortalProbeResult inferred from the HTTP response.
+ */
+ private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) {
+ // Pre-resolve the captive portal server host so we can log it.
+ // Only do this if HttpURLConnection is about to, to avoid any potentially
+ // unnecessary resolution.
+ final String host = (proxy != null) ? proxy.getHost() : url.getHost();
+ sendDnsProbe(host);
+ return sendHttpProbe(url, probeType);
+ }
+
+ /** Do a DNS resolution of the given server. */
+ private void sendDnsProbe(String host) {
+ if (TextUtils.isEmpty(host)) {
+ return;
+ }
+
+ final String name = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
+ final Stopwatch watch = new Stopwatch().start();
+ int result;
+ String connectInfo;
+ try {
+ InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(host);
+ result = ValidationProbeEvent.DNS_SUCCESS;
+ StringBuffer buffer = new StringBuffer(host).append("=");
+ for (InetAddress address : addresses) {
+ buffer.append(address.getHostAddress());
+ if (address != addresses[addresses.length-1]) buffer.append(",");
+ }
+ connectInfo = buffer.toString();
+ } catch (UnknownHostException e) {
+ result = ValidationProbeEvent.DNS_FAILURE;
+ connectInfo = host;
+ }
+ final long latency = watch.stop();
+ String resultString = (ValidationProbeEvent.DNS_SUCCESS == result) ? "OK" : "FAIL";
+ validationLog(String.format("%s %s %dms, %s", name, resultString, latency, connectInfo));
+ logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result);
+ }
+
+ /**
+ * Do a URL fetch on a known web server to see if we get the data we expect.
+ * @return a CaptivePortalProbeResult inferred from the HTTP response.
*/
@VisibleForTesting
protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) {
@@ -794,7 +835,7 @@
}
private CaptivePortalProbeResult sendParallelHttpProbes(
- URL httpsUrl, URL httpUrl, URL fallbackUrl) {
+ ProxyInfo proxy, URL httpsUrl, URL httpUrl, URL fallbackUrl) {
// Number of probes to wait for. If a probe completes with a conclusive answer
// it shortcuts the latch immediately by forcing the count to 0.
final CountDownLatch latch = new CountDownLatch(2);
@@ -814,9 +855,10 @@
@Override
public void run() {
if (mIsHttps) {
- mResult = sendHttpProbe(httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
+ mResult =
+ sendDnsAndHttpProbes(proxy, httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
} else {
- mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
+ mResult = sendDnsAndHttpProbes(proxy, httpUrl, ValidationProbeEvent.PROBE_HTTP);
}
if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
// Stop waiting immediately if https succeeds or if http finds a portal.
@@ -967,6 +1009,22 @@
mMetricsLog.log(new NetworkEvent(mNetId, evtype));
}
+ private int networkEventType(ValidationStage s, EvaluationResult r) {
+ if (s.isFirstValidation) {
+ if (r.isValidated) {
+ return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS;
+ } else {
+ return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND;
+ }
+ } else {
+ if (r.isValidated) {
+ return NetworkEvent.NETWORK_REVALIDATION_SUCCESS;
+ } else {
+ return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND;
+ }
+ }
+ }
+
private void maybeLogEvaluationResult(int evtype) {
if (mEvaluationTimer.isRunning()) {
mMetricsLog.log(new NetworkEvent(mNetId, evtype, mEvaluationTimer.stop()));
@@ -975,6 +1033,8 @@
}
private void logValidationProbe(long durationMs, int probeType, int probeResult) {
+ probeType =
+ ValidationProbeEvent.makeProbeType(probeType, validationStage().isFirstValidation);
mMetricsLog.log(new ValidationProbeEvent(mNetId, durationMs, probeType, probeResult));
}
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0beb227..6d96a10 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -71,6 +71,7 @@
import com.android.internal.util.StateMachine;
import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
+import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.net.BaseNetworkObserver;
@@ -1939,7 +1940,8 @@
private void trackNewTetherableInterface(String iface, int interfaceType) {
TetherState tetherState;
tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
- interfaceType, mNMService, mStatsService, this));
+ interfaceType, mNMService, mStatsService, this,
+ new IPv6TetheringInterfaceServices(iface, mNMService)));
mTetherStates.put(iface, tetherState);
tetherState.mStateMachine.start();
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index ede3bda..afc6247 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -27,6 +27,8 @@
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -76,6 +78,7 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.LegacyVpnInfo;
@@ -241,12 +244,14 @@
/**
* Update current state, dispaching event to listeners.
*/
- private void updateState(DetailedState detailedState, String reason) {
+ @VisibleForTesting
+ protected void updateState(DetailedState detailedState, String reason) {
if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
mNetworkInfo.setDetailedState(detailedState, reason, null);
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
+ updateAlwaysOnNotification(detailedState);
}
/**
@@ -280,7 +285,10 @@
}
mLockdown = (mAlwaysOn && lockdown);
- if (!isCurrentPreparedPackage(packageName)) {
+ if (isCurrentPreparedPackage(packageName)) {
+ updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
+ } else {
+ // Prepare this app. The notification will update as a side-effect of updateState().
prepareInternal(packageName);
}
maybeRegisterPackageChangeReceiverLocked(packageName);
@@ -682,22 +690,19 @@
}
}
- private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
- networkInfo.setIsAvailable(false);
- networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+ private void agentDisconnect(NetworkAgent networkAgent) {
if (networkAgent != null) {
+ NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
+ networkInfo.setIsAvailable(false);
+ networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
networkAgent.sendNetworkInfo(networkInfo);
}
}
- private void agentDisconnect(NetworkAgent networkAgent) {
- NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
- agentDisconnect(networkInfo, networkAgent);
- }
-
private void agentDisconnect() {
if (mNetworkInfo.isConnected()) {
- agentDisconnect(mNetworkInfo, mNetworkAgent);
+ mNetworkInfo.setIsAvailable(false);
+ updateState(DetailedState.DISCONNECTED, "agentDisconnect");
mNetworkAgent = null;
}
}
@@ -1250,6 +1255,43 @@
}
}
+ private void updateAlwaysOnNotification(DetailedState networkState) {
+ final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
+ updateAlwaysOnNotificationInternal(visible);
+ }
+
+ @VisibleForTesting
+ protected void updateAlwaysOnNotificationInternal(boolean visible) {
+ final UserHandle user = UserHandle.of(mUserHandle);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final NotificationManager notificationManager = NotificationManager.from(mContext);
+ if (!visible) {
+ notificationManager.cancelAsUser(TAG, 0, user);
+ return;
+ }
+ final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
+ final PendingIntent configIntent = PendingIntent.getActivityAsUser(
+ mContext, /* request */ 0, intent,
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
+ null, user);
+ final Notification.Builder builder = new Notification.Builder(mContext)
+ .setDefaults(0)
+ .setSmallIcon(R.drawable.vpn_connected)
+ .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(configIntent)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setPriority(Notification.PRIORITY_LOW)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setOngoing(true)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color));
+ notificationManager.notifyAsUser(TAG, 0, builder.build(), user);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private native int jniCreate(int mtu);
private native String jniGetName(int tun);
private native int jniSetAddresses(String interfaze, String addresses);
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index c2c1a8c..dec2f77 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -45,7 +45,7 @@
/**
* @hide
*/
-class IPv6TetheringInterfaceServices {
+public class IPv6TetheringInterfaceServices {
private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName();
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
private static final int RFC7421_IP_PREFIX_LENGTH = 64;
@@ -59,7 +59,7 @@
private RouterAdvertisementDaemon mRaDaemon;
private RaParams mLastRaParams;
- IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
+ public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
mIfName = ifname;
mNMService = nms;
}
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 6ca4e27..37221a9 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -94,14 +94,14 @@
public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType,
INetworkManagementService nMService, INetworkStatsService statsService,
- IControlsTethering tetherController) {
+ IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
super(ifaceName, looper);
mNMService = nMService;
mStatsService = statsService;
mTetherController = tetherController;
mIfaceName = ifaceName;
mInterfaceType = interfaceType;
- mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService);
+ mIPv6TetherSvc = ipv6Svc;
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
mInitialState = new InitialState();
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index 959a823..c48f430 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -91,6 +91,19 @@
}
}
+ /** @return whether any {@link NetworkIdentity} in this set is considered metered. */
+ public boolean isAnyMemberMetered() {
+ if (isEmpty()) {
+ return false;
+ }
+ for (NetworkIdentity ident : this) {
+ if (ident.getMetered()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** @return whether any {@link NetworkIdentity} in this set is considered roaming. */
public boolean isAnyMemberRoaming() {
if (isEmpty()) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 673dd8f..c45b416 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -17,6 +17,8 @@
package com.android.server.net;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
import static android.net.NetworkStats.SET_ALL;
@@ -242,6 +244,7 @@
entry.uid = key.uid;
entry.set = key.set;
entry.tag = key.tag;
+ entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO;
entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO;
entry.rxBytes = historyEntry.rxBytes;
entry.rxPackets = historyEntry.rxPackets;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index bff68d8..f00065f 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -34,7 +34,7 @@
import java.util.Arrays;
-public final class Installer extends SystemService {
+public class Installer extends SystemService {
private static final String TAG = "Installer";
/* ***************************************************************************
@@ -58,25 +58,33 @@
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
+ private final boolean mIsolated;
+
+ // TODO: reconnect if installd restarts
private final InstallerConnection mInstaller;
private final IInstalld mInstalld;
private volatile Object mWarnIfHeld;
public Installer(Context context) {
- super(context);
- mInstaller = new InstallerConnection();
- // TODO: reconnect if installd restarts
- mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
+ this(context, false);
}
- // Package-private installer that accepts a custom InstallerConnection. Used for
- // OtaDexoptService.
- Installer(Context context, InstallerConnection connection) {
+ /**
+ * @param isolated indicates if this object should <em>not</em> connect to
+ * the real {@code installd}. All remote calls will be ignored
+ * unless you extend this class and intercept them.
+ */
+ public Installer(Context context, boolean isolated) {
super(context);
- mInstaller = connection;
- // TODO: reconnect if installd restarts
- mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
+ mIsolated = isolated;
+ if (isolated) {
+ mInstaller = null;
+ mInstalld = null;
+ } else {
+ mInstaller = new InstallerConnection();
+ mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
+ }
}
/**
@@ -84,26 +92,41 @@
* the given object.
*/
public void setWarnIfHeld(Object warnIfHeld) {
- mInstaller.setWarnIfHeld(warnIfHeld);
+ if (mInstaller != null) {
+ mInstaller.setWarnIfHeld(warnIfHeld);
+ }
mWarnIfHeld = warnIfHeld;
}
@Override
public void onStart() {
- Slog.i(TAG, "Waiting for installd to be ready.");
- mInstaller.waitForConnection();
+ if (mInstaller != null) {
+ Slog.i(TAG, "Waiting for installd to be ready.");
+ mInstaller.waitForConnection();
+ }
}
- private void checkLock() {
+ /**
+ * Do several pre-flight checks before making a remote call.
+ *
+ * @return if the remote call should continue.
+ */
+ private boolean checkBeforeRemote() {
if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
}
+ if (mIsolated) {
+ Slog.i(TAG, "Ignoring request because this installer is isolated");
+ return false;
+ } else {
+ return true;
+ }
}
public void createAppData(String uuid, String packageName, int userId, int flags, int appId,
String seInfo, int targetSdkVersion) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
targetSdkVersion);
@@ -114,7 +137,7 @@
public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId,
String seInfo) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
} catch (RemoteException | ServiceSpecificException e) {
@@ -124,7 +147,7 @@
public void migrateAppData(String uuid, String packageName, int userId, int flags)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.migrateAppData(uuid, packageName, userId, flags);
} catch (RemoteException | ServiceSpecificException e) {
@@ -134,7 +157,7 @@
public void clearAppData(String uuid, String packageName, int userId, int flags,
long ceDataInode) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
} catch (RemoteException | ServiceSpecificException e) {
@@ -144,7 +167,7 @@
public void destroyAppData(String uuid, String packageName, int userId, int flags,
long ceDataInode) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
} catch (RemoteException | ServiceSpecificException e) {
@@ -155,7 +178,7 @@
public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
String dataAppName, int appId, String seInfo, int targetSdkVersion)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
targetSdkVersion);
@@ -166,6 +189,7 @@
public void getAppSize(String uuid, String pkgname, int userid, int flags, long ceDataInode,
String codePath, PackageStats stats) throws InstallerException {
+ if (!checkBeforeRemote()) return;
final String[] res = mInstaller.execute("get_app_size", uuid, pkgname, userid, flags,
ceDataInode, codePath);
try {
@@ -179,7 +203,7 @@
public long getAppDataInode(String uuid, String packageName, int userId, int flags)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return -1;
try {
return mInstalld.getAppDataInode(uuid, packageName, userId, flags);
} catch (RemoteException | ServiceSpecificException e) {
@@ -187,25 +211,18 @@
}
}
- public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
- int dexFlags, String compilerFilter, String volumeUuid, String sharedLibraries)
- throws InstallerException {
- assertValidInstructionSet(instructionSet);
- mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
- compilerFilter, volumeUuid, sharedLibraries);
- }
-
- public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+ public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
- String compilerFilter, String volumeUuid, String sharedLibraries)
+ String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries)
throws InstallerException {
assertValidInstructionSet(instructionSet);
+ if (!checkBeforeRemote()) return;
mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
outputPath, dexFlags, compilerFilter, volumeUuid, sharedLibraries);
}
public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return false;
try {
return mInstalld.mergeProfiles(uid, packageName);
} catch (RemoteException | ServiceSpecificException e) {
@@ -215,7 +232,7 @@
public boolean dumpProfiles(int uid, String packageName, String codePaths)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return false;
try {
return mInstalld.dumpProfiles(uid, packageName, codePaths);
} catch (RemoteException | ServiceSpecificException e) {
@@ -225,7 +242,7 @@
public void idmap(String targetApkPath, String overlayApkPath, int uid)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.idmap(targetApkPath, overlayApkPath, uid);
} catch (RemoteException | ServiceSpecificException e) {
@@ -235,7 +252,7 @@
public void rmdex(String codePath, String instructionSet) throws InstallerException {
assertValidInstructionSet(instructionSet);
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.rmdex(codePath, instructionSet);
} catch (RemoteException | ServiceSpecificException e) {
@@ -244,7 +261,7 @@
}
public void rmPackageDir(String packageDir) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.rmPackageDir(packageDir);
} catch (RemoteException | ServiceSpecificException e) {
@@ -253,7 +270,7 @@
}
public void clearAppProfiles(String packageName) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.clearAppProfiles(packageName);
} catch (RemoteException | ServiceSpecificException e) {
@@ -262,7 +279,7 @@
}
public void destroyAppProfiles(String packageName) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.destroyAppProfiles(packageName);
} catch (RemoteException | ServiceSpecificException e) {
@@ -272,7 +289,7 @@
public void createUserData(String uuid, int userId, int userSerial, int flags)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.createUserData(uuid, userId, userSerial, flags);
} catch (RemoteException | ServiceSpecificException e) {
@@ -281,7 +298,7 @@
}
public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.destroyUserData(uuid, userId, flags);
} catch (RemoteException | ServiceSpecificException e) {
@@ -291,7 +308,7 @@
public void markBootComplete(String instructionSet) throws InstallerException {
assertValidInstructionSet(instructionSet);
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.markBootComplete(instructionSet);
} catch (RemoteException | ServiceSpecificException e) {
@@ -300,7 +317,7 @@
}
public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.freeCache(uuid, freeStorageSize);
} catch (RemoteException | ServiceSpecificException e) {
@@ -315,7 +332,7 @@
*/
public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
int userId) throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
} catch (RemoteException | ServiceSpecificException e) {
@@ -325,7 +342,7 @@
public void createOatDir(String oatDir, String dexInstructionSet)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.createOatDir(oatDir, dexInstructionSet);
} catch (RemoteException | ServiceSpecificException e) {
@@ -335,7 +352,7 @@
public void linkFile(String relativePath, String fromBase, String toBase)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.linkFile(relativePath, fromBase, toBase);
} catch (RemoteException | ServiceSpecificException e) {
@@ -345,7 +362,7 @@
public void moveAb(String apkPath, String instructionSet, String outputPath)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.moveAb(apkPath, instructionSet, outputPath);
} catch (RemoteException | ServiceSpecificException e) {
@@ -355,7 +372,7 @@
public void deleteOdex(String apkPath, String instructionSet, String outputPath)
throws InstallerException {
- checkLock();
+ if (!checkBeforeRemote()) return;
try {
mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
} catch (RemoteException | ServiceSpecificException e) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 689917c..c0ae272 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -21,6 +21,7 @@
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.IOtaDexopt;
import android.content.pm.PackageParser;
@@ -29,15 +30,17 @@
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.storage.StorageManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.os.InstallerConnection;
import com.android.internal.os.InstallerConnection.InstallerException;
import java.io.File;
import java.io.FileDescriptor;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -276,9 +279,27 @@
*/
private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg,
int compilationReason) {
- // Use our custom connection that just collects the commands.
- RecordingInstallerConnection collectingConnection = new RecordingInstallerConnection();
- Installer collectingInstaller = new Installer(mContext, collectingConnection);
+ // Intercept and collect dexopt requests
+ final List<String> commands = new ArrayList<String>();
+ final Installer collectingInstaller = new Installer(mContext, true) {
+ @Override
+ public void dexopt(String apkPath, int uid, @Nullable String pkgName,
+ String instructionSet, int dexoptNeeded, @Nullable String outputPath,
+ int dexFlags, String compilerFilter, @Nullable String volumeUuid,
+ @Nullable String sharedLibraries) throws InstallerException {
+ commands.add(buildCommand("dexopt",
+ apkPath,
+ uid,
+ pkgName,
+ instructionSet,
+ dexoptNeeded,
+ outputPath,
+ dexFlags,
+ compilerFilter,
+ volumeUuid,
+ sharedLibraries));
+ }
+ };
// Use the package manager install and install lock here for the OTA dex optimizer.
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
@@ -295,7 +316,7 @@
getCompilerFilterForReason(compilationReason),
null /* CompilerStats.PackageStats */);
- return collectingConnection.commands;
+ return commands;
}
@Override
@@ -414,39 +435,27 @@
}
- private static class RecordingInstallerConnection extends InstallerConnection {
- public List<String> commands = new ArrayList<String>(1);
-
- @Override
- public void setWarnIfHeld(Object warnIfHeld) {
- throw new IllegalStateException("Should not reach here");
+ /**
+ * Cook up argument list in the format that {@code installd} expects.
+ */
+ private static String buildCommand(Object... args) {
+ final StringBuilder builder = new StringBuilder();
+ for (Object arg : args) {
+ String escaped;
+ if (arg == null) {
+ escaped = "";
+ } else {
+ escaped = String.valueOf(arg);
+ }
+ if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) {
+ throw new IllegalArgumentException(
+ "Invalid argument while executing " + Arrays.toString(args));
+ }
+ if (TextUtils.isEmpty(escaped)) {
+ escaped = "!";
+ }
+ builder.append(' ').append(escaped);
}
-
- @Override
- public synchronized String transact(String cmd) {
- commands.add(cmd);
- return "0";
- }
-
- @Override
- public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
- throw new IllegalStateException("Should not reach here");
- }
-
- @Override
- public boolean dumpProfiles(String gid, String packageName, String codePaths)
- throws InstallerException {
- throw new IllegalStateException("Should not reach here");
- }
-
- @Override
- public void disconnect() {
- throw new IllegalStateException("Should not reach here");
- }
-
- @Override
- public void waitForConnection() {
- throw new IllegalStateException("Should not reach here");
- }
+ return builder.toString();
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9102fee..81c31b8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2228,8 +2228,9 @@
getCompilerFilterForReason(REASON_SHARED_APK),
false /* newProfile */);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
- dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, "*",
+ dexCodeInstructionSet, dexoptNeeded, null,
+ DEXOPT_PUBLIC,
getCompilerFilterForReason(REASON_SHARED_APK),
StorageManager.UUID_PRIVATE_INTERNAL,
SKIP_SHARED_LIBRARY_CHECK);
diff --git a/services/core/proto/ipconnectivity.proto b/services/core/proto/ipconnectivity.proto
index e0d7f09..29b318f 100644
--- a/services/core/proto/ipconnectivity.proto
+++ b/services/core/proto/ipconnectivity.proto
@@ -53,6 +53,7 @@
// The event type code of the probe, represented by constants defined in
// android.net.metrics.IpReachabilityEvent.
+ // NUD_FAILED_ORGANIC and PROVISIONING_LOST_ORGANIC recorded since version 1.
optional int32 event_type = 2;
};
@@ -126,11 +127,12 @@
// Lifetime duration in milliseconds of a DhcpClient state, or transition
// time in milliseconds between specific pairs of DhcpClient's states.
- // Only populated when state_transition is populated.
+ // Only populated since version 1, when state_transition is populated.
optional int32 duration_ms = 4;
}
// Represents the generation of an Android Packet Filter program.
+// Since version 1.
message ApfProgramEvent {
// Lifetime of the program in seconds.
optional int64 lifetime = 1;
@@ -154,6 +156,7 @@
// Represents Router Advertisement listening statistics for an interface with
// Android Packet Filter enabled.
+// Since version 1.
message ApfStatistics {
// The time interval in milliseconds these stastistics cover.
optional int64 duration_ms = 1;
@@ -183,6 +186,7 @@
// Represents the reception of a Router Advertisement packet for an interface
// with Android Packet Filter enabled.
+// Since version 1.
message RaEvent {
// All lifetime values are expressed in seconds. The default value for an
// option lifetime that was not present in the RA option list is -1.
@@ -271,4 +275,11 @@
// The number of events that had to be dropped due to a full buffer.
optional int32 dropped_events = 2;
+
+ // The version number of the metrics events being collected.
+ // nyc-dev: not populated, implicitly 0
+ // nyc-dr1: not populated, implicitly 1 (sailfish and marlin only)
+ // nyc-mr1: not populated, implicitly 1
+ // nyc-mr2: 2
+ optional int32 version = 3;
};
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 4c75452..83001df 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -194,8 +194,10 @@
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
- private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
+ private static final int ICMP6_ROUTER_SOLICITATION = 133;
private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
+ private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
+ private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
@@ -283,14 +285,20 @@
mReceiveThread.start();
}
- // Returns seconds since Unix Epoch.
- // TODO: use SystemClock.elapsedRealtime() instead
+ // Returns seconds since device boot.
private static long curTime() {
- return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS;
+ return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
+ }
+
+ public static class InvalidRaException extends Exception {
+ public InvalidRaException(String m) {
+ super(m);
+ }
}
// A class to hold information about an RA.
- private class Ra {
+ @VisibleForTesting
+ class Ra {
// From RFC4861:
private static final int ICMP6_RA_HEADER_LEN = 16;
private static final int ICMP6_RA_CHECKSUM_OFFSET =
@@ -362,7 +370,7 @@
} catch (UnsupportedOperationException e) {
// array() failed. Cannot happen, mPacket is array-backed and read-write.
return "???";
- } catch (ClassCastException | UnknownHostException e) {
+ } catch (ClassCastException|UnknownHostException e) {
// Cannot happen.
return "???";
}
@@ -372,16 +380,16 @@
// TODO: Make this static once RA is its own class.
private void prefixOptionToString(StringBuffer sb, int offset) {
String prefix = IPv6AddresstoString(offset + 16);
- int length = uint8(mPacket.get(offset + 2));
- long valid = mPacket.getInt(offset + 4);
- long preferred = mPacket.getInt(offset + 8);
+ int length = getUint8(mPacket, offset + 2);
+ long valid = getUint32(mPacket, offset + 4);
+ long preferred = getUint32(mPacket, offset + 8);
sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
}
private void rdnssOptionToString(StringBuffer sb, int offset) {
- int optLen = uint8(mPacket.get(offset + 1)) * 8;
+ int optLen = getUint8(mPacket, offset + 1) * 8;
if (optLen < 24) return; // Malformed or empty.
- long lifetime = uint32(mPacket.getInt(offset + 4));
+ long lifetime = getUint32(mPacket, offset + 4);
int numServers = (optLen - 8) / 16;
sb.append("DNS ").append(lifetime).append("s");
for (int server = 0; server < numServers; server++) {
@@ -395,7 +403,7 @@
sb.append(String.format("RA %s -> %s %ds ",
IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
- uint16(mPacket.getShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET))));
+ getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
for (int i: mPrefixOptionOffsets) {
prefixOptionToString(sb, i);
}
@@ -403,7 +411,7 @@
rdnssOptionToString(sb, i);
}
return sb.toString();
- } catch (BufferUnderflowException | IndexOutOfBoundsException e) {
+ } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
return "<Malformed RA>";
}
}
@@ -436,16 +444,20 @@
// Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
// (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
// specifications.
- Ra(byte[] packet, int length) {
+ Ra(byte[] packet, int length) throws InvalidRaException {
+ if (length < ICMP6_RA_OPTION_OFFSET) {
+ throw new InvalidRaException("Not an ICMP6 router advertisement");
+ }
+
mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
mLastSeen = curTime();
// Sanity check packet in case a packet arrives before we attach RA filter
// to our packet socket. b/29586253
if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
- uint8(mPacket.get(IPV6_NEXT_HEADER_OFFSET)) != IPPROTO_ICMPV6 ||
- uint8(mPacket.get(ICMP6_TYPE_OFFSET)) != ICMP6_ROUTER_ADVERTISEMENT) {
- throw new IllegalArgumentException("Not an ICMP6 router advertisement");
+ getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
+ getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
+ throw new InvalidRaException("Not an ICMP6 router advertisement");
}
@@ -466,8 +478,8 @@
mPacket.position(ICMP6_RA_OPTION_OFFSET);
while (mPacket.hasRemaining()) {
final int position = mPacket.position();
- final int optionType = uint8(mPacket.get(position));
- final int optionLength = uint8(mPacket.get(position + 1)) * 8;
+ final int optionType = getUint8(mPacket, position);
+ final int optionLength = getUint8(mPacket, position + 1) * 8;
long lifetime;
switch (optionType) {
case ICMP6_PREFIX_OPTION_TYPE:
@@ -511,7 +523,7 @@
break;
}
if (optionLength <= 0) {
- throw new IllegalArgumentException(String.format(
+ throw new InvalidRaException(String.format(
"Invalid option length opt=%d len=%d", optionType, optionLength));
}
mPacket.position(position + optionLength);
@@ -552,10 +564,10 @@
final long optionLifetime;
switch (lifetimeLength) {
case 2:
- optionLifetime = uint16(byteBuffer.getShort(offset));
+ optionLifetime = getUint16(byteBuffer, offset);
break;
case 4:
- optionLifetime = uint32(byteBuffer.getInt(offset));
+ optionLifetime = getUint32(byteBuffer, offset);
break;
default:
throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
@@ -795,6 +807,8 @@
// if it's multicast and we're dropping multicast:
// drop
// pass
+ // if it's ICMPv6 RS to any:
+ // drop
// if it's ICMPv6 NA to ff02::1:
// drop
@@ -819,10 +833,12 @@
// Add unsolicited multicast neighbor announcements filter
String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
- // If not neighbor announcements, skip unsolicited multicast NA filter
gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+ // Drop all router solicitations (b/32833400)
+ gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
+ // If not neighbor announcements, skip filter.
gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
- // If to ff02::1, drop
+ // If to ff02::1, drop.
// TODO: Drop only if they don't contain the address of on-link neighbours.
gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
@@ -842,6 +858,7 @@
* <li>Pass all non-ICMPv6 IPv6 packets,
* <li>Pass all non-IPv4 and non-IPv6 packets,
* <li>Drop IPv6 ICMPv6 NAs to ff02::1.
+ * <li>Drop IPv6 ICMPv6 RSs.
* <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
* insertion of RA filters here, or if there aren't any, just passes the packets.
* </ul>
@@ -925,8 +942,8 @@
// Execution will reach the end of the program if no filters match, which will pass the
// packet to the AP.
program = gen.generate();
- } catch (IllegalInstructionException e) {
- Log.e(TAG, "Program failed to generate: ", e);
+ } catch (IllegalInstructionException|IllegalStateException e) {
+ Log.e(TAG, "Failed to generate APF program.", e);
return;
}
mLastTimeInstalledProgram = curTime();
@@ -972,7 +989,8 @@
* if the current APF program should be updated.
* @return a ProcessRaResult enum describing what action was performed.
*/
- private synchronized ProcessRaResult processRa(byte[] packet, int length) {
+ @VisibleForTesting
+ synchronized ProcessRaResult processRa(byte[] packet, int length) {
if (VDBG) hexDump("Read packet = ", packet, length);
// Have we seen this RA before?
@@ -1011,7 +1029,7 @@
try {
ra = new Ra(packet, length);
} catch (Exception e) {
- Log.e(TAG, "Error parsing RA: " + e);
+ Log.e(TAG, "Error parsing RA", e);
return ProcessRaResult.PARSE_ERROR;
}
// Ignore 0 lifetime RAs.
@@ -1150,7 +1168,11 @@
return i & 0xffffffffL;
}
- private static long getUint16(ByteBuffer buffer, int position) {
+ private static int getUint8(ByteBuffer buffer, int position) {
+ return uint8(buffer.get(position));
+ }
+
+ private static int getUint16(ByteBuffer buffer, int position) {
return uint16(buffer.getShort(position));
}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index a6bb40c..a883e28 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -50,9 +50,9 @@
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -163,8 +163,7 @@
private Map<InetAddress, Short> mIpWatchList = new HashMap<>();
@GuardedBy("mLock")
private int mIpWatchListVersion;
- @GuardedBy("mLock")
- private boolean mRunning;
+ private volatile boolean mRunning;
// Time in milliseconds of the last forced probe request.
private volatile long mLastProbeTimeMs;
@@ -246,7 +245,7 @@
}
public void stop() {
- synchronized (mLock) { mRunning = false; }
+ mRunning = false;
clearLinkProperties();
mNetlinkSocketObserver.clearNetlinkSocket();
}
@@ -281,12 +280,6 @@
}
}
- private boolean stillRunning() {
- synchronized (mLock) {
- return mRunning;
- }
- }
-
private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
for (RouteInfo route : routes) {
if (!route.hasGateway() && route.matches(ip)) {
@@ -390,12 +383,12 @@
}
public void probeAll() {
- Set<InetAddress> ipProbeList = new HashSet<InetAddress>();
+ final List<InetAddress> ipProbeList;
synchronized (mLock) {
- ipProbeList.addAll(mIpWatchList.keySet());
+ ipProbeList = new ArrayList<>(mIpWatchList.keySet());
}
- if (!ipProbeList.isEmpty() && stillRunning()) {
+ if (!ipProbeList.isEmpty() && mRunning) {
// Keep the CPU awake long enough to allow all ARP/ND
// probes a reasonable chance at success. See b/23197666.
//
@@ -406,7 +399,7 @@
}
for (InetAddress target : ipProbeList) {
- if (!stillRunning()) {
+ if (!mRunning) {
break;
}
final int returnValue = probeNeighbor(mInterfaceIndex, target);
@@ -451,21 +444,21 @@
@Override
public void run() {
if (VDBG) { Log.d(TAG, "Starting observing thread."); }
- synchronized (mLock) { mRunning = true; }
+ mRunning = true;
try {
setupNetlinkSocket();
} catch (ErrnoException | SocketException e) {
Log.e(TAG, "Failed to suitably initialize a netlink socket", e);
- synchronized (mLock) { mRunning = false; }
+ mRunning = false;
}
- ByteBuffer byteBuffer;
- while (stillRunning()) {
+ while (mRunning) {
+ final ByteBuffer byteBuffer;
try {
byteBuffer = recvKernelReply();
} catch (ErrnoException e) {
- if (stillRunning()) { Log.w(TAG, "ErrnoException: ", e); }
+ if (mRunning) { Log.w(TAG, "ErrnoException: ", e); }
break;
}
final long whenMs = SystemClock.elapsedRealtime();
@@ -477,7 +470,7 @@
clearNetlinkSocket();
- synchronized (mLock) { mRunning = false; }
+ mRunning = false; // Not a no-op when ErrnoException happened.
if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 3183930..2187c57 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -12,12 +12,12 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
+ easymocklib \
frameworks-base-testutils \
services.core \
services.devicepolicy \
services.net \
services.usage \
- easymocklib \
guava \
android-support-test \
mockito-target \
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index 0d5daa5..f841bf9 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -24,6 +24,7 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import com.android.server.net.BaseNetworkObserver;
+import com.android.internal.util.test.BroadcastInterceptingContext;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 541be3d..8d36ac9 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -78,6 +78,7 @@
import android.text.format.Time;
import android.util.TrustedTime;
+import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.server.net.NetworkPolicyManagerService;
import com.google.common.util.concurrent.AbstractFuture;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
new file mode 100644
index 0000000..50911cb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2012 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;
+
+import static android.net.NetworkScoreManager.CACHE_FILTER_NONE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+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.Manifest.permission;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.INetworkScoreCache;
+import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppManager;
+import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.ScoredNetwork;
+import android.net.WifiKey;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.server.devicepolicy.MockUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link NetworkScoreService}.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NetworkScoreServiceTest {
+ private static final ScoredNetwork SCORED_NETWORK =
+ new ScoredNetwork(new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")),
+ null /* rssiCurve*/);
+ private static final NetworkScorerAppData PREV_SCORER = new NetworkScorerAppData(
+ "prevPackageName", 0, "prevScorerName", null /* configurationActivityClassName */,
+ "prevScoringServiceClass");
+ private static final NetworkScorerAppData NEW_SCORER = new NetworkScorerAppData(
+ "newPackageName", 1, "newScorerName", null /* configurationActivityClassName */,
+ "newScoringServiceClass");
+
+ @Mock private PackageManager mPackageManager;
+ @Mock private NetworkScorerAppManager mNetworkScorerAppManager;
+ @Mock private Context mContext;
+ @Mock private Resources mResources;
+ @Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2;
+ @Mock private IBinder mIBinder, mIBinder2;
+ @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
+
+ private ContentResolver mContentResolver;
+ private NetworkScoreService mNetworkScoreService;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mNetworkScoreCache.asBinder()).thenReturn(mIBinder);
+ when(mNetworkScoreCache2.asBinder()).thenReturn(mIBinder2);
+ mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getResources()).thenReturn(mResources);
+ mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager);
+ }
+
+ @Test
+ public void testSystemReady_networkScorerProvisioned() throws Exception {
+ Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 1);
+
+ mNetworkScoreService.systemReady();
+
+ verify(mNetworkScorerAppManager, never()).setActiveScorer(anyString());
+ }
+
+ @Test
+ public void testSystemReady_networkScorerNotProvisioned_defaultScorer() throws Exception {
+ Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 0);
+
+ when(mResources.getString(R.string.config_defaultNetworkScorerPackageName))
+ .thenReturn(NEW_SCORER.mPackageName);
+
+ mNetworkScoreService.systemReady();
+
+ verify(mNetworkScorerAppManager).setActiveScorer(NEW_SCORER.mPackageName);
+ assertEquals(1,
+ Settings.Global.getInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED));
+
+ }
+
+ @Test
+ public void testSystemReady_networkScorerNotProvisioned_noDefaultScorer() throws Exception {
+ Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 0);
+
+ when(mResources.getString(R.string.config_defaultNetworkScorerPackageName))
+ .thenReturn(null);
+
+ mNetworkScoreService.systemReady();
+
+ verify(mNetworkScorerAppManager, never()).setActiveScorer(anyString());
+ assertEquals(1,
+ Settings.Global.getInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED));
+ }
+
+ @Test
+ public void testSystemRunning() {
+ when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
+
+ mNetworkScoreService.systemRunning();
+
+ verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
+ new ComponentName(NEW_SCORER.mPackageName, NEW_SCORER.mScoringServiceClassName))),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+ eq(UserHandle.SYSTEM));
+ }
+
+ @Test
+ public void testUpdateScores_notActiveScorer() {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+
+ try {
+ mNetworkScoreService.updateScores(new ScoredNetwork[0]);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testUpdateScores_oneRegisteredCache() throws RemoteException {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
+ mNetworkScoreCache, CACHE_FILTER_NONE);
+
+ mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+ verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture());
+
+ assertEquals(1, mScoredNetworkCaptor.getValue().size());
+ assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0));
+ }
+
+ @Test
+ public void testUpdateScores_twoRegisteredCaches() throws RemoteException {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
+ mNetworkScoreCache, CACHE_FILTER_NONE);
+ mNetworkScoreService.registerNetworkScoreCache(
+ NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE);
+
+ // updateScores should update both caches
+ mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+ verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class));
+ verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class));
+
+ mNetworkScoreService.unregisterNetworkScoreCache(
+ NetworkKey.TYPE_WIFI, mNetworkScoreCache2);
+
+ // updateScores should only update the first cache since the 2nd has been unregistered
+ mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+ verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class));
+
+ mNetworkScoreService.unregisterNetworkScoreCache(
+ NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+
+ // updateScores should not update any caches since they are both unregistered
+ mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+ // The register and unregister calls grab the binder from the score cache.
+ verify(mNetworkScoreCache, atLeastOnce()).asBinder();
+ verify(mNetworkScoreCache2, atLeastOnce()).asBinder();
+ verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2);
+ }
+
+ @Test
+ public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+ when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ try {
+ mNetworkScoreService.clearScores();
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testClearScores_activeScorer_noBroadcastNetworkPermission() {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+ when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ mNetworkScoreService.clearScores();
+ }
+
+ @Test
+ public void testClearScores_activeScorer() throws RemoteException {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
+ CACHE_FILTER_NONE);
+ mNetworkScoreService.clearScores();
+
+ verify(mNetworkScoreCache).clearScores();
+ }
+
+ @Test
+ public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission()
+ throws RemoteException {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+ when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
+ CACHE_FILTER_NONE);
+ mNetworkScoreService.clearScores();
+
+ verify(mNetworkScoreCache).clearScores();
+ }
+
+ @Test
+ public void testSetActiveScorer_noScoreNetworksPermission() {
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
+
+ try {
+ mNetworkScoreService.setActiveScorer(null);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testSetActiveScorer_failure() throws RemoteException {
+ when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER);
+ when(mNetworkScorerAppManager.setActiveScorer(NEW_SCORER.mPackageName)).thenReturn(false);
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
+ CACHE_FILTER_NONE);
+
+ boolean success = mNetworkScoreService.setActiveScorer(NEW_SCORER.mPackageName);
+
+ assertFalse(success);
+ verify(mNetworkScoreCache).clearScores();
+ verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
+ new ComponentName(PREV_SCORER.mPackageName, PREV_SCORER.mScoringServiceClassName))),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+ eq(UserHandle.SYSTEM));
+ }
+
+ @Test
+ public void testSetActiveScorer_success() throws RemoteException {
+ when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, NEW_SCORER);
+ when(mNetworkScorerAppManager.setActiveScorer(NEW_SCORER.mPackageName)).thenReturn(true);
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
+ CACHE_FILTER_NONE);
+
+ boolean success = mNetworkScoreService.setActiveScorer(NEW_SCORER.mPackageName);
+
+ assertTrue(success);
+ verify(mNetworkScoreCache).clearScores();
+ verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
+ new ComponentName(NEW_SCORER.mPackageName, NEW_SCORER.mScoringServiceClassName))),
+ any(ServiceConnection.class),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+ eq(UserHandle.SYSTEM));
+ verify(mContext, times(2)).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(NetworkScoreManager.ACTION_SCORER_CHANGED),
+ eq(UserHandle.SYSTEM));
+ }
+
+ @Test
+ public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+ when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ try {
+ mNetworkScoreService.disableScoring();
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ }
+
+ @Test
+ public void testDisableScoring_activeScorer() throws RemoteException {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+ when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, null);
+ when(mNetworkScorerAppManager.setActiveScorer(null)).thenReturn(true);
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
+ CACHE_FILTER_NONE);
+
+ mNetworkScoreService.disableScoring();
+
+ verify(mNetworkScoreCache).clearScores();
+ verify(mContext).sendBroadcastAsUser(
+ MockUtils.checkIntent(new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED)
+ .setPackage(PREV_SCORER.mPackageName)),
+ eq(UserHandle.SYSTEM));
+ verify(mContext, never()).bindServiceAsUser(any(Intent.class),
+ any(ServiceConnection.class), anyInt(), any(UserHandle.class));
+ }
+
+ @Test
+ public void testDisableScoring_notActiveScorer_hasBroadcastNetworkPermission()
+ throws RemoteException {
+ when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+ when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, null);
+ when(mNetworkScorerAppManager.setActiveScorer(null)).thenReturn(true);
+ mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
+ CACHE_FILTER_NONE);
+
+ mNetworkScoreService.disableScoring();
+
+ verify(mNetworkScoreCache).clearScores();
+ verify(mContext).sendBroadcastAsUser(
+ MockUtils.checkIntent(new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED)
+ .setPackage(PREV_SCORER.mPackageName)),
+ eq(UserHandle.SYSTEM));
+ verify(mContext, never()).bindServiceAsUser(any(Intent.class),
+ any(ServiceConnection.class), anyInt(), any(UserHandle.class));
+ }
+
+ @Test
+ public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() {
+ doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+ eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+
+ try {
+ mNetworkScoreService.registerNetworkScoreCache(
+ NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() {
+ doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+ eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+
+ try {
+ mNetworkScoreService.unregisterNetworkScoreCache(
+ NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testDump_noDumpPermission() {
+ doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+ eq(permission.DUMP), anyString());
+
+ try {
+ mNetworkScoreService.dump(
+ new FileDescriptor(), new PrintWriter(new StringWriter()), new String[0]);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testDump_doesNotCrash() {
+ when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
+ StringWriter stringWriter = new StringWriter();
+
+ mNetworkScoreService.dump(
+ new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
+
+ assertFalse(stringWriter.toString().isEmpty());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 58db192..3806da6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -82,6 +82,21 @@
return Mockito.argThat(m);
}
+ public static Intent checkIntent(final Intent intent) {
+ final Matcher<Intent> m = new BaseMatcher<Intent>() {
+ @Override
+ public boolean matches(Object item) {
+ if (item == null) return false;
+ return intent.filterEquals((Intent) item);
+ }
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(intent.toString());
+ }
+ };
+ return Mockito.argThat(m);
+ }
+
public static Bundle checkUserRestrictions(String... keys) {
final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
index 21560ac..5eee7b9 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.when;
import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
@@ -336,7 +337,7 @@
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -344,7 +345,7 @@
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -374,7 +375,7 @@
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -382,7 +383,7 @@
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -412,7 +413,7 @@
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -420,7 +421,7 @@
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
@@ -450,16 +451,17 @@
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
- BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
- BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES,
+ 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
index 94c6711..728eb73 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
@@ -22,6 +22,9 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
@@ -40,21 +43,21 @@
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
-import static org.easymock.EasyMock.anyInt;
-import static org.easymock.EasyMock.anyLong;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
import android.app.AlarmManager;
-import android.app.IAlarmListener;
-import android.app.IAlarmManager;
-import android.app.PendingIntent;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.Intent;
@@ -63,6 +66,7 @@
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsSession;
import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkState;
@@ -80,23 +84,28 @@
import android.os.MessageQueue.IdleHandler;
import android.os.Message;
import android.os.PowerManager;
-import android.os.WorkSource;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
-import com.android.server.BroadcastInterceptingContext;
+import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.server.net.NetworkStatsService;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
import libcore.io.IoUtils;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.File;
import java.util.ArrayList;
@@ -106,11 +115,11 @@
/**
* Tests for {@link NetworkStatsService}.
*
- * TODO: This test is really brittle, largely due to overly-strict use of Easymock.
- * Rewrite w/ Mockito.
+ * TODO: This test used to be really brittle because it used Easymock - it uses Mockito now, but
+ * still uses the Easymock structure, which could be simplified.
*/
-@LargeTest
-public class NetworkStatsServiceTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkStatsServiceTest {
private static final String TAG = "NetworkStatsServiceTest";
private static final String TEST_IFACE = "test0";
@@ -137,10 +146,12 @@
private BroadcastInterceptingContext mServiceContext;
private File mStatsDir;
- private INetworkManagementService mNetManager;
- private TrustedTime mTime;
- private NetworkStatsSettings mSettings;
- private IConnectivityManager mConnManager;
+ private @Mock INetworkManagementService mNetManager;
+ private @Mock TrustedTime mTime;
+ private @Mock NetworkStatsSettings mSettings;
+ private @Mock IConnectivityManager mConnManager;
+ private @Mock IBinder mBinder;
+ private @Mock AlarmManager mAlarmManager;
private IdleableHandlerThread mHandlerThread;
private Handler mHandler;
@@ -148,32 +159,24 @@
private INetworkStatsSession mSession;
private INetworkManagementEventObserver mNetworkObserver;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
+ MockitoAnnotations.initMocks(this);
+ final Context context = InstrumentationRegistry.getContext();
- mServiceContext = new BroadcastInterceptingContext(getContext());
- mStatsDir = getContext().getFilesDir();
+ mServiceContext = new BroadcastInterceptingContext(context);
+ mStatsDir = context.getFilesDir();
if (mStatsDir.exists()) {
IoUtils.deleteContents(mStatsDir);
}
- mNetManager = createMock(INetworkManagementService.class);
-
- // TODO: Mock AlarmManager when migrating this test to Mockito.
- AlarmManager alarmManager = (AlarmManager) mServiceContext
- .getSystemService(Context.ALARM_SERVICE);
- mTime = createMock(TrustedTime.class);
- mSettings = createMock(NetworkStatsSettings.class);
- mConnManager = createMock(IConnectivityManager.class);
-
PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock =
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mService = new NetworkStatsService(
- mServiceContext, mNetManager, alarmManager, wakeLock, mTime,
+ mServiceContext, mNetManager, mAlarmManager, wakeLock, mTime,
TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
mStatsDir, getBaseDir(mStatsDir));
mHandlerThread = new IdleableHandlerThread("HandlerThread");
@@ -190,22 +193,20 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
- // catch INetworkManagementEventObserver during systemReady()
- final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
- INetworkManagementEventObserver>();
- mNetManager.registerObserver(capture(networkObserver));
- expectLastCall().atLeastOnce();
-
- replay();
mService.systemReady();
mSession = mService.openSession();
- verifyAndReset();
+ assertNotNull("openSession() failed", mSession);
+
+ // catch INetworkManagementEventObserver during systemReady()
+ ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
+ ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
+ verify(mNetManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue();
}
- @Override
+ @After
public void tearDown() throws Exception {
IoUtils.deleteContents(mStatsDir);
@@ -219,10 +220,9 @@
mSession.close();
mService = null;
-
- super.tearDown();
}
+ @Test
public void testNetworkStatsWifi() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
@@ -231,15 +231,13 @@
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- verifyAndReset();
+
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -248,14 +246,11 @@
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
- verifyAndReset();
+
// and bump forward again, with counters going higher. this is
// important, since polling should correctly subtract last snapshot.
@@ -265,17 +260,14 @@
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L));
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
- verifyAndReset();
}
+ @Test
public void testStatsRebootPersist() throws Exception {
assertStatsFilesExist(false);
@@ -286,15 +278,13 @@
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- verifyAndReset();
+
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -308,33 +298,28 @@
.addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
- expectNetworkStatsPoll();
-
mService.setUidForeground(UID_RED, false);
mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
mService.setUidForeground(UID_RED, true);
mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
- 6);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L,
+ 2L, 4);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L,
+ 256L, 2L, 6);
assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
- verifyAndReset();
+
// graceful shutdown system, which should trigger persist of stats, and
// clear any values in memory.
expectCurrentTime();
expectDefaultSettings();
- replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
- verifyAndReset();
-
assertStatsFilesExist(true);
// boot through serviceReady() again
@@ -343,30 +328,22 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
- // catch INetworkManagementEventObserver during systemReady()
- final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
- INetworkManagementEventObserver>();
- mNetManager.registerObserver(capture(networkObserver));
- expectLastCall().atLeastOnce();
-
- replay();
mService.systemReady();
- mNetworkObserver = networkObserver.getValue();
-
// after systemReady(), we should have historical stats loaded again
assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, ROAMING_NO, 512L, 4L, 256L, 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
- 6);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L,
+ 2L, 4);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L,
+ 256L, 2L, 6);
assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
- verifyAndReset();
}
// TODO: simulate reboot to test bucket resize
- @Suppress
+ @Test
+ @Ignore
public void testStatsBucketResize() throws Exception {
NetworkStatsHistory history = null;
@@ -379,12 +356,10 @@
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -393,9 +368,6 @@
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L));
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
@@ -403,7 +375,7 @@
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
assertEquals(2, history.size());
- verifyAndReset();
+
// now change bucket duration setting and trigger another poll with
// exact same values, which should resize existing buckets.
@@ -411,9 +383,6 @@
expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// verify identical stats, but spread across 4 buckets now
@@ -421,10 +390,10 @@
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
assertEquals(4, history.size());
- verifyAndReset();
}
+ @Test
public void testUidStatsAcrossNetworks() throws Exception {
// pretend first mobile network comes online
expectCurrentTime();
@@ -432,12 +401,10 @@
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -449,11 +416,8 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
- expectNetworkStatsPoll();
-
mService.incrementOperationCount(UID_RED, 0xF00D, 10);
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
@@ -461,7 +425,7 @@
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
- verifyAndReset();
+
// now switch networks; this also tests that we're okay with interfaces
// disappearing, to verify we don't count backwards.
@@ -475,13 +439,11 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
forcePollAndWaitForIdle();
- verifyAndReset();
+
// create traffic on second network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -494,11 +456,8 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
- expectNetworkStatsPoll();
-
mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
- replay();
forcePollAndWaitForIdle();
// verify original history still intact
@@ -511,10 +470,10 @@
assertNetworkTotal(sTemplateImsi2, 128L, 1L, 1024L, 8L, 0);
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1L, 1024L, 8L, 10);
- verifyAndReset();
}
+ @Test
public void testUidRemovedIsMoved() throws Exception {
// pretend that network comes online
expectCurrentTime();
@@ -522,12 +481,10 @@
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -540,11 +497,8 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
.addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
- expectNetworkStatsPoll();
-
mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
@@ -552,7 +506,7 @@
assertUidTotal(sTemplateWifi, UID_RED, 16L, 1L, 16L, 1L, 10);
assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0);
assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
- verifyAndReset();
+
// now pretend two UIDs are uninstalled, which should migrate stats to
// special "removed" bucket.
@@ -565,9 +519,6 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
.addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
- expectNetworkStatsPoll();
-
- replay();
final Intent intent = new Intent(ACTION_UID_REMOVED);
intent.putExtra(EXTRA_UID, UID_BLUE);
mServiceContext.sendBroadcast(intent);
@@ -581,10 +532,10 @@
assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L, 0L, 0L, 0);
assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 259L, 528L, 33L, 10);
- verifyAndReset();
}
+ @Test
public void testUid3g4gCombinedByTemplate() throws Exception {
// pretend that network comes online
expectCurrentTime();
@@ -592,12 +543,10 @@
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -607,16 +556,13 @@
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
- expectNetworkStatsPoll();
-
mService.incrementOperationCount(UID_RED, 0xF00D, 5);
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
- verifyAndReset();
+
// now switch over to 4g network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -627,13 +573,11 @@
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
forcePollAndWaitForIdle();
- verifyAndReset();
+
// create traffic on second network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -645,19 +589,15 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
.addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
- expectNetworkStatsPoll();
-
mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
- replay();
forcePollAndWaitForIdle();
// verify that ALL_MOBILE template combines both
assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
-
- verifyAndReset();
}
+ @Test
public void testSummaryForAllUid() throws Exception {
// pretend that network comes online
expectCurrentTime();
@@ -665,12 +605,10 @@
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -681,17 +619,14 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
- expectNetworkStatsPoll();
-
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1);
assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 8L, 512L, 4L, 0);
- verifyAndReset();
+
// now create more traffic in next hour, but only for one app
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -702,33 +637,29 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L));
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// first verify entire history present
NetworkStats stats = mSession.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(3, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 50L, 5L,
- 50L, 5L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 10L, 1L, 10L,
- 1L, 1);
- assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 2048L, 16L,
- 1024L, 8L, 0);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50L,
+ 5L, 50L, 5L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 10L,
+ 1L, 10L, 1L, 1);
+ assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 2048L, 16L, 1024L, 8L, 0);
// now verify that recent history only contains one uid
final long currentTime = currentTimeMillis();
stats = mSession.getSummaryForAllUid(
sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
assertEquals(1, stats.size());
- assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
- 512L, 4L, 0);
-
- verifyAndReset();
+ assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ 1024L, 8L, 512L, 4L, 0);
}
+ @Test
public void testForegroundBackground() throws Exception {
// pretend that network comes online
expectCurrentTime();
@@ -736,12 +667,10 @@
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -751,16 +680,13 @@
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
- expectNetworkStatsPoll();
-
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
- verifyAndReset();
+
// now switch to foreground
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -772,12 +698,9 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
- expectNetworkStatsPoll();
-
mService.setUidForeground(UID_RED, true);
mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
- replay();
forcePollAndWaitForIdle();
// test that we combined correctly
@@ -787,18 +710,59 @@
final NetworkStats stats = mSession.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(4, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
- 128L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
- 1L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, ROAMING_NO, 32L, 2L,
- 32L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_NO, 1L, 1L, 1L,
- 1L, 1);
-
- verifyAndReset();
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L,
+ 2L, 128L, 2L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L,
+ 1L, 64L, 1L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ 32L, 2L, 32L, 2L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, METERED_NO, ROAMING_NO, 1L,
+ 1L, 1L, 1L, 1);
}
+ @Test
+ public void testMetered() throws Exception {
+ // pretend that network comes online
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkState(buildWifiState(true /* isMetered */));
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces();
+
+
+ // create some initial traffic
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ // Note that all traffic from NetworkManagementService is tagged as METERED_NO and
+ // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
+ // on top by inspecting the iface properties.
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L,
+ 2L, 128L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L,
+ 1L, 64L, 1L, 0L));
+ mService.incrementOperationCount(UID_RED, 0xF00D, 1);
+
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
+ // verify entire history present
+ final NetworkStats stats = mSession.getSummaryForAllUid(
+ sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(2, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ 128L, 2L, 128L, 2L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 64L,
+ 1L, 64L, 1L, 1);
+ }
+
+ @Test
public void testRoaming() throws Exception {
// pretend that network comes online
expectCurrentTime();
@@ -806,29 +770,24 @@
expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
- // Note that all traffic from NetworkManagementService is tagged as ROAMING_NO, because
- // roaming isn't tracked at that layer. We layer it on top by inspecting the iface
- // properties.
+ // Note that all traffic from NetworkManagementService is tagged as METERED_NO and
+ // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
+ // on top by inspecting the iface properties.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
- 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
- 1L, 0L));
- expectNetworkStatsPoll();
-
- replay();
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
+ 128L, 2L, 128L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, 64L,
+ 1L, 64L, 1L, 0L));
forcePollAndWaitForIdle();
// verify service recorded history
@@ -838,14 +797,13 @@
final NetworkStats stats = mSession.getSummaryForAllUid(
sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(2, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 2L,
- 128L, 2L, 0);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L,
- 1L, 0);
-
- verifyAndReset();
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_YES,
+ 128L, 2L, 128L, 2L, 0);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_YES, 64L,
+ 1L, 64L, 1L, 0);
}
+ @Test
public void testTethering() throws Exception {
// pretend first mobile network comes online
expectCurrentTime();
@@ -853,12 +811,10 @@
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
- verifyAndReset();
+
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -871,22 +827,20 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" };
final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L);
+ .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
+ 0L);
expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats);
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
- verifyAndReset();
}
+ @Test
public void testRegisterUsageCallback() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
@@ -895,16 +849,12 @@
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
expectBandwidthControlCheck();
- replay();
mService.forceUpdateIfaces();
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- verifyAndReset();
-
String callingPackage = "the.calling.package";
long thresholdInBytes = 1L; // very small; should be overriden by framework
DataUsageRequest inputRequest = new DataUsageRequest(
@@ -915,23 +865,18 @@
LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
Messenger messenger = new Messenger(latchedHandler);
- // Allow binder to connect
- IBinder mockBinder = createMock(IBinder.class);
- mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
- EasyMock.replay(mockBinder);
-
// Force poll
expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
- replay();
+
+
// Register and verify request and that binder was called
DataUsageRequest request =
mService.registerUsageCallback(callingPackage, inputRequest,
- messenger, mockBinder);
+ messenger, mBinder);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateWifi, request.template));
long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
@@ -941,11 +886,11 @@
mHandler.sendMessage(mHandler.obtainMessage(-1));
mHandlerThread.waitForIdle(WAIT_TIMEOUT);
- verifyAndReset();
+
// Make sure that the caller binder gets connected
- EasyMock.verify(mockBinder);
- EasyMock.reset(mockBinder);
+ verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
// modify some number on wifi, and trigger poll event
// not enough traffic to call data usage callback
@@ -955,13 +900,9 @@
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
- verifyAndReset();
assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
// make sure callback has not being called
@@ -975,14 +916,11 @@
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0);
- verifyAndReset();
+
// Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
assertTrue(cv.block(WAIT_TIMEOUT));
@@ -990,9 +928,7 @@
cv.close();
// Allow binder to disconnect
- expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
- .andReturn(true);
- EasyMock.replay(mockBinder);
+ when(mBinder.unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt())).thenReturn(true);
// Unregister request
mService.unregisterUsageRequest(request);
@@ -1002,9 +938,10 @@
assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
// Make sure that the caller binder gets disconnected
- EasyMock.verify(mockBinder);
+ verify(mBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
}
+ @Test
public void testUnregisterUsageCallback_unknown_noop() throws Exception {
String callingPackage = "the.calling.package";
long thresholdInBytes = 10 * 1024 * 1024; // 10 MB
@@ -1034,18 +971,18 @@
// verify summary API
final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
- assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_NO, rxBytes,
- rxPackets, txBytes, txPackets, operations);
+ assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
+ rxBytes, rxPackets, txBytes, txPackets, operations);
}
private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) throws Exception {
- assertUidTotal(template, uid, SET_ALL, ROAMING_ALL, rxBytes, rxPackets, txBytes, txPackets,
- operations);
+ assertUidTotal(template, uid, SET_ALL, METERED_ALL, ROAMING_ALL, rxBytes, rxPackets,
+ txBytes, txPackets, operations);
}
- private void assertUidTotal(NetworkTemplate template, int uid, int set, int roaming,
- long rxBytes, long rxPackets, long txBytes, long txPackets, int operations)
+ private void assertUidTotal(NetworkTemplate template, int uid, int set, int metered,
+ int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations)
throws Exception {
// verify history API
final NetworkStatsHistory history = mSession.getHistoryForUid(
@@ -1056,38 +993,35 @@
// verify summary API
final NetworkStats stats = mSession.getSummaryForAllUid(
template, Long.MIN_VALUE, Long.MAX_VALUE, false);
- assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, roaming, rxBytes, rxPackets, txBytes,
- txPackets, operations);
+ assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, metered, roaming, rxBytes, rxPackets,
+ txBytes, txPackets, operations);
}
private void expectSystemReady() throws Exception {
- mNetManager.setGlobalAlert(anyLong());
- expectLastCall().atLeastOnce();
-
expectNetworkStatsSummary(buildEmptyStats());
expectBandwidthControlCheck();
}
private void expectNetworkState(NetworkState... state) throws Exception {
- expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+ when(mConnManager.getAllNetworkState()).thenReturn(state);
final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null;
- expect(mConnManager.getActiveLinkProperties()).andReturn(linkProp).atLeastOnce();
+ when(mConnManager.getActiveLinkProperties()).thenReturn(linkProp);
}
private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
- expect(mConnManager.getAllVpnInfo()).andReturn(new VpnInfo[0]).atLeastOnce();
+ when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]);
expectNetworkStatsSummaryDev(summary);
expectNetworkStatsSummaryXt(summary);
}
private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
- expect(mNetManager.getNetworkStatsSummaryDev()).andReturn(summary).atLeastOnce();
+ when(mNetManager.getNetworkStatsSummaryDev()).thenReturn(summary);
}
private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
- expect(mNetManager.getNetworkStatsSummaryXt()).andReturn(summary).atLeastOnce();
+ when(mNetManager.getNetworkStatsSummaryXt()).thenReturn(summary);
}
private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
@@ -1097,11 +1031,10 @@
private void expectNetworkStatsUidDetail(
NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats)
throws Exception {
- expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce();
+ when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail);
// also include tethering details, since they are folded into UID
- expect(mNetManager.getNetworkStatsTethering())
- .andReturn(tetherStats).atLeastOnce();
+ when(mNetManager.getNetworkStatsTethering()).thenReturn(tetherStats);
}
private void expectDefaultSettings() throws Exception {
@@ -1110,38 +1043,33 @@
private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
throws Exception {
- expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
- expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
- expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
+ when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
+ when(mSettings.getTimeCacheMaxAge()).thenReturn(DAY_IN_MILLIS);
+ when(mSettings.getSampleEnabled()).thenReturn(true);
final Config config = new Config(bucketDuration, deleteAge, deleteAge);
- expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
- expect(mSettings.getXtConfig()).andReturn(config).anyTimes();
- expect(mSettings.getUidConfig()).andReturn(config).anyTimes();
- expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes();
+ when(mSettings.getDevConfig()).thenReturn(config);
+ when(mSettings.getXtConfig()).thenReturn(config);
+ when(mSettings.getUidConfig()).thenReturn(config);
+ when(mSettings.getUidTagConfig()).thenReturn(config);
- expect(mSettings.getGlobalAlertBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
- expect(mSettings.getDevPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
- expect(mSettings.getXtPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
- expect(mSettings.getUidPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
- expect(mSettings.getUidTagPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
+ when(mSettings.getGlobalAlertBytes(anyLong())).thenReturn(MB_IN_BYTES);
+ when(mSettings.getDevPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
+ when(mSettings.getXtPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
+ when(mSettings.getUidPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
+ when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
}
private void expectCurrentTime() throws Exception {
- expect(mTime.forceRefresh()).andReturn(false).anyTimes();
- expect(mTime.hasCache()).andReturn(true).anyTimes();
- expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes();
- expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
- expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
- }
-
- private void expectNetworkStatsPoll() throws Exception {
- mNetManager.setGlobalAlert(anyLong());
- expectLastCall().anyTimes();
+ when(mTime.forceRefresh()).thenReturn(false);
+ when(mTime.hasCache()).thenReturn(true);
+ when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
+ when(mTime.getCacheAge()).thenReturn(0L);
+ when(mTime.getCacheCertainty()).thenReturn(0L);
}
private void expectBandwidthControlCheck() throws Exception {
- expect(mNetManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
+ when(mNetManager.isBandwidthControlEnabled()).thenReturn(true);
}
private void assertStatsFilesExist(boolean exist) {
@@ -1154,8 +1082,8 @@
}
private static void assertValues(NetworkStats stats, String iface, int uid, int set,
- int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
- int operations) {
+ int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
+ long txPackets, int operations) {
final NetworkStats.Entry entry = new NetworkStats.Entry();
List<Integer> sets = new ArrayList<>();
if (set == SET_DEFAULT || set == SET_ALL) {
@@ -1173,11 +1101,21 @@
roamings.add(ROAMING_YES);
}
+ List<Integer> meterings = new ArrayList<>();
+ if (metered == METERED_NO || metered == METERED_ALL) {
+ meterings.add(METERED_NO);
+ }
+ if (metered == METERED_YES || metered == METERED_ALL) {
+ meterings.add(METERED_YES);
+ }
+
for (int s : sets) {
for (int r : roamings) {
- final int i = stats.findIndex(iface, uid, s, tag, r);
- if (i != -1) {
- entry.add(stats.getValues(i, null));
+ for (int m : meterings) {
+ final int i = stats.findIndex(iface, uid, s, tag, m, r);
+ if (i != -1) {
+ entry.add(stats.getValues(i, null));
+ }
}
}
}
@@ -1200,11 +1138,19 @@
}
private static NetworkState buildWifiState() {
+ return buildWifiState(false);
+ }
+
+ private static NetworkState buildWifiState(boolean isMetered) {
final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
- return new NetworkState(info, prop, null, null, null, TEST_SSID);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ if (!isMetered) {
+ capabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ }
+ return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
}
private static NetworkState buildMobile3gState(String subscriberId) {
@@ -1218,7 +1164,8 @@
info.setRoaming(isRoaming);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
- return new NetworkState(info, prop, null, null, subscriberId, null);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ return new NetworkState(info, prop, capabilities, null, subscriberId, null);
}
private static NetworkState buildMobile4gState(String iface) {
@@ -1226,7 +1173,8 @@
info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(iface);
- return new NetworkState(info, prop, null, null, null, null);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ return new NetworkState(info, prop, capabilities, null, null, null);
}
private NetworkStats buildEmptyStats() {
@@ -1249,15 +1197,6 @@
mElapsedRealtime += duration;
}
- private void replay() {
- EasyMock.replay(mNetManager, mTime, mSettings, mConnManager);
- }
-
- private void verifyAndReset() {
- EasyMock.verify(mNetManager, mTime, mSettings, mConnManager);
- EasyMock.reset(mNetManager, mTime, mSettings, mConnManager);
- }
-
private void forcePollAndWaitForIdle() {
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// Send dummy message to make sure that any previous message has been handled
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
new file mode 100644
index 0000000..8aa27a9
--- /dev/null
+++ b/tests/net/Android.mk
@@ -0,0 +1,80 @@
+#########################################################################
+# Build FrameworksNetTests package
+#########################################################################
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ frameworks-base-testutils \
+ framework-protos \
+ android-support-test \
+ mockito-target-minus-junit4 \
+ platform-test-annotations \
+ services.core \
+ services.net
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworksNetTests
+
+LOCAL_CERTIFICATE := platform
+
+# These are not normally accessible from apps so they must be explicitly included.
+LOCAL_JNI_SHARED_LIBRARIES := libframeworksnettestsjni \
+ libbacktrace \
+ libbase \
+ libbinder \
+ libc++ \
+ libcutils \
+ liblog \
+ liblzma \
+ libnativehelper \
+ libnetdaidl \
+ libui \
+ libunwind \
+ libutils
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+include $(BUILD_PACKAGE)
+
+#########################################################################
+# Build JNI Shared Library
+#########################################################################
+
+LOCAL_PATH:= $(LOCAL_PATH)/jni
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Wall -Wextra -Werror
+
+LOCAL_C_INCLUDES := \
+ libpcap \
+ hardware/google/apf
+
+LOCAL_SRC_FILES := $(call all-cpp-files-under)
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ liblog \
+ libcutils \
+ libnativehelper \
+ libnetdaidl
+
+LOCAL_STATIC_LIBRARIES := \
+ libpcap \
+ libapf
+
+LOCAL_MODULE := libframeworksnettestsjni
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
new file mode 100644
index 0000000..e069dd0
--- /dev/null
+++ b/tests/net/AndroidManifest.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.tests.net">
+
+ <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+ <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+ <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
+ <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+ <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+ <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.tests.net"
+ android:label="Frameworks Networking Tests" />
+</manifest>
diff --git a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
similarity index 97%
rename from services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
rename to tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
index 6d42cce..f896030 100644
--- a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
+++ b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
import java.util.List;
import junit.framework.TestCase;
import org.mockito.ArgumentCaptor;
@@ -49,6 +50,7 @@
mLog = new ConnectivityMetricsLogger(mService);
}
+ @SmallTest
public void testLogEvents() throws Exception {
mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
@@ -60,6 +62,7 @@
assertEventsEqual(expectedEvent(3), gotEvents.get(2));
}
+ @SmallTest
public void testLogEventTriggerThrottling() throws Exception {
when(mService.logEvent(any())).thenReturn(1234L);
@@ -70,6 +73,7 @@
assertEventsEqual(expectedEvent(1), gotEvents.get(0));
}
+ @SmallTest
public void testLogEventFails() throws Exception {
when(mService.logEvent(any())).thenReturn(-1L); // Error.
@@ -80,6 +84,7 @@
assertEventsEqual(expectedEvent(1), gotEvents.get(0));
}
+ @SmallTest
public void testLogEventWhenThrottling() throws Exception {
when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
@@ -92,6 +97,7 @@
assertEventsEqual(expectedEvent(1), gotEvents.get(0));
}
+ @SmallTest
public void testLogEventRecoverFromThrottling() throws Exception {
final long throttleTimeout = System.currentTimeMillis() + 10;
when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
diff --git a/services/tests/servicestests/src/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java
similarity index 98%
rename from services/tests/servicestests/src/android/net/UidRangeTest.java
rename to tests/net/java/android/net/UidRangeTest.java
index 221fe0f..0a56e1b 100644
--- a/services/tests/servicestests/src/android/net/UidRangeTest.java
+++ b/tests/net/java/android/net/UidRangeTest.java
@@ -26,7 +26,7 @@
public class UidRangeTest extends TestCase {
static {
- System.loadLibrary("servicestestsjni");
+ System.loadLibrary("frameworksnettestsjni");
}
private static native byte[] readAndWriteNative(byte[] inParcel);
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
similarity index 95%
rename from services/tests/servicestests/src/android/net/apf/ApfTest.java
rename to tests/net/java/android/net/apf/ApfTest.java
index f7c61d1..ff61754 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -16,10 +16,6 @@
package android.net.apf;
-import static android.system.OsConstants.*;
-
-import com.android.frameworks.servicestests.R;
-
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
@@ -36,7 +32,11 @@
import android.system.ErrnoException;
import android.system.Os;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import static android.system.OsConstants.*;
+
+import com.android.frameworks.tests.net.R;
+import com.android.internal.util.HexDump;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -54,6 +54,7 @@
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.List;
+import java.util.Random;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -74,7 +75,7 @@
super.setUp();
MockitoAnnotations.initMocks(this);
// Load up native shared library containing APF interpreter exposed via JNI.
- System.loadLibrary("servicestestsjni");
+ System.loadLibrary("frameworksnettestsjni");
}
// Expected return codes from APF interpreter.
@@ -153,7 +154,7 @@
* generating bytecode for that program and running it through the
* interpreter to verify it functions correctly.
*/
- @LargeTest
+ @SmallTest
public void testApfInstructions() throws IllegalInstructionException {
// Empty program should pass because having the program counter reach the
// location immediately after the program indicates the packet should be
@@ -561,7 +562,7 @@
* Generate some BPF programs, translate them to APF, then run APF and BPF programs
* over packet traces and verify both programs filter out the same packets.
*/
- @LargeTest
+ @SmallTest
public void testApfAgainstBpf() throws Exception {
String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
"arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
@@ -660,9 +661,13 @@
// The IPv6 all nodes address ff02::1
private static final byte[] IPV6_ALL_NODES_ADDRESS =
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+ private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
+ { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+ private static final int ICMP6_ROUTER_SOLICITATION = 133;
private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
+ private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
private static final int ICMP6_RA_HEADER_LEN = 16;
@@ -719,7 +724,7 @@
private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2};
private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
- @LargeTest
+ @SmallTest
public void testApfFilterIPv4() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
@@ -774,7 +779,7 @@
apfFilter.shutdown();
}
- @LargeTest
+ @SmallTest
public void testApfFilterIPv6() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
@@ -797,10 +802,16 @@
put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
assertDrop(program, packet.array());
+ // Verify ICMPv6 RS to any is dropped
+ packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
+ assertDrop(program, packet.array());
+ put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
+ assertDrop(program, packet.array());
+
apfFilter.shutdown();
}
- @LargeTest
+ @SmallTest
public void testApfFilterMulticast() throws Exception {
final byte[] unicastIpv4Addr = {(byte)192,0,2,63};
final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
@@ -910,7 +921,7 @@
assertDrop(program, garpReply());
}
- @LargeTest
+ @SmallTest
public void testApfFilterArp() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
@@ -1029,7 +1040,7 @@
ipManagerCallback.assertNoProgramUpdate();
}
- @LargeTest
+ @SmallTest
public void testApfFilterRa() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
@@ -1146,6 +1157,41 @@
buffer.position(original);
}
+ @SmallTest
+ public void testRaParsing() throws Exception {
+ final int maxRandomPacketSize = 512;
+ final Random r = new Random();
+ MockIpManagerCallback cb = new MockIpManagerCallback();
+ TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
+ for (int i = 0; i < 1000; i++) {
+ byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+ r.nextBytes(packet);
+ try {
+ apfFilter.new Ra(packet, packet.length);
+ } catch (ApfFilter.InvalidRaException e) {
+ } catch (Exception e) {
+ throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+ }
+ }
+ }
+
+ @SmallTest
+ public void testRaProcessing() throws Exception {
+ final int maxRandomPacketSize = 512;
+ final Random r = new Random();
+ MockIpManagerCallback cb = new MockIpManagerCallback();
+ TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
+ for (int i = 0; i < 1000; i++) {
+ byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+ r.nextBytes(packet);
+ try {
+ apfFilter.processRa(packet, packet.length);
+ } catch (Exception e) {
+ throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+ }
+ }
+ }
+
/**
* Call the APF interpreter the run {@code program} on {@code packet} pretending the
* filter was installed {@code filter_age} seconds ago.
@@ -1167,6 +1213,7 @@
private native static boolean compareBpfApf(String filter, String pcap_filename,
byte[] apf_program);
+ @SmallTest
public void testBytesToInt() {
assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR));
assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS));
diff --git a/services/tests/servicestests/src/android/net/apf/Bpf2Apf.java b/tests/net/java/android/net/apf/Bpf2Apf.java
similarity index 100%
rename from services/tests/servicestests/src/android/net/apf/Bpf2Apf.java
rename to tests/net/java/android/net/apf/Bpf2Apf.java
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
similarity index 99%
rename from services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
rename to tests/net/java/android/net/dhcp/DhcpPacketTest.java
index bc8baa1..d79c312 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java
@@ -473,6 +473,7 @@
assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
}
+ @SmallTest
public void testTruncatedOfferPackets() throws Exception {
final byte[] packet = HexDump.hexStringToByteArray(
// IP header.
@@ -506,6 +507,7 @@
}
}
+ @SmallTest
public void testRandomPackets() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
similarity index 97%
rename from services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
rename to tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
index e677475..5deba27 100644
--- a/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
@@ -24,6 +24,7 @@
import android.net.netlink.NetlinkErrorMessage;
import android.net.netlink.NetlinkMessage;
import android.net.netlink.StructNlMsgErr;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -53,6 +54,7 @@
public static final byte[] NLM_ERROR_OK =
HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
+ @SmallTest
public void testParseNlmErrorOk() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
diff --git a/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
similarity index 97%
rename from services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
rename to tests/net/java/android/net/netlink/NetlinkSocketTest.java
index c599fe3..78b3b70 100644
--- a/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
@@ -20,6 +20,7 @@
import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
+import android.test.suitebuilder.annotation.SmallTest;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
import android.system.OsConstants;
@@ -33,6 +34,7 @@
public class NetlinkSocketTest extends TestCase {
private final String TAG = "NetlinkSocketTest";
+ @SmallTest
public void testBasicWorkingGetNeighborsQuery() throws Exception {
NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
assertNotNull(s);
@@ -91,6 +93,7 @@
s.close();
}
+ @SmallTest
public void testRepeatedCloseCallsAreQuiet() throws Exception {
// Create a working NetlinkSocket.
NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
diff --git a/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
similarity index 98%
rename from services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
rename to tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
index 19ee000..029758e 100644
--- a/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -21,12 +21,13 @@
import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
+import android.test.suitebuilder.annotation.SmallTest;
import android.system.OsConstants;
import android.util.Log;
import libcore.util.HexEncoding;
-import java.net.InetAddress;
import java.net.Inet4Address;
+import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -135,6 +136,7 @@
public static final byte[] RTM_GETNEIGH_RESPONSE =
HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
+ @SmallTest
public void testParseRtmDelNeigh() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
@@ -161,6 +163,7 @@
assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
}
+ @SmallTest
public void testParseRtmNewNeigh() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
@@ -187,6 +190,7 @@
assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
}
+ @SmallTest
public void testParseRtmGetNeighResponse() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
@@ -211,6 +215,7 @@
assertEquals(14, messageCount);
}
+ @SmallTest
public void testCreateRtmNewNeighMessage() {
final int seqNo = 2635;
final int ifIndex = 14;
diff --git a/services/tests/servicestests/src/android/net/util/IpUtilsTest.java b/tests/net/java/android/net/util/IpUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/android/net/util/IpUtilsTest.java
rename to tests/net/java/android/net/util/IpUtilsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
similarity index 90%
rename from services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
rename to tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4af1cf1..d62c30d 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -68,14 +68,15 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.test.AndroidTestCase;
+import android.test.FlakyTest;
import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.LogPrinter;
-import com.android.internal.util.FakeSettingsProvider;
import com.android.internal.util.WakeupMessage;
+import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
@@ -89,6 +90,7 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BooleanSupplier;
/**
* Tests for {@link ConnectivityService}.
@@ -193,6 +195,7 @@
}
// Tests that IdleableHandlerThread works as expected.
+ @SmallTest
public void testIdleableHandlerThread() {
final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
@@ -215,8 +218,21 @@
mService.waitForIdle();
assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
}
+ }
+
+ @SmallTest
+ @FlakyTest(tolerance = 3)
+ public void testNotWaitingForIdleCausesRaceConditions() {
+ // Bring up a network that we can use to send messages to ConnectivityService.
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ waitFor(cv);
+ Network n = mWiFiNetworkAgent.getNetwork();
+ assertNotNull(n);
// Ensure that not calling waitForIdle causes a race condition.
+ final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
for (int i = 0; i < attempts; i++) {
mWiFiNetworkAgent.setSignalStrength(i);
if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) {
@@ -236,6 +252,7 @@
private final IdleableHandlerThread mHandlerThread;
private final ConditionVariable mDisconnected = new ConditionVariable();
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
+ private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
private int mScore;
private NetworkAgent mNetworkAgent;
private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
@@ -291,6 +308,11 @@
mRedirectUrl = redirectUrl;
mNetworkStatusReceived.open();
}
+
+ @Override
+ protected void preventAutomaticReconnect() {
+ mPreventReconnectReceived.open();
+ }
};
// Waits for the NetworkAgent to be registered, which includes the creation of the
// NetworkMonitor.
@@ -375,11 +397,6 @@
mWrappedNetworkMonitor.gen204ProbeResult = 200;
mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
connect(false);
- waitFor(new Criteria() { public boolean get() {
- NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork());
- return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} });
- mWrappedNetworkMonitor.gen204ProbeResult = 500;
- mWrappedNetworkMonitor.gen204ProbeRedirectUrl = null;
}
public void disconnect() {
@@ -391,6 +408,10 @@
return new Network(mNetworkAgent.netId);
}
+ public ConditionVariable getPreventReconnectReceived() {
+ return mPreventReconnectReceived;
+ }
+
public ConditionVariable getDisconnectedCV() {
return mDisconnected;
}
@@ -597,12 +618,13 @@
@Override
protected CaptivePortalProbeResult isCaptivePortal() {
+ if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
}
}
private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker {
- public boolean configRestrictsAvoidBadWifi;
+ public volatile boolean configRestrictsAvoidBadWifi;
public WrappedAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
super(c, h, r);
@@ -707,10 +729,7 @@
static private void waitFor(Criteria criteria) {
int delays = 0;
while (!criteria.get()) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- }
+ sleepFor(50);
if (++delays == 10) fail();
}
}
@@ -743,6 +762,9 @@
mService.systemReady();
mCm = new WrappedConnectivityManager(getContext(), mService);
mCm.bindProcessToNetwork(null);
+
+ // Ensure that the default setting for Captive Portals is used for most tests
+ setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
}
public void tearDown() throws Exception {
@@ -819,7 +841,7 @@
return cv;
}
- @LargeTest
+ @SmallTest
public void testLingering() throws Exception {
verifyNoNetwork();
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -859,7 +881,7 @@
verifyNoNetwork();
}
- @LargeTest
+ @SmallTest
public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
// Test bringing up unvalidated WiFi
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -894,7 +916,7 @@
verifyNoNetwork();
}
- @LargeTest
+ @SmallTest
public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
// Test bringing up unvalidated cellular.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -920,7 +942,7 @@
verifyNoNetwork();
}
- @LargeTest
+ @SmallTest
public void testUnlingeringDoesNotValidate() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -948,7 +970,7 @@
NET_CAPABILITY_VALIDATED));
}
- @LargeTest
+ @SmallTest
public void testCellularOutscoresWeakWifi() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -974,7 +996,7 @@
verifyActiveNetwork(TRANSPORT_WIFI);
}
- @LargeTest
+ @SmallTest
public void testReapingNetwork() throws Exception {
// Test bringing up WiFi without NET_CAPABILITY_INTERNET.
// Expect it to be torn down immediately because it satisfies no requests.
@@ -1007,7 +1029,7 @@
waitFor(cv);
}
- @LargeTest
+ @SmallTest
public void testCellularFallback() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1045,7 +1067,7 @@
verifyActiveNetwork(TRANSPORT_WIFI);
}
- @LargeTest
+ @SmallTest
public void testWiFiFallback() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1077,7 +1099,8 @@
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
LOSING,
- LOST
+ LOST,
+ UNAVAILABLE
}
/**
@@ -1118,6 +1141,11 @@
}
@Override
+ public void onUnavailable() {
+ setLastCallback(CallbackState.UNAVAILABLE, null, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -1166,7 +1194,7 @@
}
}
- @LargeTest
+ @SmallTest
public void testStateChangeNetworkCallbacks() throws Exception {
final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
@@ -1549,7 +1577,7 @@
handlerThread.quit();
}
- @LargeTest
+ @SmallTest
public void testNetworkFactoryRequests() throws Exception {
tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
@@ -1569,7 +1597,7 @@
// Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
}
- @LargeTest
+ @SmallTest
public void testNoMutableNetworkRequests() throws Exception {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
@@ -1594,7 +1622,7 @@
} catch (IllegalArgumentException expected) {}
}
- @LargeTest
+ @SmallTest
public void testMMSonWiFi() throws Exception {
// Test bringing up cellular without MMS NetworkRequest gets reaped
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1629,7 +1657,7 @@
verifyActiveNetwork(TRANSPORT_WIFI);
}
- @LargeTest
+ @SmallTest
public void testMMSonCell() throws Exception {
// Test bringing up cellular without MMS
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1655,7 +1683,7 @@
verifyActiveNetwork(TRANSPORT_CELLULAR);
}
- @LargeTest
+ @SmallTest
public void testCaptivePortal() {
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -1705,6 +1733,47 @@
}
@SmallTest
+ public void testAvoidOrIgnoreCaptivePortals() {
+ final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
+ final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
+ mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
+
+ final TestNetworkCallback validatedCallback = new TestNetworkCallback();
+ final NetworkRequest validatedRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_VALIDATED).build();
+ mCm.registerNetworkCallback(validatedRequest, validatedCallback);
+
+ setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
+ // Bring up a network with a captive portal.
+ // Expect it to fail to connect and not result in any callbacks.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ String firstRedirectUrl = "http://example.com/firstPath";
+
+ ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV();
+ ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived();
+ mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
+ waitFor(disconnectCv);
+ waitFor(avoidCv);
+
+ assertNoCallbacks(captivePortalCallback, validatedCallback);
+
+ // Now test ignore mode.
+ setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
+
+ // Bring up a network with a captive portal.
+ // Since we're ignoring captive portals, the network will validate.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ String secondRedirectUrl = "http://example.com/secondPath";
+ mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
+
+ // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
+ validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ // But there should be no CaptivePortal callback.
+ captivePortalCallback.assertNoCallback();
+ }
+
+ @SmallTest
public void testInvalidNetworkSpecifier() {
boolean execptionCalled = true;
@@ -1734,7 +1803,7 @@
execptionCalled);
}
- @LargeTest
+ @SmallTest
public void testRegisterDefaultNetworkCallback() throws Exception {
final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -1795,7 +1864,7 @@
}
}
- @LargeTest
+ @SmallTest
public void testRequestCallbackUpdates() throws Exception {
// File a network request for mobile.
final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
@@ -1844,6 +1913,11 @@
mCm.unregisterNetworkCallback(cellNetworkCallback);
}
+ private void setCaptivePortalMode(int mode) {
+ ContentResolver cr = mServiceContext.getContentResolver();
+ Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
+ }
+
private void setMobileDataAlwaysOn(boolean enable) {
ContentResolver cr = mServiceContext.getContentResolver();
Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
@@ -1925,6 +1999,7 @@
@SmallTest
public void testRequestBenchmark() throws Exception {
+ // TODO: turn this unit test into a real benchmarking test.
// Benchmarks connecting and switching performance in the presence of a large number of
// NetworkRequests.
// 1. File NUM_REQUESTS requests.
@@ -1938,61 +2013,80 @@
final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS);
final CountDownLatch losingLatch = new CountDownLatch(NUM_REQUESTS);
- final int REGISTER_TIME_LIMIT_MS = 100;
- long startTime = System.currentTimeMillis();
for (int i = 0; i < NUM_REQUESTS; i++) {
callbacks[i] = new NetworkCallback() {
@Override public void onAvailable(Network n) { availableLatch.countDown(); }
@Override public void onLosing(Network n, int t) { losingLatch.countDown(); }
};
- mCm.registerNetworkCallback(request, callbacks[i]);
}
- long timeTaken = System.currentTimeMillis() - startTime;
- String msg = String.format("Register %d callbacks: %dms, acceptable %dms",
- NUM_REQUESTS, timeTaken, REGISTER_TIME_LIMIT_MS);
- Log.d(TAG, msg);
- assertTrue(msg, timeTaken < REGISTER_TIME_LIMIT_MS);
- final int CONNECT_TIME_LIMIT_MS = 30;
+ final int REGISTER_TIME_LIMIT_MS = 180;
+ assertTimeLimit("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
+ for (NetworkCallback cb : callbacks) {
+ mCm.registerNetworkCallback(request, cb);
+ }
+ });
+
+ final int CONNECT_TIME_LIMIT_MS = 40;
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
// Don't request that the network validate, because otherwise connect() will block until
// the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
// and we won't actually measure anything.
mCellNetworkAgent.connect(false);
- startTime = System.currentTimeMillis();
- if (!availableLatch.await(CONNECT_TIME_LIMIT_MS, TimeUnit.MILLISECONDS)) {
- fail(String.format("Only dispatched %d/%d onAvailable callbacks in %dms",
- NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
- CONNECT_TIME_LIMIT_MS));
- }
- timeTaken = System.currentTimeMillis() - startTime;
- Log.d(TAG, String.format("Connect, %d callbacks: %dms, acceptable %dms",
- NUM_REQUESTS, timeTaken, CONNECT_TIME_LIMIT_MS));
- final int SWITCH_TIME_LIMIT_MS = 30;
+ long onAvailableDispatchingDuration = durationOf(() -> {
+ if (!awaitLatch(availableLatch, CONNECT_TIME_LIMIT_MS)) {
+ fail(String.format("Only dispatched %d/%d onAvailable callbacks in %dms",
+ NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
+ CONNECT_TIME_LIMIT_MS));
+ }
+ });
+ Log.d(TAG, String.format("Connect, %d callbacks: %dms, acceptable %dms",
+ NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS));
+
+ final int SWITCH_TIME_LIMIT_MS = 40;
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
// Give wifi a high enough score that we'll linger cell when wifi comes up.
mWiFiNetworkAgent.adjustScore(40);
mWiFiNetworkAgent.connect(false);
- startTime = System.currentTimeMillis();
- if (!losingLatch.await(SWITCH_TIME_LIMIT_MS, TimeUnit.MILLISECONDS)) {
- fail(String.format("Only dispatched %d/%d onLosing callbacks in %dms",
- NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, SWITCH_TIME_LIMIT_MS));
- }
- timeTaken = System.currentTimeMillis() - startTime;
+
+ long onLostDispatchingDuration = durationOf(() -> {
+ if (!awaitLatch(losingLatch, SWITCH_TIME_LIMIT_MS)) {
+ fail(String.format("Only dispatched %d/%d onLosing callbacks in %dms",
+ NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, SWITCH_TIME_LIMIT_MS));
+ }
+ });
Log.d(TAG, String.format("Linger, %d callbacks: %dms, acceptable %dms",
- NUM_REQUESTS, timeTaken, SWITCH_TIME_LIMIT_MS));
+ NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS));
final int UNREGISTER_TIME_LIMIT_MS = 10;
- startTime = System.currentTimeMillis();
- for (int i = 0; i < NUM_REQUESTS; i++) {
- mCm.unregisterNetworkCallback(callbacks[i]);
- }
- timeTaken = System.currentTimeMillis() - startTime;
- msg = String.format("Unregister %d callbacks: %dms, acceptable %dms",
- NUM_REQUESTS, timeTaken, UNREGISTER_TIME_LIMIT_MS);
+ assertTimeLimit("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
+ for (NetworkCallback cb : callbacks) {
+ mCm.unregisterNetworkCallback(cb);
+ }
+ });
+ }
+
+ private long durationOf(Runnable fn) {
+ long startTime = SystemClock.elapsedRealtime();
+ fn.run();
+ return SystemClock.elapsedRealtime() - startTime;
+ }
+
+ private void assertTimeLimit(String descr, long timeLimit, Runnable fn) {
+ long timeTaken = durationOf(fn);
+ String msg = String.format("%s: took %dms, limit was %dms", descr, timeTaken, timeLimit);
Log.d(TAG, msg);
- assertTrue(msg, timeTaken < UNREGISTER_TIME_LIMIT_MS);
+ assertTrue(msg, timeTaken <= timeLimit);
+ }
+
+ private boolean awaitLatch(CountDownLatch l, long timeoutMs) {
+ try {
+ if (l.await(timeoutMs, TimeUnit.MILLISECONDS)) {
+ return true;
+ }
+ } catch (InterruptedException e) {}
+ return false;
}
@SmallTest
@@ -2073,7 +2167,7 @@
tracker.reevaluate();
mService.waitForIdle();
String msg = String.format("config=false, setting=%s", values[i]);
- assertTrue(msg, mService.avoidBadWifi());
+ assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
}
@@ -2082,19 +2176,19 @@
Settings.Global.putInt(cr, settingName, 0);
tracker.reevaluate();
mService.waitForIdle();
- assertFalse(mService.avoidBadWifi());
+ assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putInt(cr, settingName, 1);
tracker.reevaluate();
mService.waitForIdle();
- assertTrue(mService.avoidBadWifi());
+ assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putString(cr, settingName, null);
tracker.reevaluate();
mService.waitForIdle();
- assertFalse(mService.avoidBadWifi());
+ assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
assertTrue(tracker.shouldNotifyWifiUnvalidated());
}
@@ -2221,6 +2315,107 @@
mCm.unregisterNetworkCallback(defaultCallback);
}
+ /**
+ * Validate that a satisfied network request does not trigger onUnavailable() once the
+ * time-out period expires.
+ */
+ @SmallTest
+ public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.requestNetwork(nr, networkCallback, 10);
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+
+ // pass timeout and validate that UNAVAILABLE is not called
+ sleepFor(15);
+ networkCallback.assertNoCallback();
+ }
+
+ /**
+ * Validate that a satisfied network request followed by a disconnected (lost) network does
+ * not trigger onUnavailable() once the time-out period expires.
+ */
+ @SmallTest
+ public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() {
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.requestNetwork(nr, networkCallback, 500);
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ sleepFor(20);
+ mWiFiNetworkAgent.disconnect();
+ networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+
+ // pass timeout and validate that UNAVAILABLE is not called
+ sleepFor(600);
+ networkCallback.assertNoCallback();
+ }
+
+ /**
+ * Validate that when a time-out is specified for a network request the onUnavailable()
+ * callback is called when time-out expires. Then validate that if network request is
+ * (somehow) satisfied - the callback isn't called later.
+ */
+ @SmallTest
+ public void testTimedoutNetworkRequest() {
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.requestNetwork(nr, networkCallback, 10);
+
+ // pass timeout and validate that UNAVAILABLE is called
+ networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+
+ // create a network satisfying request - validate that request not triggered
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ networkCallback.assertNoCallback();
+ }
+
+ /**
+ * Validate that when a network request is unregistered (cancelled) the time-out for that
+ * request doesn't trigger the onUnavailable() callback.
+ */
+ @SmallTest
+ public void testTimedoutAfterUnregisteredNetworkRequest() {
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.requestNetwork(nr, networkCallback, 10);
+
+ // remove request
+ mCm.unregisterNetworkCallback(networkCallback);
+
+ // pass timeout and validate that no callbacks
+ // Note: doesn't validate that nothing called from CS since even if called the CM already
+ // unregisters the callback and won't pass it through!
+ sleepFor(15);
+ networkCallback.assertNoCallback();
+
+ // create a network satisfying request - validate that request not triggered
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ networkCallback.assertNoCallback();
+ }
+
+ public void assertEventuallyTrue(BooleanSupplier fn, long maxWaitingTimeMs) throws Exception {
+ long start = SystemClock.elapsedRealtime();
+ while (SystemClock.elapsedRealtime() <= start + maxWaitingTimeMs) {
+ if (fn.getAsBoolean()) {
+ return;
+ }
+ Thread.sleep(10);
+ }
+ assertTrue(fn.getAsBoolean());
+ }
+
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
@@ -2310,6 +2505,7 @@
return mWiFiNetworkAgent.getNetwork();
}
+ @SmallTest
public void testPacketKeepalives() throws Exception {
InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
@@ -2625,4 +2821,13 @@
mCm.unregisterNetworkCallback(pendingIntent);
}
}
+
+ /* test utilities */
+ static private void sleepFor(int ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (InterruptedException e) {
+ }
+
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
similarity index 95%
rename from services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
rename to tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index aed3635..84f0f90 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -71,7 +71,8 @@
" transport_types: 3",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -93,7 +94,8 @@
" state_transition: \"SomeState\"",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -114,7 +116,8 @@
" state_transition: \"\"",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -160,7 +163,8 @@
" return_codes: 178",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -181,7 +185,8 @@
" latency_ms: 5678",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -200,7 +205,8 @@
" if_name: \"wlan0\"",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -223,7 +229,8 @@
" >",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -248,7 +255,8 @@
" probe_result: 204",
" probe_type: 1",
" >",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -274,7 +282,8 @@
" program_length: 2048",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -305,7 +314,8 @@
" zero_lifetime_ras: 1",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
@@ -332,7 +342,8 @@
" router_lifetime: 2000",
" >",
" time_ms: 1",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, ev);
}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
similarity index 91%
rename from services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
rename to tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 3fc89b9..aa491bb 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
+import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.DhcpClientEvent;
@@ -57,7 +58,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mService = new IpConnectivityMetrics(mCtx);
+ mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
}
public void testLoggingEvents() throws Exception {
@@ -112,6 +113,27 @@
assertEquals("", output3);
}
+ public void testRateLimiting() {
+ final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
+ final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0);
+ final long fakeTimestamp = 1;
+
+ int attempt = 100; // More than burst quota, but less than buffer size.
+ for (int i = 0; i < attempt; i++) {
+ logger.log(ev);
+ }
+
+ String output1 = getdump("flush");
+ assertFalse("".equals(output1));
+
+ for (int i = 0; i < attempt; i++) {
+ assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
+ }
+
+ String output2 = getdump("flush");
+ assertEquals("", output2);
+ }
+
public void testEndToEndLogging() {
IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
@@ -204,7 +226,8 @@
" router_lifetime: 2000",
" >",
" time_ms: 700",
- ">");
+ ">",
+ "version: 2");
verifySerialization(want, getdump("flush"));
}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
similarity index 97%
rename from services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
rename to tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index bce5787e..77956be 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -24,6 +24,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
+import android.test.suitebuilder.annotation.SmallTest;
import android.text.format.DateUtils;
import com.android.internal.R;
import com.android.server.ConnectivityService;
@@ -70,6 +71,7 @@
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
}
+ @SmallTest
public void testTransitions() {
setNotificationSwitch(transition(WIFI, CELLULAR));
NetworkAgentInfo nai1 = wifiNai(100);
@@ -79,6 +81,7 @@
assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
}
+ @SmallTest
public void testNotificationOnLinger() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -89,6 +92,7 @@
verifyNotification(from, to);
}
+ @SmallTest
public void testToastOnLinger() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -99,6 +103,7 @@
verifyToast(from, to);
}
+ @SmallTest
public void testNotificationClearedAfterDisconnect() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -112,6 +117,7 @@
verify(mNotifier, times(1)).clearNotification(100);
}
+ @SmallTest
public void testNotificationClearedAfterSwitchingBack() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -125,6 +131,7 @@
verify(mNotifier, times(1)).clearNotification(100);
}
+ @SmallTest
public void testUniqueToast() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -142,6 +149,7 @@
verifyNoNotifications();
}
+ @SmallTest
public void testMultipleNotifications() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -160,6 +168,7 @@
verifyNotification(wifi2, cell);
}
+ @SmallTest
public void testRateLimiting() throws InterruptedException {
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
@@ -185,6 +194,7 @@
verifyNoNotifications();
}
+ @SmallTest
public void testDailyLimiting() throws InterruptedException {
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
@@ -211,6 +221,7 @@
verifyNoNotifications();
}
+ @SmallTest
public void testUniqueNotification() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -227,6 +238,7 @@
verifyNotification(from, to);
}
+ @SmallTest
public void testIgnoreNeverValidatedNetworks() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -238,6 +250,7 @@
verifyNoNotifications();
}
+ @SmallTest
public void testIgnoreCurrentlyValidatedNetworks() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -249,6 +262,7 @@
verifyNoNotifications();
}
+ @SmallTest
public void testNoNotificationType() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch();
@@ -259,6 +273,7 @@
verifyNoNotifications();
}
+ @SmallTest
public void testNoTransitionToNotify() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -269,6 +284,7 @@
verifyNoNotifications();
}
+ @SmallTest
public void testDifferentTransitionToNotify() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch(transition(CELLULAR, WIFI));
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
similarity index 97%
rename from services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
rename to tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
index 5f84ea1..5981f48 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/MetricsLoggerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
@@ -20,6 +20,7 @@
import android.net.ConnectivityMetricsEvent;
import android.os.Bundle;
import android.os.RemoteException;
+import android.test.suitebuilder.annotation.SmallTest;
import static android.net.ConnectivityMetricsEvent.Reference;
import junit.framework.TestCase;
@@ -67,12 +68,14 @@
mService.onStart();
}
+ @SmallTest
public void testGetNoEvents() throws Exception {
Reference r = new Reference(0);
assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
assertEquals(0, r.getValue());
}
+ @SmallTest
public void testLogAndGetEvents() throws Exception {
mService.mBinder.logEvents(EVENTS);
@@ -85,6 +88,7 @@
assertEquals(N_EVENTS, r.getValue());
}
+ @SmallTest
public void testLogOneByOne() throws Exception {
for (ConnectivityMetricsEvent ev : EVENTS) {
mService.mBinder.logEvent(ev);
@@ -99,6 +103,7 @@
assertEquals(N_EVENTS, r.getValue());
}
+ @SmallTest
public void testInterleavedLogAndGet() throws Exception {
mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
@@ -117,6 +122,7 @@
assertEquals(N_EVENTS, r.getValue());
}
+ @SmallTest
public void testMultipleGetAll() throws Exception {
mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
@@ -131,6 +137,7 @@
assertEquals(N_EVENTS, r2.getValue());
}
+ @SmallTest
public void testLogAndDumpConcurrently() throws Exception {
for (int i = 0; i < 50; i++) {
mContext = null;
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java b/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java
rename to tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
similarity index 93%
rename from services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
rename to tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 9e2fd62..2bb62bb 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -22,6 +22,8 @@
import android.net.metrics.DnsEvent;
import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
import org.junit.Before;
@@ -82,6 +84,7 @@
verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
}
+ @SmallTest
public void testOneBatch() throws Exception {
log(105, LATENCIES);
log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
@@ -96,6 +99,7 @@
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
+ @SmallTest
public void testSeveralBatches() throws Exception {
log(105, LATENCIES);
log(106, LATENCIES);
@@ -109,6 +113,7 @@
new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
+ @SmallTest
public void testBatchAndNetworkLost() throws Exception {
byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
@@ -125,6 +130,7 @@
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
+ @SmallTest
public void testConcurrentBatchesAndDumps() throws Exception {
final long stop = System.currentTimeMillis() + 100;
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
@@ -146,6 +152,7 @@
new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
+ @SmallTest
public void testConcurrentBatchesAndNetworkLoss() throws Exception {
logAsync(105, LATENCIES);
Thread.sleep(10L);
@@ -157,9 +164,13 @@
}
void log(int netId, int[] latencies) {
- for (int l : latencies) {
- mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null, 0,
- 0);
+ try {
+ for (int l : latencies) {
+ mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null,
+ 0, 0);
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/connectivity/TetheringTest.java
rename to tests/net/java/com/android/server/connectivity/TetheringTest.java
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
similarity index 77%
rename from services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
rename to tests/net/java/com/android/server/connectivity/VpnTest.java
index 5d8b843..b51b277 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -25,9 +25,11 @@
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.net.NetworkInfo.DetailedState;
import android.net.UidRange;
import android.os.INetworkManagementService;
import android.os.Looper;
@@ -43,6 +45,8 @@
import java.util.Map;
import java.util.Set;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -88,14 +92,18 @@
@Mock private PackageManager mPackageManager;
@Mock private INetworkManagementService mNetService;
@Mock private AppOpsManager mAppOps;
+ @Mock private NotificationManager mNotificationManager;
@Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
setMockedPackages(mPackages);
+ when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
+ when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
+ .thenReturn(mNotificationManager);
doNothing().when(mNetService).registerObserver(any());
}
@@ -103,7 +111,7 @@
public void testRestrictedProfilesAreAddedToVpn() {
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
@@ -117,7 +125,7 @@
public void testManagedProfilesAreNotAddedToVpn() {
setMockedUsers(primaryUser, managedProfileA);
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
@@ -130,7 +138,7 @@
public void testAddUserToVpnOnlyAddsOneUser() {
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final Set<UidRange> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
@@ -141,7 +149,7 @@
@SmallTest
public void testUidWhiteAndBlacklist() throws Exception {
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final UidRange user = UidRange.createForUser(primaryUser.id);
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
@@ -166,15 +174,15 @@
@SmallTest
public void testLockdownChangingPackage() throws Exception {
- final MockVpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final UidRange user = UidRange.createForUser(primaryUser.id);
// Default state.
- vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on without lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
- vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on with lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
@@ -182,8 +190,8 @@
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
}));
- vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
- vpn.assertUnblocked(user.start + PKG_UIDS[1]);
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[1]);
// Switch to another app.
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
@@ -195,13 +203,13 @@
new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
}));
- vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
- vpn.assertUnblocked(user.start + PKG_UIDS[3]);
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[3]);
}
@SmallTest
public void testLockdownAddingAProfile() throws Exception {
- final MockVpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
setMockedUsers(primaryUser);
// Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
@@ -220,7 +228,7 @@
}));
// Verify restricted user isn't affected at first.
- vpn.assertUnblocked(profile.start + PKG_UIDS[0]);
+ assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
// Add the restricted user.
setMockedUsers(primaryUser, tempProfile);
@@ -239,24 +247,53 @@
}));
}
+ @SmallTest
+ public void testNotificationShownForAlwaysOnApp() {
+ final Vpn vpn = spyVpn(primaryUser.id);
+ final InOrder order = inOrder(vpn);
+ setMockedUsers(primaryUser);
+
+ // Don't show a notification for regular disconnected states.
+ vpn.updateState(DetailedState.DISCONNECTED, TAG);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+
+ // Start showing a notification for disconnected once always-on.
+ vpn.setAlwaysOnPackage(PKGS[0], false);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(true);
+
+ // Stop showing the notification once connected.
+ vpn.updateState(DetailedState.CONNECTED, TAG);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+
+ // Show the notification if we disconnect again.
+ vpn.updateState(DetailedState.DISCONNECTED, TAG);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(true);
+
+ // Notification should be cleared after unsetting always-on package.
+ vpn.setAlwaysOnPackage(null, false);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+ }
+
/**
- * A subclass of {@link Vpn} with some of the fields pre-mocked.
+ * Mock some methods of vpn object.
*/
- private class MockVpn extends Vpn {
- public MockVpn(@UserIdInt int userId) {
- super(Looper.myLooper(), mContext, mNetService, userId);
- }
+ private Vpn spyVpn(@UserIdInt int userId) {
+ final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId));
- public void assertBlocked(int... uids) {
- for (int uid : uids) {
- assertTrue("Uid " + uid + " should be blocked", isBlockingUid(uid));
- }
- }
+ // Block calls to the NotificationManager or PendingIntent#getActivity.
+ doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean());
+ return vpn;
+ }
- public void assertUnblocked(int... uids) {
- for (int uid : uids) {
- assertFalse("Uid " + uid + " should not be blocked", isBlockingUid(uid));
- }
+ private static void assertBlocked(Vpn vpn, int... uids) {
+ for (int uid : uids) {
+ assertTrue("Uid " + uid + " should be blocked", vpn.isBlockingUid(uid));
+ }
+ }
+
+ private static void assertUnblocked(Vpn vpn, int... uids) {
+ for (int uid : uids) {
+ assertFalse("Uid " + uid + " should not be blocked", vpn.isBlockingUid(uid));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
similarity index 97%
rename from services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
rename to tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index a30b362..9f7261d 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -59,13 +59,14 @@
@Mock private INetworkStatsService mStatsService;
@Mock private IControlsTethering mTetherHelper;
@Mock private InterfaceConfiguration mInterfaceConfiguration;
+ @Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices;
private final TestLooper mLooper = new TestLooper();
private TetherInterfaceStateMachine mTestedSm;
private void initStateMachine(int interfaceType) throws Exception {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType,
- mNMService, mStatsService, mTetherHelper);
+ mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices);
mTestedSm.start();
// Starting the state machine always puts us in a consistent state and notifies
// the test of the world that we've changed from an unknown to available state.
@@ -91,7 +92,8 @@
@Test
public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper);
+ ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+ mIPv6TetheringInterfaceServices);
mTestedSm.start();
mLooper.dispatchAll();
verify(mTetherHelper).notifyInterfaceStateChange(
@@ -274,4 +276,4 @@
upstreamIface);
mLooper.dispatchAll();
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/jni/UidRangeTest.cpp b/tests/net/jni/UidRangeTest.cpp
similarity index 100%
rename from services/tests/servicestests/jni/UidRangeTest.cpp
rename to tests/net/jni/UidRangeTest.cpp
diff --git a/services/tests/servicestests/jni/UidRangeTest.h b/tests/net/jni/UidRangeTest.h
similarity index 100%
rename from services/tests/servicestests/jni/UidRangeTest.h
rename to tests/net/jni/UidRangeTest.h
diff --git a/services/tests/servicestests/jni/apf_jni.cpp b/tests/net/jni/apf_jni.cpp
similarity index 100%
rename from services/tests/servicestests/jni/apf_jni.cpp
rename to tests/net/jni/apf_jni.cpp
diff --git a/services/tests/servicestests/res/raw/apf.pcap b/tests/net/res/raw/apf.pcap
similarity index 100%
rename from services/tests/servicestests/res/raw/apf.pcap
rename to tests/net/res/raw/apf.pcap
Binary files differ
diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk
index d53167f..acbe4bc 100644
--- a/tests/utils/testutils/Android.mk
+++ b/tests/utils/testutils/Android.mk
@@ -27,4 +27,6 @@
android-support-test \
mockito-target
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
similarity index 89%
rename from services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
rename to tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 13657ab..27b7419 100644
--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.internal.util.test;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -25,13 +25,12 @@
import android.os.Handler;
import android.os.UserHandle;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.AbstractFuture;
-
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -42,9 +41,17 @@
public class BroadcastInterceptingContext extends ContextWrapper {
private static final String TAG = "WatchingContext";
- private final List<BroadcastInterceptor> mInterceptors = Lists.newArrayList();
+ private final List<BroadcastInterceptor> mInterceptors = new ArrayList<>();
- public class BroadcastInterceptor extends AbstractFuture<Intent> {
+ public abstract class FutureIntent extends FutureTask<Intent> {
+ public FutureIntent() {
+ super(
+ () -> { throw new IllegalStateException("Cannot happen"); }
+ );
+ }
+ }
+
+ public class BroadcastInterceptor extends FutureIntent {
private final BroadcastReceiver mReceiver;
private final IntentFilter mFilter;
@@ -82,11 +89,11 @@
super(base);
}
- public Future<Intent> nextBroadcastIntent(String action) {
+ public FutureIntent nextBroadcastIntent(String action) {
return nextBroadcastIntent(new IntentFilter(action));
}
- public Future<Intent> nextBroadcastIntent(IntentFilter filter) {
+ public FutureIntent nextBroadcastIntent(IntentFilter filter) {
final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
synchronized (mInterceptors) {
mInterceptors.add(interceptor);
diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
rename to tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java
index 808f4dd..8ca849b 100644
--- a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.util;
+package com.android.internal.util.test;
import android.net.Uri;
import android.os.Bundle;