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:
committed by
Android (Google) Code Review
commit
277bd4235e
@@ -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 \
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 +
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
6
core/java/android/net/EventLogTags.logtags
Normal file
6
core/java/android/net/EventLogTags.logtags
Normal 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)
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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"});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}.
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
126
core/java/com/android/internal/util/TokenBucket.java
Normal file
126
core/java/com/android/internal/util/TokenBucket.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
180
core/tests/coretests/src/android/util/TokenBucketTest.java
Normal file
180
core/tests/coretests/src/android/util/TokenBucketTest.java
Normal 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(); }
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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."); }
|
||||
}
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
80
tests/net/Android.mk
Normal file
80
tests/net/Android.mk
Normal 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)
|
||||
57
tests/net/AndroidManifest.xml
Normal file
57
tests/net/AndroidManifest.xml
Normal 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>
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
@@ -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();
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
@@ -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));
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,4 +28,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
legacy-android-test \
|
||||
mockito-target
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||
|
||||
include $(BUILD_STATIC_JAVA_LIBRARY)
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user