summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2011-06-19 22:07:41 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-06-19 22:07:41 -0700
commit7553ecbe5be1dc6c5c577d568bc1ff4f198beb33 (patch)
tree1ec77e77d64b4f1f05c8d0dcdefe29d6fb3bca8a
parent75a0e9c0f076093368ca50ac7e905a48af919f8b (diff)
parentd03fd3f004e3ba8aaa1692ee0e92e8ae171d2a04 (diff)
downloadframeworks_base-7553ecbe5be1dc6c5c577d568bc1ff4f198beb33.zip
frameworks_base-7553ecbe5be1dc6c5c577d568bc1ff4f198beb33.tar.gz
frameworks_base-7553ecbe5be1dc6c5c577d568bc1ff4f198beb33.tar.bz2
Merge "Persist "tagged" network stats along with UIDs."
-rw-r--r--core/java/android/net/INetworkStatsService.aidl4
-rw-r--r--core/java/android/provider/Settings.java2
-rw-r--r--services/java/com/android/server/NetworkManagementService.java7
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java215
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java224
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);
}