Handle removed UIDs in network stats and policy.
When UID_REMOVED, clean up any existing UID network policy so it doesn't linger for future apps. Also move any NetworkStatsHistory to special UID_REMOVED tracking bucket. Tests for new removal code. Also test detailed UID stats, including network changes to verify template matching logic. Bug: 4584212 Change-Id: I9faadf6b6f3830eb45d86c7f1980a27cdbcdb11e
This commit is contained in:
@@ -95,9 +95,13 @@ public class NetworkIdentity {
|
||||
|
||||
final String subscriberId;
|
||||
if (isNetworkTypeMobile(type)) {
|
||||
final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
|
||||
Context.TELEPHONY_SERVICE);
|
||||
subscriberId = telephony.getSubscriberId();
|
||||
if (state.subscriberId != null) {
|
||||
subscriberId = state.subscriberId;
|
||||
} else {
|
||||
final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
|
||||
Context.TELEPHONY_SERVICE);
|
||||
subscriberId = telephony.getSubscriberId();
|
||||
}
|
||||
} else {
|
||||
subscriberId = null;
|
||||
}
|
||||
|
||||
@@ -29,18 +29,27 @@ public class NetworkState implements Parcelable {
|
||||
public final NetworkInfo networkInfo;
|
||||
public final LinkProperties linkProperties;
|
||||
public final LinkCapabilities linkCapabilities;
|
||||
/** Currently only used by testing. */
|
||||
public final String subscriberId;
|
||||
|
||||
public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
|
||||
LinkCapabilities linkCapabilities) {
|
||||
this(networkInfo, linkProperties, linkCapabilities, null);
|
||||
}
|
||||
|
||||
public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
|
||||
LinkCapabilities linkCapabilities, String subscriberId) {
|
||||
this.networkInfo = networkInfo;
|
||||
this.linkProperties = linkProperties;
|
||||
this.linkCapabilities = linkCapabilities;
|
||||
this.subscriberId = subscriberId;
|
||||
}
|
||||
|
||||
public NetworkState(Parcel in) {
|
||||
networkInfo = in.readParcelable(null);
|
||||
linkProperties = in.readParcelable(null);
|
||||
linkCapabilities = in.readParcelable(null);
|
||||
subscriberId = in.readString();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -53,6 +62,7 @@ public class NetworkState implements Parcelable {
|
||||
out.writeParcelable(networkInfo, flags);
|
||||
out.writeParcelable(linkProperties, flags);
|
||||
out.writeParcelable(linkCapabilities, flags);
|
||||
out.writeString(subscriberId);
|
||||
}
|
||||
|
||||
public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
|
||||
|
||||
@@ -41,6 +41,14 @@ public class TrafficStats {
|
||||
*/
|
||||
public final static int UNSUPPORTED = -1;
|
||||
|
||||
/**
|
||||
* Special UID value used when collecting {@link NetworkStatsHistory} for
|
||||
* removed applications.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int UID_REMOVED = -4;
|
||||
|
||||
/**
|
||||
* Snapshot of {@link NetworkStats} when the currently active profiling
|
||||
* session started, or {@code null} if no session active.
|
||||
|
||||
@@ -22,6 +22,8 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS;
|
||||
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
|
||||
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
|
||||
import static android.Manifest.permission.READ_PHONE_STATE;
|
||||
import static android.content.Intent.ACTION_UID_REMOVED;
|
||||
import static android.content.Intent.EXTRA_UID;
|
||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||
import static android.net.NetworkPolicy.LIMIT_DISABLED;
|
||||
@@ -247,9 +249,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
mContext.registerReceiver(mScreenReceiver, screenFilter);
|
||||
|
||||
// watch for network interfaces to be claimed
|
||||
final IntentFilter ifaceFilter = new IntentFilter();
|
||||
ifaceFilter.addAction(CONNECTIVITY_ACTION);
|
||||
mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
|
||||
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
|
||||
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
|
||||
|
||||
// listen for uid removal to clean policy
|
||||
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
|
||||
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
|
||||
|
||||
// listen for warning polling events; currently dispatched by
|
||||
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
|
||||
@@ -312,6 +317,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// on background handler thread, and UID_REMOVED is protected
|
||||
// broadcast.
|
||||
final int uid = intent.getIntExtra(EXTRA_UID, 0);
|
||||
synchronized (mRulesLock) {
|
||||
// remove any policy and update rules to clean up
|
||||
mUidPolicy.delete(uid);
|
||||
updateRulesForUidLocked(uid);
|
||||
writePolicyLocked();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Receiver that watches for {@link INetworkStatsService} updates, which we
|
||||
* use to check against {@link NetworkPolicy#warningBytes}.
|
||||
@@ -473,7 +493,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
* Receiver that watches for {@link IConnectivityManager} to claim network
|
||||
* interfaces. Used to apply {@link NetworkPolicy} to matching networks.
|
||||
*/
|
||||
private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
|
||||
private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// on background handler thread, and verified CONNECTIVITY_INTERNAL
|
||||
|
||||
@@ -19,11 +19,14 @@ package com.android.server.net;
|
||||
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
||||
import static android.Manifest.permission.DUMP;
|
||||
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
|
||||
import static android.Manifest.permission.SHUTDOWN;
|
||||
import static android.content.Intent.ACTION_SHUTDOWN;
|
||||
import static android.content.Intent.ACTION_UID_REMOVED;
|
||||
import static android.content.Intent.EXTRA_UID;
|
||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.TrafficStats.UID_REMOVED;
|
||||
import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
|
||||
import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
|
||||
import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
|
||||
@@ -206,17 +209,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
// watch for network interfaces to be claimed
|
||||
final IntentFilter ifaceFilter = new IntentFilter();
|
||||
ifaceFilter.addAction(CONNECTIVITY_ACTION);
|
||||
mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
|
||||
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
|
||||
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
|
||||
|
||||
// listen for periodic polling events
|
||||
final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
|
||||
mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
|
||||
|
||||
// listen for uid removal to clean stats
|
||||
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
|
||||
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
|
||||
|
||||
// persist stats during clean shutdown
|
||||
final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
|
||||
mContext.registerReceiver(mShutdownReceiver, shutdownFilter, SHUTDOWN, null);
|
||||
final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
|
||||
mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
|
||||
|
||||
try {
|
||||
registerPollAlarmLocked();
|
||||
@@ -226,8 +232,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
private void shutdownLocked() {
|
||||
mContext.unregisterReceiver(mIfaceReceiver);
|
||||
mContext.unregisterReceiver(mConnReceiver);
|
||||
mContext.unregisterReceiver(mPollReceiver);
|
||||
mContext.unregisterReceiver(mRemovedReceiver);
|
||||
mContext.unregisterReceiver(mShutdownReceiver);
|
||||
|
||||
writeNetworkStatsLocked();
|
||||
@@ -352,7 +359,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
* interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
|
||||
* with mobile interfaces.
|
||||
*/
|
||||
private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
|
||||
private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// on background handler thread, and verified CONNECTIVITY_INTERNAL
|
||||
@@ -375,10 +382,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// on background handler thread, and UID_REMOVED is protected
|
||||
// broadcast.
|
||||
final int uid = intent.getIntExtra(EXTRA_UID, 0);
|
||||
synchronized (mStatsLock) {
|
||||
removeUidLocked(uid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// verified SHUTDOWN permission above.
|
||||
// SHUTDOWN is protected broadcast.
|
||||
synchronized (mStatsLock) {
|
||||
shutdownLocked();
|
||||
}
|
||||
@@ -545,6 +564,31 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
mLastUidPoll = uidStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up {@link #mUidStats} after UID is removed.
|
||||
*/
|
||||
private void removeUidLocked(int uid) {
|
||||
ensureUidStatsLoadedLocked();
|
||||
|
||||
// migrate all UID stats into special "removed" bucket
|
||||
for (NetworkIdentitySet ident : mUidStats.keySet()) {
|
||||
final SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
|
||||
final NetworkStatsHistory uidHistory = uidStats.get(uid);
|
||||
if (uidHistory != null) {
|
||||
final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
|
||||
ident, UID_REMOVED);
|
||||
removedHistory.recordEntireHistory(uidHistory);
|
||||
uidStats.remove(uid);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: push kernel event to wipe stats for UID, otherwise we risk
|
||||
// picking them up again during next poll.
|
||||
|
||||
// since this was radical rewrite, push to disk
|
||||
writeUidStatsLocked();
|
||||
}
|
||||
|
||||
private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) {
|
||||
final long bucketDuration = mSettings.getNetworkBucketDuration();
|
||||
final NetworkStatsHistory existing = mNetworkStats.get(ident);
|
||||
@@ -568,6 +612,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
private NetworkStatsHistory findOrCreateUidStatsLocked(NetworkIdentitySet ident, int uid) {
|
||||
ensureUidStatsLoadedLocked();
|
||||
|
||||
// find bucket for identity first, then find uid
|
||||
SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
|
||||
if (uidStats == null) {
|
||||
@@ -734,6 +780,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
private void writeUidStatsLocked() {
|
||||
if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
|
||||
|
||||
if (!mUidStatsLoaded) {
|
||||
Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: consider duplicating stats and releasing lock while writing
|
||||
|
||||
FileOutputStream fos = null;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import static android.content.Intent.ACTION_UID_REMOVED;
|
||||
import static android.content.Intent.EXTRA_UID;
|
||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
import static android.net.NetworkPolicyManager.POLICY_NONE;
|
||||
@@ -386,6 +388,22 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
|
||||
verifyAndReset();
|
||||
}
|
||||
|
||||
public void testUidRemovedPolicyCleared() throws Exception {
|
||||
// POLICY_REJECT should RULE_REJECT in background
|
||||
expectRulesChanged(UID_A, RULE_REJECT_METERED);
|
||||
replay();
|
||||
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
|
||||
verifyAndReset();
|
||||
|
||||
// uninstall should clear RULE_REJECT
|
||||
expectRulesChanged(UID_A, RULE_ALLOW_ALL);
|
||||
replay();
|
||||
final Intent intent = new Intent(ACTION_UID_REMOVED);
|
||||
intent.putExtra(EXTRA_UID, UID_A);
|
||||
mServiceContext.sendBroadcast(intent);
|
||||
verifyAndReset();
|
||||
}
|
||||
|
||||
private static long parseTime(String time) {
|
||||
final Time result = new Time();
|
||||
result.parse3339(time);
|
||||
|
||||
@@ -16,11 +16,16 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import static android.content.Intent.ACTION_UID_REMOVED;
|
||||
import static android.content.Intent.EXTRA_UID;
|
||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
|
||||
import static android.net.NetworkTemplate.MATCH_WIFI;
|
||||
import static android.net.TrafficStats.UID_REMOVED;
|
||||
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
||||
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
|
||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||
@@ -46,6 +51,7 @@ import android.net.NetworkStats;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
import android.util.TrustedTime;
|
||||
@@ -67,10 +73,16 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
private static final String TEST_IFACE = "test0";
|
||||
private static final long TEST_START = 1194220800000L;
|
||||
|
||||
private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
|
||||
private static final String IMSI_1 = "310004";
|
||||
private static final String IMSI_2 = "310260";
|
||||
|
||||
private static final int TEST_UID_1 = 1001;
|
||||
private static final int TEST_UID_2 = 1002;
|
||||
private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
|
||||
private static NetworkTemplate sTemplateImsi1 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_1);
|
||||
private static NetworkTemplate sTemplateImsi2 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_2);
|
||||
|
||||
private static final int TEST_UID_RED = 1001;
|
||||
private static final int TEST_UID_BLUE = 1002;
|
||||
private static final int TEST_UID_GREEN = 1003;
|
||||
|
||||
private BroadcastInterceptingContext mServiceContext;
|
||||
private File mStatsDir;
|
||||
@@ -121,13 +133,15 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
mNetManager = null;
|
||||
mAlarmManager = null;
|
||||
mTime = null;
|
||||
mSettings = null;
|
||||
mConnManager = null;
|
||||
|
||||
mService = null;
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testSummaryStatsWifi() throws Exception {
|
||||
public void testNetworkStatsWifi() throws Exception {
|
||||
long elapsedRealtime = 0;
|
||||
|
||||
// pretend that wifi network comes online; service should ask about full
|
||||
@@ -202,16 +216,16 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
|
||||
.addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 2048L));
|
||||
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 2)
|
||||
.addEntry(TEST_IFACE, TEST_UID_1, TAG_NONE, 512L, 256L)
|
||||
.addEntry(TEST_IFACE, TEST_UID_2, TAG_NONE, 128L, 128L));
|
||||
.addEntry(TEST_IFACE, TEST_UID_RED, TAG_NONE, 512L, 256L)
|
||||
.addEntry(TEST_IFACE, TEST_UID_BLUE, TAG_NONE, 128L, 128L));
|
||||
|
||||
replay();
|
||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||
|
||||
// verify service recorded history
|
||||
assertNetworkTotal(sTemplateWifi, 1024L, 2048L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_1, 512L, 256L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_2, 128L, 128L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_RED, 512L, 256L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_BLUE, 128L, 128L);
|
||||
verifyAndReset();
|
||||
|
||||
// graceful shutdown system, which should trigger persist of stats, and
|
||||
@@ -236,8 +250,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
|
||||
// after systemReady(), we should have historical stats loaded again
|
||||
assertNetworkTotal(sTemplateWifi, 1024L, 2048L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_1, 512L, 256L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_2, 128L, 128L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_RED, 512L, 256L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_BLUE, 128L, 128L);
|
||||
verifyAndReset();
|
||||
|
||||
}
|
||||
@@ -301,6 +315,135 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
|
||||
}
|
||||
|
||||
public void testUidStatsAcrossNetworks() throws Exception {
|
||||
long elapsedRealtime = 0;
|
||||
|
||||
// pretend first mobile network comes online
|
||||
expectTime(TEST_START + elapsedRealtime);
|
||||
expectDefaultSettings();
|
||||
expectNetworkState(buildMobile3gState(IMSI_1));
|
||||
expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
|
||||
|
||||
replay();
|
||||
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
|
||||
verifyAndReset();
|
||||
|
||||
// create some traffic on first network
|
||||
elapsedRealtime += HOUR_IN_MILLIS;
|
||||
expectTime(TEST_START + elapsedRealtime);
|
||||
expectDefaultSettings();
|
||||
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
|
||||
.addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 2048L, 512L));
|
||||
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 3)
|
||||
.addEntry(TEST_IFACE, TEST_UID_RED, TAG_NONE, 1024L, 0L)
|
||||
.addEntry(TEST_IFACE, TEST_UID_RED, 0xF00D, 512L, 512L)
|
||||
.addEntry(TEST_IFACE, TEST_UID_BLUE, TAG_NONE, 512L, 0L));
|
||||
|
||||
replay();
|
||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||
|
||||
// verify service recorded history
|
||||
assertNetworkTotal(sTemplateImsi1, 2048L, 512L);
|
||||
assertNetworkTotal(sTemplateWifi, 0L, 0L);
|
||||
assertUidTotal(sTemplateImsi1, TEST_UID_RED, 1536L, 512L);
|
||||
assertUidTotal(sTemplateImsi1, TEST_UID_BLUE, 512L, 0L);
|
||||
verifyAndReset();
|
||||
|
||||
// now switch networks; this also tests that we're okay with interfaces
|
||||
// disappearing, to verify we don't count backwards.
|
||||
elapsedRealtime += HOUR_IN_MILLIS;
|
||||
expectTime(TEST_START + elapsedRealtime);
|
||||
expectDefaultSettings();
|
||||
expectNetworkState(buildMobile3gState(IMSI_2));
|
||||
expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
|
||||
expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
|
||||
|
||||
replay();
|
||||
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
|
||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||
verifyAndReset();
|
||||
|
||||
// create traffic on second network
|
||||
elapsedRealtime += HOUR_IN_MILLIS;
|
||||
expectTime(TEST_START + elapsedRealtime);
|
||||
expectDefaultSettings();
|
||||
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
|
||||
.addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 128L, 1024L));
|
||||
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
|
||||
.addEntry(TEST_IFACE, TEST_UID_BLUE, TAG_NONE, 128L, 1024L));
|
||||
|
||||
replay();
|
||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||
|
||||
// verify original history still intact
|
||||
assertNetworkTotal(sTemplateImsi1, 2048L, 512L);
|
||||
assertUidTotal(sTemplateImsi1, TEST_UID_RED, 1536L, 512L);
|
||||
assertUidTotal(sTemplateImsi1, TEST_UID_BLUE, 512L, 0L);
|
||||
|
||||
// and verify new history also recorded under different template, which
|
||||
// verifies that we didn't cross the streams.
|
||||
assertNetworkTotal(sTemplateImsi2, 128L, 1024L);
|
||||
assertNetworkTotal(sTemplateWifi, 0L, 0L);
|
||||
assertUidTotal(sTemplateImsi2, TEST_UID_BLUE, 128L, 1024L);
|
||||
verifyAndReset();
|
||||
|
||||
}
|
||||
|
||||
public void testUidRemovedIsMoved() throws Exception {
|
||||
long elapsedRealtime = 0;
|
||||
|
||||
// pretend that network comes online
|
||||
expectTime(TEST_START + elapsedRealtime);
|
||||
expectDefaultSettings();
|
||||
expectNetworkState(buildWifiState());
|
||||
expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
|
||||
|
||||
replay();
|
||||
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
|
||||
verifyAndReset();
|
||||
|
||||
// create some traffic
|
||||
elapsedRealtime += HOUR_IN_MILLIS;
|
||||
expectTime(TEST_START + elapsedRealtime);
|
||||
expectDefaultSettings();
|
||||
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
|
||||
.addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 4128L, 544L));
|
||||
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
|
||||
.addEntry(TEST_IFACE, TEST_UID_RED, TAG_NONE, 16L, 16L)
|
||||
.addEntry(TEST_IFACE, TEST_UID_BLUE, TAG_NONE, 4096L, 512L)
|
||||
.addEntry(TEST_IFACE, TEST_UID_GREEN, TAG_NONE, 16L, 16L));
|
||||
|
||||
replay();
|
||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||
|
||||
// verify service recorded history
|
||||
assertNetworkTotal(sTemplateWifi, 4128L, 544L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_RED, 16L, 16L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_BLUE, 4096L, 512L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_GREEN, 16L, 16L);
|
||||
verifyAndReset();
|
||||
|
||||
// now pretend two UIDs are uninstalled, which should migrate stats to
|
||||
// special "removed" bucket.
|
||||
expectDefaultSettings();
|
||||
replay();
|
||||
final Intent intent = new Intent(ACTION_UID_REMOVED);
|
||||
intent.putExtra(EXTRA_UID, TEST_UID_BLUE);
|
||||
mServiceContext.sendBroadcast(intent);
|
||||
intent.putExtra(EXTRA_UID, TEST_UID_RED);
|
||||
mServiceContext.sendBroadcast(intent);
|
||||
|
||||
// existing uid and total should remain unchanged; but removed UID
|
||||
// should be gone completely.
|
||||
assertNetworkTotal(sTemplateWifi, 4128L, 544L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_RED, 0L, 0L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_BLUE, 0L, 0L);
|
||||
assertUidTotal(sTemplateWifi, TEST_UID_GREEN, 16L, 16L);
|
||||
assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 528L);
|
||||
verifyAndReset();
|
||||
|
||||
}
|
||||
|
||||
private void assertNetworkTotal(NetworkTemplate template, long rx, long tx) {
|
||||
final NetworkStatsHistory history = mService.getHistoryForNetwork(template);
|
||||
final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
|
||||
@@ -360,14 +503,14 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
private void assertStatsFilesExist(boolean exist) {
|
||||
final File summaryFile = new File(mStatsDir, "netstats.bin");
|
||||
final File detailFile = new File(mStatsDir, "netstats_uid.bin");
|
||||
final File networkFile = new File(mStatsDir, "netstats.bin");
|
||||
final File uidFile = new File(mStatsDir, "netstats_uid.bin");
|
||||
if (exist) {
|
||||
assertTrue(summaryFile.exists());
|
||||
assertTrue(detailFile.exists());
|
||||
assertTrue(networkFile.exists());
|
||||
assertTrue(uidFile.exists());
|
||||
} else {
|
||||
assertFalse(summaryFile.exists());
|
||||
assertFalse(detailFile.exists());
|
||||
assertFalse(networkFile.exists());
|
||||
assertFalse(uidFile.exists());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +522,15 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
return new NetworkState(info, prop, null);
|
||||
}
|
||||
|
||||
private static NetworkState buildMobile3gState(String subscriberId) {
|
||||
final NetworkInfo info = new NetworkInfo(
|
||||
TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null);
|
||||
info.setDetailedState(DetailedState.CONNECTED, null, null);
|
||||
final LinkProperties prop = new LinkProperties();
|
||||
prop.setInterfaceName(TEST_IFACE);
|
||||
return new NetworkState(info, prop, null, subscriberId);
|
||||
}
|
||||
|
||||
private static NetworkStats buildEmptyStats(long elapsedRealtime) {
|
||||
return new NetworkStats(elapsedRealtime, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user