Merge changes from topic 'net-sync-aosp-with-stage-aosp' into stage-aosp-master

* changes:
  Captive portals: login activity probes like NetworkMonitor
  Logging improvements in CaptivePortalLoginActivity
  Captive portal systel log improvements
  Fix flaky IpPrefixTest.
  Removing bogus file added by mistake
  frameworks-test: adding missing @SmallTest
  Netd events: record connect() success/errno
  Add missing dependency.
  Show notification for always-on app VPN
  Implement metered tracking for NetworkStats summary queries.
  NetworkMonitor: send one DNS probe per web probe
  NetworkMonitor metrics: add first validation information
  APF: also drop any ICMPv6 RSs
  ConnectivityServiceTest: fix testAvoidBadWifiSettings
  Fix ConnectivityServiceTest testRequestBenchmark
  Switch over to new "time.android.com" NTP pool.
  Define API for metering network stats buckets.
  Refactored NetworkStatsServiceTest to use Mockito instead of EasyMock.
  Use @Ignore to explicitly disable a @Test method.
  Fixed NetworkStatsServiceTest and converted it to JUnit4.
  VPN network stat accounting changes.
  ConnectivityThread: use lazy holder idiom
  ConnectivityManager: use ConnectivityThread looper
  ConnectivityManager: a simpler CallbackHandler
  Indicate the NsdServiceInfo attributes are only filled in for a resolved service.
  Add a null check for the OnStartTetheringCallback.
  TokenBucket for rate-limiting and throttling
  IpConnectivityMetrics reads buffer size in settings
  CaptivePortalLogin: set mixed content policy to compatibility.
  Add IP conn metrics to dumpsys and bug reports
  IpConnectivity metrics: add version number
  [CS] Remove timeout event after first available
  ApfTest: tag tests with @SmallTest or @MediumTest
  Unbreak TetherInterfaceStateMachineTest.
  Move the connectivity tests to frameworks/base/tests/net.
  De-guava BroadcastInterceptingContext and move it to testutils.
  Move FakeSettingsProvider to a common location.
  ConnectivityServiceTest: mark flaky test as such
  Add option to skip and avoid captive portals.
  ApfFilter: use elapsedRealTime for RA lifetime
  Do not synchronize boolean reads/writes
  ApfFilter: systematically use u8, u16, u32 getters
  Add fuzzing tests to ApfFilter RA processing
  Support timeouts for requestNetwork() invocations.
  Silence the obnoxious MTU 0 error message that occur when no MTU is specified for a given network.
This commit is contained in:
Lorenzo Colitti
2017-01-27 00:34:13 +00:00
committed by Android (Google) Code Review
75 changed files with 2350 additions and 995 deletions

View File

@@ -45,6 +45,7 @@ LOCAL_SRC_FILES += \
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 \

View File

