diff options
author | Jeff Sharkey <jsharkey@android.com> | 2011-06-19 22:07:41 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-06-19 22:07:41 -0700 |
commit | 7553ecbe5be1dc6c5c577d568bc1ff4f198beb33 (patch) | |
tree | 1ec77e77d64b4f1f05c8d0dcdefe29d6fb3bca8a | |
parent | 75a0e9c0f076093368ca50ac7e905a48af919f8b (diff) | |
parent | d03fd3f004e3ba8aaa1692ee0e92e8ae171d2a04 (diff) | |
download | frameworks_base-7553ecbe5be1dc6c5c577d568bc1ff4f198beb33.zip frameworks_base-7553ecbe5be1dc6c5c577d568bc1ff4f198beb33.tar.gz frameworks_base-7553ecbe5be1dc6c5c577d568bc1ff4f198beb33.tar.bz2 |
Merge "Persist "tagged" network stats along with UIDs."
5 files changed, 348 insertions, 104 deletions
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 6371500..ae9aa05 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -26,11 +26,11 @@ interface INetworkStatsService { /** Return historical stats for traffic that matches template. */ NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template); /** Return historical stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid); + NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag); /** Return usage summary for traffic that matches template. */ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return usage summary per UID for traffic that matches template. */ - NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end); + NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 01e028e7..603edf0 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3800,6 +3800,8 @@ public final class Settings { public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration"; /** {@hide} */ public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history"; + /** {@hide} */ + public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history"; /** * @hide diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index d5bdd21..d6704f4 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -965,14 +965,9 @@ class NetworkManagementService extends INetworkManagementService.Stub { final int uid = Integer.parseInt(t.nextToken()); final long rx = Long.parseLong(t.nextToken()); final long tx = Long.parseLong(t.nextToken()); - + if (limitUid == UID_ALL || limitUid == uid) { stats.addEntry(iface, uid, tag, rx, tx); - if (tag != TAG_NONE) { - // proc also counts tagged data in generic tag, so - // we subtract it here to avoid double-counting. - stats.combineEntry(iface, uid, TAG_NONE, -rx, -tx); - } } } catch (NumberFormatException e) { Slog.w(TAG, "problem parsing stats for idx " + idx + ": " + e); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 79612e3..043a581 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -31,6 +31,7 @@ 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; import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; +import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY; import static android.text.format.DateUtils.DAY_IN_MILLIS; @@ -63,9 +64,9 @@ import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; +import android.util.LongSparseArray; import android.util.NtpTrustedTime; import android.util.Slog; -import android.util.SparseArray; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; @@ -102,6 +103,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_NETWORK_INIT = 1; private static final int VERSION_UID_INIT = 1; private static final int VERSION_UID_WITH_IDENT = 2; + private static final int VERSION_UID_WITH_TAG = 3; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -122,6 +124,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: listen for kernel push events through netd instead of polling // TODO: watch for UID uninstall, and transfer stats into single bucket + // TODO: trim empty history objects entirely + private static final long KB_IN_BYTES = 1024; private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES; @@ -136,6 +140,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getNetworkMaxHistory(); public long getUidBucketDuration(); public long getUidMaxHistory(); + public long getTagMaxHistory(); public long getTimeCacheMaxAge(); } @@ -146,16 +151,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Set of historical stats for known networks. */ private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkStats = Maps.newHashMap(); /** Set of historical stats for known UIDs. */ - private HashMap<NetworkIdentitySet, SparseArray<NetworkStatsHistory>> mUidStats = + private HashMap<NetworkIdentitySet, LongSparseArray<NetworkStatsHistory>> mUidStats = Maps.newHashMap(); /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; - private NetworkStats mLastNetworkPoll; - private NetworkStats mLastNetworkPersist; + private NetworkStats mLastNetworkSnapshot; + private NetworkStats mLastPersistNetworkSnapshot; - private NetworkStats mLastUidPoll; + private NetworkStats mLastUidSnapshot; private final HandlerThread mHandlerThread; private final Handler mHandler; @@ -274,7 +279,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mNetworkStats.keySet()) { if (templateMatches(template, ident)) { final NetworkStatsHistory history = mNetworkStats.get(ident); - combined.recordEntireHistory(history); + if (history != null) { + combined.recordEntireHistory(history); + } } } return combined; @@ -282,18 +289,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid) { + public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { ensureUidStatsLoadedLocked(); + final long packed = packUidAndTag(uid, tag); // combine all interfaces that match template final NetworkStatsHistory combined = new NetworkStatsHistory( mSettings.getUidBucketDuration(), estimateUidBuckets()); for (NetworkIdentitySet ident : mUidStats.keySet()) { if (templateMatches(template, ident)) { - final NetworkStatsHistory history = mUidStats.get(ident).get(uid); + final NetworkStatsHistory history = mUidStats.get(ident).get(packed); if (history != null) { combined.recordEntireHistory(history); } @@ -329,7 +337,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStats getSummaryForAllUid(NetworkTemplate template, long start, long end) { + public NetworkStats getSummaryForAllUid( + NetworkTemplate template, long start, long end, boolean includeTags) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { @@ -340,12 +349,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mUidStats.keySet()) { if (templateMatches(template, ident)) { - final SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); + final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); for (int i = 0; i < uidStats.size(); i++) { - final int uid = uidStats.keyAt(i); - final NetworkStatsHistory history = uidStats.valueAt(i); - total = history.getTotalData(start, end, total); - stats.combineEntry(IFACE_ALL, uid, TAG_NONE, total[0], total[1]); + final long packed = uidStats.keyAt(i); + final int uid = unpackUid(packed); + final int tag = unpackTag(packed); + + // always include summary under TAG_NONE, and include + // other tags when requested. + if (tag == TAG_NONE || includeTags) { + final NetworkStatsHistory history = uidStats.valueAt(i); + total = history.getTotalData(start, end, total); + final long rx = total[0]; + final long tx = total[1]; + if (rx > 0 || tx > 0) { + stats.combineEntry(IFACE_ALL, uid, tag, rx, tx); + } + } } } } @@ -464,23 +484,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final NetworkStats ifaceStats; - final NetworkStats uidStats; + final NetworkStats networkSnapshot; + final NetworkStats uidSnapshot; try { - ifaceStats = mNetworkManager.getNetworkStatsSummary(); - uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; + networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats"); return; } - performNetworkPollLocked(ifaceStats, currentTime); + performNetworkPollLocked(networkSnapshot, currentTime); if (detailedPoll) { - performUidPollLocked(uidStats, currentTime); + performUidPollLocked(uidSnapshot, currentTime); } // decide if enough has changed to trigger persist - final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, ifaceStats); + final NetworkStats persistDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot); final long persistThreshold = mSettings.getPersistThreshold(); for (String iface : persistDelta.getUniqueIfaces()) { final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE); @@ -490,7 +511,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (mUidStatsLoaded) { writeUidStatsLocked(); } - mLastNetworkPersist = ifaceStats; + mLastPersistNetworkSnapshot = networkSnapshot; break; } } @@ -504,12 +525,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Update {@link #mNetworkStats} historical usage. */ - private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) { + private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) { final HashSet<String> unknownIface = Sets.newHashSet(); - final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats); + final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot); final long timeStart = currentTime - delta.elapsedRealtime; - final long maxHistory = mSettings.getNetworkMaxHistory(); for (int i = 0; i < delta.size; i++) { final String iface = delta.iface[i]; final NetworkIdentitySet ident = mActiveIfaces.get(iface); @@ -523,9 +543,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); history.recordData(timeStart, currentTime, rx, tx); + } + + // trim any history beyond max + final long maxHistory = mSettings.getNetworkMaxHistory(); + for (NetworkStatsHistory history : mNetworkStats.values()) { history.removeBucketsBefore(currentTime - maxHistory); } - mLastNetworkPoll = networkStats; + + mLastNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); @@ -535,15 +561,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Update {@link #mUidStats} historical usage. */ - private void performUidPollLocked(NetworkStats uidStats, long currentTime) { + private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); - final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats); + final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot); final long timeStart = currentTime - delta.elapsedRealtime; - final long maxHistory = mSettings.getUidMaxHistory(); - - // NOTE: historical UID stats ignore tags, and simply records all stats - // entries into a single UID bucket. for (int i = 0; i < delta.size; i++) { final String iface = delta.iface[i]; @@ -553,15 +575,32 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } final int uid = delta.uid[i]; + final int tag = delta.tag[i]; final long rx = delta.rx[i]; final long tx = delta.tx[i]; - final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid); + final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid, tag); history.recordData(timeStart, currentTime, rx, tx); - history.removeBucketsBefore(currentTime - maxHistory); } - mLastUidPoll = uidStats; + // trim any history beyond max + final long maxUidHistory = mSettings.getUidMaxHistory(); + final long maxTagHistory = mSettings.getTagMaxHistory(); + for (LongSparseArray<NetworkStatsHistory> uidStats : mUidStats.values()) { + for (int i = 0; i < uidStats.size(); i++) { + final long packed = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + + // detailed tags are trimmed sooner than summary in TAG_NONE + if (unpackTag(packed) == TAG_NONE) { + history.removeBucketsBefore(currentTime - maxUidHistory); + } else { + history.removeBucketsBefore(currentTime - maxTagHistory); + } + } + } + + mLastUidSnapshot = uidSnapshot; } /** @@ -572,13 +611,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // 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); + final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); + for (int i = 0; i < uidStats.size(); i++) { + final long packed = uidStats.keyAt(i); + if (unpackUid(packed) == uid) { + // only migrate combined TAG_NONE history + if (unpackTag(packed) == TAG_NONE) { + final NetworkStatsHistory uidHistory = uidStats.valueAt(i); + final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( + ident, UID_REMOVED, TAG_NONE); + removedHistory.recordEntireHistory(uidHistory); + } + uidStats.remove(packed); + } } } @@ -590,10 +635,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) { - final long bucketDuration = mSettings.getNetworkBucketDuration(); final NetworkStatsHistory existing = mNetworkStats.get(ident); // update when no existing, or when bucket duration changed + final long bucketDuration = mSettings.getNetworkBucketDuration(); NetworkStatsHistory updated = null; if (existing == null) { updated = new NetworkStatsHistory(bucketDuration, 10); @@ -611,20 +656,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private NetworkStatsHistory findOrCreateUidStatsLocked(NetworkIdentitySet ident, int uid) { + private NetworkStatsHistory findOrCreateUidStatsLocked( + NetworkIdentitySet ident, int uid, int tag) { ensureUidStatsLoadedLocked(); - // find bucket for identity first, then find uid - SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); + LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); if (uidStats == null) { - uidStats = new SparseArray<NetworkStatsHistory>(); + uidStats = new LongSparseArray<NetworkStatsHistory>(); mUidStats.put(ident, uidStats); } - final long bucketDuration = mSettings.getUidBucketDuration(); - final NetworkStatsHistory existing = uidStats.get(uid); + final long packed = packUidAndTag(uid, tag); + final NetworkStatsHistory existing = uidStats.get(packed); // update when no existing, or when bucket duration changed + final long bucketDuration = mSettings.getUidBucketDuration(); NetworkStatsHistory updated = null; if (existing == null) { updated = new NetworkStatsHistory(bucketDuration, 10); @@ -635,7 +681,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (updated != null) { - uidStats.put(uid, updated); + uidStats.put(packed, updated); return updated; } else { return existing; @@ -719,17 +765,27 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } case VERSION_UID_WITH_IDENT: { // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) + + // drop this data version, since this version only existed + // for a short time. + break; + } + case VERSION_UID_WITH_TAG: { + // uid := size *(NetworkIdentitySet size *(UID tag NetworkStatsHistory)) final int ifaceSize = in.readInt(); for (int i = 0; i < ifaceSize; i++) { final NetworkIdentitySet ident = new NetworkIdentitySet(in); - final int uidSize = in.readInt(); - final SparseArray<NetworkStatsHistory> uidStats = new SparseArray< - NetworkStatsHistory>(uidSize); - for (int j = 0; j < uidSize; j++) { + final int childSize = in.readInt(); + final LongSparseArray<NetworkStatsHistory> uidStats = new LongSparseArray< + NetworkStatsHistory>(childSize); + for (int j = 0; j < childSize; j++) { final int uid = in.readInt(); + final int tag = in.readInt(); + final long packed = packUidAndTag(uid, tag); + final NetworkStatsHistory history = new NetworkStatsHistory(in); - uidStats.put(uid, history); + uidStats.put(packed, history); } mUidStats.put(ident, uidStats); @@ -793,19 +849,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final DataOutputStream out = new DataOutputStream(fos); out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_UID_WITH_IDENT); + out.writeInt(VERSION_UID_WITH_TAG); - out.writeInt(mUidStats.size()); + final int size = mUidStats.size(); + out.writeInt(size); for (NetworkIdentitySet ident : mUidStats.keySet()) { - final SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); + final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); ident.writeToStream(out); - final int size = uidStats.size(); - out.writeInt(size); - for (int i = 0; i < size; i++) { - final int uid = uidStats.keyAt(i); + final int childSize = uidStats.size(); + out.writeInt(childSize); + for (int i = 0; i < childSize; i++) { + final long packed = uidStats.keyAt(i); + final int uid = unpackUid(packed); + final int tag = unpackTag(packed); final NetworkStatsHistory history = uidStats.valueAt(i); out.writeInt(uid); + out.writeInt(tag); history.writeToStream(out); } } @@ -864,11 +924,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mUidStats.keySet()) { pw.print(" ident="); pw.println(ident.toString()); - final SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); + final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); for (int i = 0; i < uidStats.size(); i++) { - final int uid = uidStats.keyAt(i); + final long packed = uidStats.keyAt(i); + final int uid = unpackUid(packed); + final int tag = unpackTag(packed); final NetworkStatsHistory history = uidStats.valueAt(i); - pw.print(" UID="); pw.println(uid); + pw.print(" UID="); pw.print(uid); + pw.print(" tag="); pw.println(tag); history.dump(" ", pw); } } @@ -902,7 +965,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (ApplicationInfo info : installedApps) { final int uid = info.uid; - findOrCreateUidStatsLocked(ident, uid).generateRandom( + findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom( uidStart, uidEnd, uidRx, uidTx); } } @@ -932,6 +995,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); } + // @VisibleForTesting + public static long packUidAndTag(int uid, int tag) { + final long uidLong = uid; + final long tagLong = tag; + return (uidLong << 32) | (tagLong & 0xFFFFFFFFL); + } + + // @VisibleForTesting + public static int unpackUid(long packed) { + return (int) (packed >> 32); + } + + // @VisibleForTesting + public static int unpackTag(long packed) { + return (int) (packed & 0xFFFFFFFFL); + } + /** * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} * in the given {@link NetworkIdentitySet}. @@ -978,6 +1058,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getUidMaxHistory() { return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS); } + public long getTagMaxHistory() { + return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS); + } public long getTimeCacheMaxAge() { return DAY_IN_MILLIS; } diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 2c6dbbf..636d059 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -21,6 +21,8 @@ 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.ConnectivityManager.TYPE_WIMAX; +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.NetworkTemplate.MATCH_MOBILE_ALL; @@ -31,6 +33,9 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; +import static com.android.server.net.NetworkStatsService.packUidAndTag; +import static com.android.server.net.NetworkStatsService.unpackTag; +import static com.android.server.net.NetworkStatsService.unpackUid; import static org.easymock.EasyMock.anyLong; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.eq; @@ -54,6 +59,7 @@ import android.os.INetworkManagementService; import android.telephony.TelephonyManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; import android.util.TrustedTime; import com.android.server.net.NetworkStatsService; @@ -80,9 +86,9 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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 static final int UID_RED = 1001; + private static final int UID_BLUE = 1002; + private static final int UID_GREEN = 1003; private BroadcastInterceptingContext mServiceContext; private File mStatsDir; @@ -216,16 +222,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_RED, TAG_NONE, 512L, 256L) - .addEntry(TEST_IFACE, TEST_UID_BLUE, TAG_NONE, 128L, 128L)); + .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 512L, 256L) + .addEntry(TEST_IFACE, 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_RED, 512L, 256L); - assertUidTotal(sTemplateWifi, TEST_UID_BLUE, 128L, 128L); + assertUidTotal(sTemplateWifi, UID_RED, 512L, 256L); + assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 128L); verifyAndReset(); // graceful shutdown system, which should trigger persist of stats, and @@ -250,8 +256,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // after systemReady(), we should have historical stats loaded again assertNetworkTotal(sTemplateWifi, 1024L, 2048L); - assertUidTotal(sTemplateWifi, TEST_UID_RED, 512L, 256L); - assertUidTotal(sTemplateWifi, TEST_UID_BLUE, 128L, 128L); + assertUidTotal(sTemplateWifi, UID_RED, 512L, 256L); + assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 128L); verifyAndReset(); } @@ -335,9 +341,9 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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)); + .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 1536L, 512L) + .addEntry(TEST_IFACE, UID_RED, 0xF00D, 512L, 512L) + .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 512L, 0L)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); @@ -345,8 +351,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // 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); + assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 512L); + assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 0L); verifyAndReset(); // now switch networks; this also tests that we're okay with interfaces @@ -370,21 +376,21 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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)); + .addEntry(TEST_IFACE, 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); + assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 512L); + assertUidTotal(sTemplateImsi1, 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); + assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1024L); verifyAndReset(); } @@ -409,18 +415,18 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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)); + .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 16L, 16L) + .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 4096L, 512L) + .addEntry(TEST_IFACE, 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); + assertUidTotal(sTemplateWifi, UID_RED, 16L, 16L); + assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 512L); + assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 16L); verifyAndReset(); // now pretend two UIDs are uninstalled, which should migrate stats to @@ -428,22 +434,162 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectDefaultSettings(); replay(); final Intent intent = new Intent(ACTION_UID_REMOVED); - intent.putExtra(EXTRA_UID, TEST_UID_BLUE); + intent.putExtra(EXTRA_UID, UID_BLUE); mServiceContext.sendBroadcast(intent); - intent.putExtra(EXTRA_UID, TEST_UID_RED); + intent.putExtra(EXTRA_UID, 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_RED, 0L, 0L); + assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L); + assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 16L); assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 528L); verifyAndReset(); } + public void testUid3g4gCombinedByTemplate() throws Exception { + long elapsedRealtime = 0; + + // pretend that 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 + elapsedRealtime += HOUR_IN_MILLIS; + expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime)); + expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 1024L, 1024L) + .addEntry(TEST_IFACE, UID_RED, 0xF00D, 512L, 512L)); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + + // verify service recorded history + assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 1024L); + verifyAndReset(); + + // now switch over to 4g network + elapsedRealtime += HOUR_IN_MILLIS; + expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkState(buildMobile4gState()); + 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(buildEmptyStats(elapsedRealtime)); + expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 512L, 256L)); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + + // verify that ALL_MOBILE template combines both + assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 1280L); + + verifyAndReset(); + + } + + public void testPackedUidAndTag() throws Exception { + assertEquals(0x0000000000000000L, packUidAndTag(0, 0x0)); + assertEquals(0x000003E900000000L, packUidAndTag(1001, 0x0)); + assertEquals(0x000003E90000F00DL, packUidAndTag(1001, 0xF00D)); + + long packed; + packed = packUidAndTag(Integer.MAX_VALUE, Integer.MIN_VALUE); + assertEquals(Integer.MAX_VALUE, unpackUid(packed)); + assertEquals(Integer.MIN_VALUE, unpackTag(packed)); + + packed = packUidAndTag(Integer.MIN_VALUE, Integer.MAX_VALUE); + assertEquals(Integer.MIN_VALUE, unpackUid(packed)); + assertEquals(Integer.MAX_VALUE, unpackTag(packed)); + + packed = packUidAndTag(10005, 0xFFFFFFFF); + assertEquals(10005, unpackUid(packed)); + assertEquals(0xFFFFFFFF, unpackTag(packed)); + + } + + public void testSummaryForAllUid() 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 for two apps + elapsedRealtime += HOUR_IN_MILLIS; + expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime)); + expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 50L, 50L) + .addEntry(TEST_IFACE, UID_RED, 0xF00D, 10L, 10L) + .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 1024L, 512L)); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + + // verify service recorded history + assertUidTotal(sTemplateWifi, UID_RED, 50L, 50L); + assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 512L); + verifyAndReset(); + + // now create more traffic in next hour, but only for one app + elapsedRealtime += HOUR_IN_MILLIS; + expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime)); + expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 2048L, 1024L)); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + + // first verify entire history present + NetworkStats stats = mService.getSummaryForAllUid( + sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); + assertEquals(3, stats.size); + assertStatsEntry(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 50L); + assertStatsEntry(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 10L); + assertStatsEntry(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 1024L); + + // now verify that recent history only contains one uid + final long currentTime = TEST_START + elapsedRealtime; + stats = mService.getSummaryForAllUid( + sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true); + assertEquals(1, stats.size); + assertStatsEntry(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 512L); + + 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); @@ -452,7 +598,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } private void assertUidTotal(NetworkTemplate template, int uid, long rx, long tx) { - final NetworkStatsHistory history = mService.getHistoryForUid(template, uid); + final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE); final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(rx, total[0]); assertEquals(tx, total[1]); @@ -491,6 +637,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expect(mSettings.getNetworkMaxHistory()).andReturn(maxHistory).anyTimes(); expect(mSettings.getUidBucketDuration()).andReturn(bucketDuration).anyTimes(); expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes(); + expect(mSettings.getTagMaxHistory()).andReturn(maxHistory).anyTimes(); expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes(); } @@ -514,6 +661,15 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } } + private static void assertStatsEntry( + NetworkStats stats, int i, String iface, int uid, int tag, long rx, long tx) { + assertEquals(iface, stats.iface[i]); + assertEquals(uid, stats.uid[i]); + assertEquals(tag, stats.tag[i]); + assertEquals(rx, stats.rx[i]); + assertEquals(tx, stats.tx[i]); + } + private static NetworkState buildWifiState() { final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); info.setDetailedState(DetailedState.CONNECTED, null, null); @@ -531,6 +687,14 @@ public class NetworkStatsServiceTest extends AndroidTestCase { return new NetworkState(info, prop, null, subscriberId); } + private static NetworkState buildMobile4gState() { + final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null); + info.setDetailedState(DetailedState.CONNECTED, null, null); + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(TEST_IFACE); + return new NetworkState(info, prop, null); + } + private static NetworkStats buildEmptyStats(long elapsedRealtime) { return new NetworkStats(elapsedRealtime, 0); } |