@@ -6448,6 +6448,7 @@ package android.app.usage {
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();
@@ -6457,6 +6458,9 @@ package android.app.usage {
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

View File

@@ -6743,6 +6743,7 @@ package android.app.usage {
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();
@@ -6752,6 +6753,9 @@ package android.app.usage {
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

View File

@@ -6457,6 +6457,7 @@ package android.app.usage {
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();
@@ -6466,6 +6467,9 @@ package android.app.usage {
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

View File

@@ -163,6 +163,29 @@ public final class NetworkStats implements AutoCloseable {
*/
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)
@@ -200,6 +223,7 @@ public final class NetworkStats implements AutoCloseable {
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 @@ public final class NetworkStats implements AutoCloseable {
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;
@@ -278,6 +311,21 @@ public final class NetworkStats implements AutoCloseable {
return mState;
}
/**
* 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>
@@ -491,6 +539,7 @@ public final class NetworkStats implements AutoCloseable {
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 @@ public final class NetworkStats implements AutoCloseable {
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 +

View File

@@ -51,16 +51,17 @@ import android.util.Log;
* {@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 @@ public class NetworkStatsManager {
/**
* 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 @@ public class NetworkStatsManager {
* 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 @@ public class NetworkStatsManager {
/**
* 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 @@ public class NetworkStatsManager {
/**
* 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

View File

@@ -222,6 +222,13 @@ public class ConnectivityManager {
*/
public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
/**
* Key for passing a user agent string to the captive portal login activity.
* {@hide}
*/
public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT =
"android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
/**
* Broadcast action to indicate the change of data activity status
* (idle or active) on a network in a recent period.
@@ -2079,6 +2086,8 @@ public class ConnectivityManager {
@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 +2098,7 @@ public class ConnectivityManager {
}
}
};
try {
mService.startTethering(type, wrappedCallback, showProvisioningUi);
} catch (RemoteException e) {
@@ -2592,7 +2602,8 @@ public class ConnectivityManager {
/**
* 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 +2667,7 @@ public class ConnectivityManager {
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 +2677,38 @@ public class ConnectivityManager {
/** @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 +2751,7 @@ public class ConnectivityManager {
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 +2759,7 @@ public class ConnectivityManager {
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 +2779,16 @@ public class ConnectivityManager {
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 +2798,14 @@ public class ConnectivityManager {
}
}
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 +2814,56 @@ public class ConnectivityManager {
}
}
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;
}
/**

View File

@@ -27,25 +27,30 @@ import android.os.Looper;
* @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();
}
}

View File

@@ -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)

View File

@@ -171,7 +171,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
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 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
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;

View File

@@ -68,11 +68,18 @@ public class NetworkStats implements Parcelable {
// 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 @@ public class NetworkStats implements Parcelable {
private int[] uid;
private int[] set;
private int[] tag;
private int[] metered;
private int[] roaming;
private long[] rxBytes;
private long[] rxPackets;
@@ -100,6 +108,12 @@ public class NetworkStats implements Parcelable {
public int uid;
public int set;
public int tag;
/**
* 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 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
@@ -123,16 +137,17 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
}
@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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
* 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 @@ public class NetworkStats implements Parcelable {
/**
* 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 @@ public class NetworkStats implements Parcelable {
* 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 @@ public class NetworkStats implements Parcelable {
}
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 class NetworkStats implements Parcelable {
*/
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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]);
@@ -829,6 +866,22 @@ public class NetworkStats implements Parcelable {
return "0x" + Integer.toHexString(tag);
}
/**
* 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.
*/
@@ -904,7 +957,8 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
* 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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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 @@ public class NetworkStats implements Parcelable {
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);
}

View File

@@ -36,8 +36,7 @@ import java.util.Arrays;
* }
* </pre>
*/
public class SntpClient
{
public class SntpClient {
private static final String TAG = "SntpClient";
private static final boolean DBG = true;
@@ -88,6 +87,7 @@ public class SntpClient
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 @@ public class SntpClient
// = (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 @@ public class SntpClient
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 {

View File

@@ -41,6 +41,15 @@ public final class NetworkEvent implements Parcelable {
public static final int NETWORK_UNLINGER = 6;
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,
@@ -50,6 +59,10 @@ public final class NetworkEvent implements Parcelable {
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 {}

View File

@@ -44,10 +44,8 @@ public final class ValidationProbeEvent implements Parcelable {
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 class ValidationProbeEvent implements Parcelable {
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;
@@ -99,9 +102,19 @@ public final class ValidationProbeEvent implements Parcelable {
}
};
/** @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 @@ public final class ValidationProbeEvent implements Parcelable {
@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"});
}
}

View File

@@ -103,11 +103,11 @@ import com.android.internal.util.Protocol;
* 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

View File

@@ -250,7 +250,8 @@ public final class NsdServiceInfo implements Parcelable {
}
/**
* 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}.

View File

@@ -7173,6 +7173,13 @@ public final class Settings {
*/
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} */
@@ -8049,11 +8056,45 @@ public final class Settings {
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";

View File

@@ -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;
}
}

View File

@@ -43,6 +43,7 @@ static struct {
jfieldID uid;
jfieldID set;
jfieldID tag;
jfieldID metered;
jfieldID roaming;
jfieldID rxBytes;
jfieldID rxPackets;
@@ -239,6 +240,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
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 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
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 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
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 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {
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");

View File

@@ -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 -->

View File

@@ -18,14 +18,14 @@ package android.net;
import android.net.IpPrefix;
import android.os.Parcel;
import static android.test.MoreAsserts.assertNotEqual;
import android.test.suitebuilder.annotation.SmallTest;
import static org.junit.Assert.assertArrayEquals;
import java.net.InetAddress;
import java.util.Random;
import junit.framework.TestCase;
import static android.test.MoreAsserts.assertNotEqual;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class IpPrefixTest extends TestCase {
@@ -242,25 +242,42 @@ public class IpPrefixTest extends TestCase {
@SmallTest
public void testHashCode() {
IpPrefix p;
int oldCode = -1;
IpPrefix p = new IpPrefix(new byte[4], 0);
Random random = new Random();
for (int i = 0; i < 100; i++) {
final IpPrefix oldP = p;
if (random.nextBoolean()) {
// IPv4.
byte[] b = new byte[4];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(33));
assertNotEqual(oldCode, p.hashCode());
oldCode = p.hashCode();
} else {
// IPv6.
byte[] b = new byte[16];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(129));
assertNotEqual(oldCode, p.hashCode());
oldCode = p.hashCode();
}
if (p.equals(oldP)) {
assertEquals(p.hashCode(), oldP.hashCode());
}
if (p.hashCode() != oldP.hashCode()) {
assertNotEqual(p, oldP);
}
}
}
@SmallTest
public void testHashCodeIsNotConstant() {
IpPrefix[] prefixes = {
new IpPrefix("2001:db8:f00::ace:d00d/127"),
new IpPrefix("192.0.2.0/23"),
new IpPrefix("::/0"),
new IpPrefix("0.0.0.0/0"),
};
for (int i = 0; i < prefixes.length; i++) {
for (int j = i + 1; j < prefixes.length; j++) {
assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
}
}
}

View File

@@ -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 @@ public class NetworkStatsTest extends TestCase {
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 @@ public class NetworkStatsTest extends TestCase {
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 @@ public class NetworkStatsTest extends TestCase {
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 @@ public class NetworkStatsTest extends TestCase {
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 @@ public class NetworkStatsTest extends TestCase {
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 @@ public class NetworkStatsTest extends TestCase {
// 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 @@ public class NetworkStatsTest extends TestCase {
.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 class NetworkStatsTest extends TestCase {
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 @@ public class NetworkStatsTest extends TestCase {
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 @@ public class NetworkStatsTest extends TestCase {
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);
}

View File

@@ -0,0 +1,180 @@
/*
* 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(); }
}

View File

@@ -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 @@ public class NetworkStatsFactoryTest extends AndroidTestCase {
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 @@ public class NetworkStatsFactoryTest extends AndroidTestCase {
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 @@ public class NetworkStatsFactoryTest extends AndroidTestCase {
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 @@ public class NetworkStatsFactoryTest extends AndroidTestCase {
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);

View File

@@ -14,6 +14,7 @@ LOCAL_SRC_FILES += src/android/util/IRemoteMemoryIntArray.aidl
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
frameworks-base-testutils \
mockito-target
LOCAL_JAVA_LIBRARIES := android.test.runner

View File

@@ -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;

View File

@@ -55,12 +55,15 @@ import java.lang.reflect.Method;
import java.util.Random;
public class CaptivePortalLoginActivity extends Activity {
private static final String TAG = "CaptivePortalLogin";
private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName();
private static final boolean DBG = true;
private static final int SOCKET_TIMEOUT_MS = 10000;
private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS };
private URL mURL;
private URL mUrl;
private String mUserAgent;
private Network mNetwork;
private CaptivePortal mCaptivePortal;
private NetworkCallback mNetworkCallback;
@@ -72,17 +75,20 @@ public class CaptivePortalLoginActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCm = ConnectivityManager.from(this);
String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
if (url == null) url = mCm.getCaptivePortalServerUrl();
try {
mURL = new URL(url);
} catch (MalformedURLException e) {
// System misconfigured, bail out in a way that at least provides network access.
Log.e(TAG, "Invalid captive portal URL, url=" + url);
done(Result.WANTED_AS_IS);
}
mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
mUserAgent = getIntent().getParcelableExtra(
ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT);
mUrl = getUrl();
if (mUrl == null) {
// getUrl() failed to parse the url provided in the intent: bail out in a way that
// at least provides network access.
done(Result.WANTED_AS_IS);
return;
}
if (DBG) {
Log.d(TAG, String.format("onCreate for %s", mUrl.toString()));
}
// Also initializes proxy system properties.
mCm.bindProcessToNetwork(mNetwork);
@@ -115,6 +121,7 @@ public class CaptivePortalLoginActivity extends Activity {
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());
@@ -148,6 +155,9 @@ public class CaptivePortalLoginActivity extends Activity {
}
private void done(Result result) {
if (DBG) {
Log.d(TAG, String.format("Result %s for %s", result.name(), mUrl.toString()));
}
if (mNetworkCallback != null) {
mCm.unregisterNetworkCallback(mNetworkCallback);
mNetworkCallback = null;
@@ -184,22 +194,31 @@ public class CaptivePortalLoginActivity extends Activity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_use_network) {
done(Result.WANTED_AS_IS);
return true;
final Result result;
final String action;
final int id = item.getItemId();
switch (id) {
case R.id.action_use_network:
result = Result.WANTED_AS_IS;
action = "USE_NETWORK";
break;
case R.id.action_do_not_use_network:
result = Result.UNWANTED;
action = "DO_NOT_USE_NETWORK";
break;
default:
return super.onOptionsItemSelected(item);
}
if (id == R.id.action_do_not_use_network) {
done(Result.UNWANTED);
return true;
if (DBG) {
Log.d(TAG, String.format("onOptionsItemSelect %s for %s", action, mUrl.toString()));
}
return super.onOptionsItemSelected(item);
done(result);
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mNetworkCallback != null) {
mCm.unregisterNetworkCallback(mNetworkCallback);
mNetworkCallback = null;
@@ -214,11 +233,29 @@ public class CaptivePortalLoginActivity extends Activity {
} catch (InterruptedException e) {
}
}
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(mURL.toString())));
final String url = mUrl.toString();
if (DBG) {
Log.d(TAG, "starting activity with intent ACTION_VIEW for " + url);
}
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
}
private URL getUrl() {
String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
if (url == null) {
url = mCm.getCaptivePortalServerUrl();
}
try {
return new URL(url);
} catch (MalformedURLException e) {
Log.e(TAG, "Invalid captive portal URL " + url);
}
return null;
}
private void testForCaptivePortal() {
// TODO: reuse NetworkMonitor facilities for consistent captive portal detection.
new Thread(new Runnable() {
public void run() {
// Give time for captive portal to open.
@@ -229,11 +266,14 @@ public class CaptivePortalLoginActivity extends Activity {
HttpURLConnection urlConnection = null;
int httpResponseCode = 500;
try {
urlConnection = (HttpURLConnection) mURL.openConnection();
urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setUseCaches(false);
if (mUserAgent != null) {
urlConnection.setRequestProperty("User-Agent", mUserAgent);
}
urlConnection.getInputStream();
httpResponseCode = urlConnection.getResponseCode();
} catch (IOException e) {
@@ -291,7 +331,7 @@ public class CaptivePortalLoginActivity extends Activity {
// settings. Now prompt the WebView read the Network-specific proxy settings.
setWebViewProxy();
// Load the real page.
view.loadUrl(mURL.toString());
view.loadUrl(mUrl.toString());
return;
} else if (mPagesLoaded == 2) {
// Prevent going back to empty first page.

View File

@@ -1804,11 +1804,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
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;
@@ -2254,11 +2257,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
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) {
@@ -2279,6 +2290,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
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:
@@ -2588,14 +2605,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
"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) {
@@ -2689,7 +2720,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
}
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
callCallbackForRequest(nri, null, whichCallback, 0);
}
@Override
@@ -2926,6 +2957,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
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;
@@ -5283,6 +5319,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// 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 {

View File

@@ -48,6 +48,10 @@ final public class IpConnectivityEventBuilder {
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);
}

View File

@@ -22,6 +22,7 @@ import android.net.IIpConnectivityMetrics;
import android.net.metrics.IpConnectivityLog;
import android.os.IBinder;
import android.os.Parcelable;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
@@ -32,6 +33,7 @@ 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 +42,19 @@ final public class IpConnectivityMetrics extends SystemService {
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;
// Lock ensuring that concurrent manipulations of the event buffer are correct.
// There are three concurrent operations to synchronize:
@@ -63,11 +74,18 @@ final public class IpConnectivityMetrics extends SystemService {
@GuardedBy("mLock")
private int mCapacity;
public IpConnectivityMetrics(Context ctx) {
private final ToIntFunction<Context> mCapacityGetter;
public IpConnectivityMetrics(Context ctx, ToIntFunction<Context> capacityGetter) {
super(ctx);
mCapacityGetter = capacityGetter;
initBuffer();
}
public IpConnectivityMetrics(Context ctx) {
this(ctx, READ_BUFFER_SIZE);
}
@Override
public void onStart() {
if (DBG) Log.d(TAG, "onStart");
@@ -86,7 +104,7 @@ final public class IpConnectivityMetrics extends SystemService {
@VisibleForTesting
public int bufferCapacity() {
return DEFAULT_BUFFER_SIZE; // TODO: read from config
return mCapacityGetter.applyAsInt(getContext());
}
private void initBuffer() {
@@ -186,6 +204,7 @@ final public class IpConnectivityMetrics extends SystemService {
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 +222,8 @@ final public class IpConnectivityMetrics extends SystemService {
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 +247,13 @@ final public class IpConnectivityMetrics extends SystemService {
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);
};
}

View File

@@ -24,6 +24,7 @@ import android.net.NetworkRequest;
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 class NetdEventListenerService extends INetdEventListener.Stub {
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 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
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 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
// 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 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
@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 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
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));
}
}

View File

@@ -80,7 +80,8 @@ import java.util.concurrent.TimeUnit;
*/
public class NetworkMonitor extends StateMachine {
private static final String TAG = NetworkMonitor.class.getSimpleName();
private static final boolean DBG = false;
private static final boolean DBG = true;
private static final boolean VDBG = false;
// Default configuration values for captive portal detection probes.
// TODO: append a random length parameter to the default HTTPS url.
@@ -96,6 +97,24 @@ public class NetworkMonitor extends StateMachine {
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 +230,12 @@ public class NetworkMonitor extends StateMachine {
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 +288,8 @@ public class NetworkMonitor extends StateMachine {
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 +310,10 @@ public class NetworkMonitor extends StateMachine {
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 +390,11 @@ public class NetworkMonitor extends StateMachine {
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
@@ -403,6 +433,8 @@ public class NetworkMonitor extends StateMachine {
}));
intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL,
mLastPortalProbeResult.detectUrl);
intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
getCaptivePortalUserAgent(mContext));
intent.setFlags(
Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
@@ -580,7 +612,8 @@ public class NetworkMonitor extends StateMachine {
@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 +633,7 @@ public class NetworkMonitor extends StateMachine {
// Retest for captive portal occasionally.
sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
mValidations++;
}
@Override
@@ -632,7 +666,10 @@ public class NetworkMonitor extends StateMachine {
@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 +709,13 @@ public class NetworkMonitor extends StateMachine {
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 +728,50 @@ public class NetworkMonitor extends StateMachine {
}
/**
* 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 +838,7 @@ public class NetworkMonitor extends StateMachine {
}
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 +858,10 @@ public class NetworkMonitor extends StateMachine {
@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.
@@ -912,7 +957,7 @@ public class NetworkMonitor extends StateMachine {
latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
} else {
if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
return;
}
break;
@@ -925,8 +970,8 @@ public class NetworkMonitor extends StateMachine {
if (cellInfo.isRegistered()) {
numRegisteredCellInfo++;
if (numRegisteredCellInfo > 1) {
log("more than one registered CellInfo. Can't " +
"tell which is active. Bailing.");
if (VDBG) logw("more than one registered CellInfo." +
" Can't tell which is active. Bailing.");
return;
}
if (cellInfo instanceof CellInfoCdma) {
@@ -942,7 +987,7 @@ public class NetworkMonitor extends StateMachine {
CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
} else {
if (DBG) logw("Registered cellinfo is unrecognized");
if (VDBG) logw("Registered cellinfo is unrecognized");
return;
}
}
@@ -967,6 +1012,22 @@ public class NetworkMonitor extends StateMachine {
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 +1036,8 @@ public class NetworkMonitor extends StateMachine {
}
private void logValidationProbe(long durationMs, int probeType, int probeResult) {
probeType =
ValidationProbeEvent.makeProbeType(probeType, validationStage().isFirstValidation);
mMetricsLog.log(new ValidationProbeEvent(mNetId, durationMs, probeType, probeResult));
}
}

View File

@@ -114,7 +114,7 @@ public class NetworkNotificationManager {
}
if (DBG) {
Slog.d(TAG, "showNotification " + notifyType
Slog.d(TAG, "showNotification id=" + id + " " + notifyType
+ " transportType=" + getTransportName(transportType)
+ " extraInfo=" + extraInfo + " highPriority=" + highPriority);
}
@@ -187,7 +187,7 @@ public class NetworkNotificationManager {
try {
mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
} catch (NullPointerException npe) {
Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe);
Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
}
}
@@ -198,7 +198,7 @@ public class NetworkNotificationManager {
try {
mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
} catch (NullPointerException npe) {
Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe);
Slog.d(TAG, "setNotificationVisible: cancel notificationManager error", npe);
}
}

View File

@@ -75,6 +75,7 @@ import com.android.internal.util.State;
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.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
@@ -1645,7 +1646,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
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();
}

View File

@@ -27,6 +27,8 @@ import android.annotation.Nullable;
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.text.TextUtils;
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 @@ public class Vpn {
/**
* 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 @@ public class Vpn {
}
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 @@ public class Vpn {
}
}
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 @@ public class Vpn {
}
}
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);

View File

@@ -45,7 +45,7 @@ import java.util.Objects;
/**
* @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 @@ class IPv6TetheringInterfaceServices {
private RouterAdvertisementDaemon mRaDaemon;
private RaParams mLastRaParams;
IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
mIfName = ifname;
mNMService = nms;
}

View File

@@ -94,14 +94,14 @@ public class TetherInterfaceStateMachine extends StateMachine {
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();

View File

@@ -91,6 +91,19 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
}
}
/** @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()) {

View File

@@ -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 @@ public class NetworkStatsCollection implements FileRotator.Reader {
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;

View File

@@ -53,6 +53,7 @@ message IpReachabilityEvent {
// 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 @@ message DHCPEvent {
// 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 @@ message ApfProgramEvent {
// 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 @@ message ApfStatistics {
// 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 @@ message IpConnectivityLog {
// 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;
};

View File

@@ -194,8 +194,10 @@ public class ApfFilter {
{ (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 @@ public class ApfFilter {
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 @@ public class ApfFilter {
} 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 @@ public class ApfFilter {
// 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 @@ public class ApfFilter {
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 @@ public class ApfFilter {
rdnssOptionToString(sb, i);
}
return sb.toString();
} catch (BufferUnderflowException | IndexOutOfBoundsException e) {
} catch (BufferUnderflowException|IndexOutOfBoundsException e) {
return "<Malformed RA>";
}
}
@@ -436,16 +444,20 @@ public class ApfFilter {
// 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 @@ public class ApfFilter {
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 @@ public class ApfFilter {
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 @@ public class ApfFilter {
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 @@ public class ApfFilter {
// 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 @@ public class ApfFilter {
// 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 @@ public class ApfFilter {
* <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 @@ public class ApfFilter {
// 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 @@ public class ApfFilter {
* 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 @@ public class ApfFilter {
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 @@ public class ApfFilter {
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));
}

View File

@@ -50,9 +50,9 @@ import java.net.NetworkInterface;
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 @@ public class IpReachabilityMonitor {
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 class IpReachabilityMonitor {
}
public void stop() {
synchronized (mLock) { mRunning = false; }
mRunning = false;
clearLinkProperties();
mNetlinkSocketObserver.clearNetlinkSocket();
}
@@ -281,12 +280,6 @@ public class IpReachabilityMonitor {
}
}
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 class IpReachabilityMonitor {
}
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 @@ public class IpReachabilityMonitor {
}
for (InetAddress target : ipProbeList) {
if (!stillRunning()) {
if (!mRunning) {
break;
}
final int returnValue = probeNeighbor(mInterfaceIndex, target);
@@ -451,21 +444,21 @@ public class IpReachabilityMonitor {
@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 @@ public class IpReachabilityMonitor {
clearNetlinkSocket();
synchronized (mLock) { mRunning = false; }
mRunning = false; // Not a no-op when ErrnoException happened.
if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
}

View File

@@ -12,12 +12,12 @@ LOCAL_MODULE_TAGS := tests
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 \

View File

@@ -24,6 +24,7 @@ import android.os.Binder;
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;

View File

@@ -78,6 +78,7 @@ import android.test.suitebuilder.annotation.Suppress;
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;

View File

@@ -25,6 +25,7 @@ import static org.mockito.Matchers.isA;
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 @@ public class NetworkStatsObserversTest extends TestCase {
// 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 @@ public class NetworkStatsObserversTest extends TestCase {
// 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 @@ public class NetworkStatsObserversTest extends TestCase {
// 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 @@ public class NetworkStatsObserversTest extends TestCase {
// 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 @@ public class NetworkStatsObserversTest extends TestCase {
// 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 @@ public class NetworkStatsObserversTest extends TestCase {
// 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 @@ public class NetworkStatsObserversTest extends TestCase {
// 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);

80
tests/net/Android.mk Normal file
View File

@@ -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)

View File

@@ -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>

View File

@@ -18,6 +18,7 @@ package android.net;
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 @@ public class ConnectivityMetricsLoggerTest extends TestCase {
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 @@ public class ConnectivityMetricsLoggerTest extends TestCase {
assertEventsEqual(expectedEvent(3), gotEvents.get(2));
}
@SmallTest
public void testLogEventTriggerThrottling() throws Exception {
when(mService.logEvent(any())).thenReturn(1234L);
@@ -70,6 +73,7 @@ public class ConnectivityMetricsLoggerTest extends TestCase {
assertEventsEqual(expectedEvent(1), gotEvents.get(0));
}
@SmallTest
public void testLogEventFails() throws Exception {
when(mService.logEvent(any())).thenReturn(-1L); // Error.
@@ -80,6 +84,7 @@ public class ConnectivityMetricsLoggerTest extends TestCase {
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 @@ public class ConnectivityMetricsLoggerTest extends TestCase {
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);

View File

@@ -26,7 +26,7 @@ import static org.junit.Assert.assertArrayEquals;
public class UidRangeTest extends TestCase {
static {
System.loadLibrary("servicestestsjni");
System.loadLibrary("frameworksnettestsjni");
}
private static native byte[] readAndWriteNative(byte[] inParcel);

View File

@@ -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.os.Parcelable;
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.InetAddress;
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 @@ public class ApfTest extends AndroidTestCase {
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 @@ public class ApfTest extends AndroidTestCase {
* 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 @@ public class ApfTest extends AndroidTestCase {
* 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 @@ public class ApfTest extends AndroidTestCase {
// 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 @@ public class ApfTest extends AndroidTestCase {
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 @@ public class ApfTest extends AndroidTestCase {
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 @@ public class ApfTest extends AndroidTestCase {
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 @@ public class ApfTest extends AndroidTestCase {
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 @@ public class ApfTest extends AndroidTestCase {
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 @@ public class ApfTest extends AndroidTestCase {
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 @@ public class ApfTest extends AndroidTestCase {
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));

View File

@@ -473,6 +473,7 @@ public class DhcpPacketTest extends TestCase {
assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
}
@SmallTest
public void testTruncatedOfferPackets() throws Exception {
final byte[] packet = HexDump.hexStringToByteArray(
// IP header.
@@ -506,6 +507,7 @@ public class DhcpPacketTest extends TestCase {
}
}
@SmallTest
public void testRandomPackets() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();

View File

@@ -24,6 +24,7 @@ import android.net.netlink.NetlinkConstants;
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 class NetlinkErrorMessageTest extends TestCase {
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.

View File

@@ -20,6 +20,7 @@ import android.net.netlink.NetlinkSocket;
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 @@ import junit.framework.TestCase;
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 @@ public class NetlinkSocketTest extends TestCase {
s.close();
}
@SmallTest
public void testRepeatedCloseCallsAreQuiet() throws Exception {
// Create a working NetlinkSocket.
NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);

View File

@@ -21,12 +21,13 @@ import android.net.netlink.NetlinkMessage;
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 class RtNetlinkNeighborMessageTest extends TestCase {
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 @@ public class RtNetlinkNeighborMessageTest extends TestCase {
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 @@ public class RtNetlinkNeighborMessageTest extends TestCase {
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 @@ public class RtNetlinkNeighborMessageTest extends TestCase {
assertEquals(14, messageCount);
}
@SmallTest
public void testCreateRtmNewNeighMessage() {
final int seqNo = 2635;
final int ifIndex = 14;

View File

@@ -68,14 +68,15 @@ import android.os.Process;
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.CountDownLatch;
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
// 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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return new Network(mNetworkAgent.netId);
}
public ConditionVariable getPreventReconnectReceived() {
return mPreventReconnectReceived;
}
public ConditionVariable getDisconnectedCV() {
return mDisconnected;
}
@@ -597,12 +618,13 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return cv;
}
@LargeTest
@SmallTest
public void testLingering() throws Exception {
verifyNoNetwork();
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -859,7 +881,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
verifyNoNetwork();
}
@LargeTest
@SmallTest
public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
// Test bringing up unvalidated WiFi
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -894,7 +916,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
verifyNoNetwork();
}
@LargeTest
@SmallTest
public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
// Test bringing up unvalidated cellular.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -920,7 +942,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
verifyNoNetwork();
}
@LargeTest
@SmallTest
public void testUnlingeringDoesNotValidate() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -948,7 +970,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NET_CAPABILITY_VALIDATED));
}
@LargeTest
@SmallTest
public void testCellularOutscoresWeakWifi() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -974,7 +996,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 @@ public class ConnectivityServiceTest extends AndroidTestCase {
waitFor(cv);
}
@LargeTest
@SmallTest
public void testCellularFallback() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1045,7 +1067,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
verifyActiveNetwork(TRANSPORT_WIFI);
}
@LargeTest
@SmallTest
public void testWiFiFallback() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1077,7 +1099,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
LOSING,
LOST
LOST,
UNAVAILABLE
}
private static class CallbackInfo {
@@ -1125,6 +1148,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
setLastCallback(CallbackState.AVAILABLE, network, null);
}
@Override
public void onUnavailable() {
setLastCallback(CallbackState.UNAVAILABLE, null, null);
}
@Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
@@ -1181,7 +1209,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
@LargeTest
@SmallTest
public void testStateChangeNetworkCallbacks() throws Exception {
final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
@@ -1564,7 +1592,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
handlerThread.quit();
}
@LargeTest
@SmallTest
public void testNetworkFactoryRequests() throws Exception {
tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
@@ -1584,7 +1612,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// 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();
@@ -1609,7 +1637,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
} catch (IllegalArgumentException expected) {}
}
@LargeTest
@SmallTest
public void testMMSonWiFi() throws Exception {
// Test bringing up cellular without MMS NetworkRequest gets reaped
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1644,7 +1672,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
verifyActiveNetwork(TRANSPORT_WIFI);
}
@LargeTest
@SmallTest
public void testMMSonCell() throws Exception {
// Test bringing up cellular without MMS
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1670,7 +1698,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
verifyActiveNetwork(TRANSPORT_CELLULAR);
}
@LargeTest
@SmallTest
public void testCaptivePortal() {
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -1719,6 +1747,47 @@ public class ConnectivityServiceTest extends AndroidTestCase {
validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
}
@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;
@@ -1749,7 +1818,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
execptionCalled);
}
@LargeTest
@SmallTest
public void testRegisterDefaultNetworkCallback() throws Exception {
final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -1810,7 +1879,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
@LargeTest
@SmallTest
public void testRequestCallbackUpdates() throws Exception {
// File a network request for mobile.
final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
@@ -1859,6 +1928,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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);
@@ -1940,6 +2014,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@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.
@@ -1953,61 +2028,80 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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
@@ -2088,7 +2182,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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());
}
@@ -2097,19 +2191,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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());
}
@@ -2236,6 +2330,107 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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 };
@@ -2325,6 +2520,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
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");
@@ -2640,4 +2836,13 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCm.unregisterNetworkCallback(pendingIntent);
}
}
/* test utilities */
static private void sleepFor(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
}
}
}

View File

@@ -71,7 +71,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" transport_types: 3",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -93,7 +94,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" state_transition: \"SomeState\"",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -114,7 +116,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" state_transition: \"\"",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -160,7 +163,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" return_codes: 178",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -181,7 +185,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" latency_ms: 5678",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -200,7 +205,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" if_name: \"wlan0\"",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -223,7 +229,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" >",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -248,7 +255,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" probe_result: 204",
" probe_type: 1",
" >",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -274,7 +282,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" program_length: 2048",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -305,7 +314,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" zero_lifetime_ras: 1",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}
@@ -332,7 +342,8 @@ public class IpConnectivityEventBuilderTest extends TestCase {
" router_lifetime: 2000",
" >",
" time_ms: 1",
">");
">",
"version: 2");
verifySerialization(want, ev);
}

View File

@@ -57,7 +57,7 @@ public class IpConnectivityMetricsTest extends TestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
mService = new IpConnectivityMetrics(mCtx);
mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
}
public void testLoggingEvents() throws Exception {
@@ -204,7 +204,8 @@ public class IpConnectivityMetricsTest extends TestCase {
" router_lifetime: 2000",
" >",
" time_ms: 700",
">");
">",
"version: 2");
verifySerialization(want, getdump("flush"));
}

View File

@@ -24,6 +24,7 @@ import android.net.Network;
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 @@ public class LingerMonitorTest extends TestCase {
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 @@ public class LingerMonitorTest extends TestCase {
assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
}
@SmallTest
public void testNotificationOnLinger() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -89,6 +92,7 @@ public class LingerMonitorTest extends TestCase {
verifyNotification(from, to);
}
@SmallTest
public void testToastOnLinger() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -99,6 +103,7 @@ public class LingerMonitorTest extends TestCase {
verifyToast(from, to);
}
@SmallTest
public void testNotificationClearedAfterDisconnect() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -112,6 +117,7 @@ public class LingerMonitorTest extends TestCase {
verify(mNotifier, times(1)).clearNotification(100);
}
@SmallTest
public void testNotificationClearedAfterSwitchingBack() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -125,6 +131,7 @@ public class LingerMonitorTest extends TestCase {
verify(mNotifier, times(1)).clearNotification(100);
}
@SmallTest
public void testUniqueToast() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
@@ -142,6 +149,7 @@ public class LingerMonitorTest extends TestCase {
verifyNoNotifications();
}
@SmallTest
public void testMultipleNotifications() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -160,6 +168,7 @@ public class LingerMonitorTest extends TestCase {
verifyNotification(wifi2, cell);
}
@SmallTest
public void testRateLimiting() throws InterruptedException {
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
@@ -185,6 +194,7 @@ public class LingerMonitorTest extends TestCase {
verifyNoNotifications();
}
@SmallTest
public void testDailyLimiting() throws InterruptedException {
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
@@ -211,6 +221,7 @@ public class LingerMonitorTest extends TestCase {
verifyNoNotifications();
}
@SmallTest
public void testUniqueNotification() {
setNotificationSwitch(transition(WIFI, CELLULAR));
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
@@ -227,6 +238,7 @@ public class LingerMonitorTest extends TestCase {
verifyNotification(from, to);
}
@SmallTest
public void testIgnoreNeverValidatedNetworks() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -238,6 +250,7 @@ public class LingerMonitorTest extends TestCase {
verifyNoNotifications();
}
@SmallTest
public void testIgnoreCurrentlyValidatedNetworks() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -249,6 +262,7 @@ public class LingerMonitorTest extends TestCase {
verifyNoNotifications();
}
@SmallTest
public void testNoNotificationType() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch();
@@ -259,6 +273,7 @@ public class LingerMonitorTest extends TestCase {
verifyNoNotifications();
}
@SmallTest
public void testNoTransitionToNotify() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
setNotificationSwitch(transition(WIFI, CELLULAR));
@@ -269,6 +284,7 @@ public class LingerMonitorTest extends TestCase {
verifyNoNotifications();
}
@SmallTest
public void testDifferentTransitionToNotify() {
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
setNotificationSwitch(transition(CELLULAR, WIFI));

View File

@@ -20,6 +20,7 @@ import android.content.Context;
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 @@ public class MetricsLoggerServiceTest extends TestCase {
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 @@ public class MetricsLoggerServiceTest extends TestCase {
assertEquals(N_EVENTS, r.getValue());
}
@SmallTest
public void testLogOneByOne() throws Exception {
for (ConnectivityMetricsEvent ev : EVENTS) {
mService.mBinder.logEvent(ev);
@@ -99,6 +103,7 @@ public class MetricsLoggerServiceTest extends TestCase {
assertEquals(N_EVENTS, r.getValue());
}
@SmallTest
public void testInterleavedLogAndGet() throws Exception {
mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
@@ -117,6 +122,7 @@ public class MetricsLoggerServiceTest extends TestCase {
assertEquals(N_EVENTS, r.getValue());
}
@SmallTest
public void testMultipleGetAll() throws Exception {
mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
@@ -131,6 +137,7 @@ public class MetricsLoggerServiceTest extends TestCase {
assertEquals(N_EVENTS, r2.getValue());
}
@SmallTest
public void testLogAndDumpConcurrently() throws Exception {
for (int i = 0; i < 50; i++) {
mContext = null;

View File

@@ -22,6 +22,8 @@ import android.net.Network;
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 @@ public class NetdEventListenerServiceTest extends TestCase {
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 @@ public class NetdEventListenerServiceTest extends TestCase {
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
@SmallTest
public void testSeveralBatches() throws Exception {
log(105, LATENCIES);
log(106, LATENCIES);
@@ -109,6 +113,7 @@ public class NetdEventListenerServiceTest extends TestCase {
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 @@ public class NetdEventListenerServiceTest extends TestCase {
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 @@ public class NetdEventListenerServiceTest extends TestCase {
new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
@SmallTest
public void testConcurrentBatchesAndNetworkLoss() throws Exception {
logAsync(105, LATENCIES);
Thread.sleep(10L);
@@ -157,9 +164,13 @@ public class NetdEventListenerServiceTest extends TestCase {
}
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();
}
}

View File

@@ -25,9 +25,11 @@ import static org.mockito.Mockito.*;
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.Arrays;
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 @@ public class VpnTest extends AndroidTestCase {
@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 class VpnTest extends AndroidTestCase {
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 class VpnTest extends AndroidTestCase {
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 class VpnTest extends AndroidTestCase {
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 @@ public class VpnTest extends AndroidTestCase {
@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 @@ public class VpnTest extends AndroidTestCase {
@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 @@ public class VpnTest extends AndroidTestCase {
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 @@ public class VpnTest extends AndroidTestCase {
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 @@ public class VpnTest extends AndroidTestCase {
}));
// 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 @@ public class VpnTest extends AndroidTestCase {
}));
}
@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));
}
}

View File

@@ -59,13 +59,14 @@ public class TetherInterfaceStateMachineTest {
@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 @@ public class TetherInterfaceStateMachineTest {
@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 @@ public class TetherInterfaceStateMachineTest {
upstreamIface);
mLooper.dispatchAll();
}
}
}

View File

@@ -28,4 +28,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
legacy-android-test \
mockito-target
LOCAL_JAVA_LIBRARIES := android.test.runner
include $(BUILD_STATIC_JAVA_LIBRARY)

View File

@@ -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.Bundle;
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 @@ import java.util.concurrent.TimeoutException;
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 @@ public class BroadcastInterceptingContext extends ContextWrapper {
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);

View File

@@ -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;