Persist "tagged" network stats along with UIDs.

Now stores tags other than TAG_NONE (0x0), which are useful for app
debugging.  Combine UID and tag together into single long key, and
expose tag data through AIDL when requested.  Change NMS to track
TAG_NONE as total UID traffic, matching the kernel definition.

Added TAG_MAX_HISTORY to control how long tag-granularity statistics
are stored; overall UID usage is still kept for UID_MAX_HISTORY.  Fix
bug to trim NetworkStatsHistory outside normal polling loops to catch
non-active networks and UIDs.

Test to verify UID and tag packing, and to verify that UID traffic on
two networks are combined to match MOBILE_ALL template.

Change-Id: If0e039416d9e7f63b1a39e04cddfb1133b5a78ee
This commit is contained in:
Jeff Sharkey
2011-06-19 20:55:09 -07:00
parent c04cda602c
commit b590477065
2 changed files with 151 additions and 68 deletions

View File

@@ -26,11 +26,11 @@ interface INetworkStatsService {
/** Return historical stats for traffic that matches template. */ /** Return historical stats for traffic that matches template. */
NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template); NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template);
/** Return historical stats for specific UID traffic that matches 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. */ /** Return usage summary for traffic that matches template. */
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
/** Return usage summary per UID for traffic that matches template. */ /** 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);
} }

View File

@@ -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_NETWORK_MAX_HISTORY;
import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; 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_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_BUCKET_DURATION;
import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -63,9 +64,9 @@ import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
import android.provider.Settings; import android.provider.Settings;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.util.LongSparseArray;
import android.util.NtpTrustedTime; import android.util.NtpTrustedTime;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray;
import android.util.TrustedTime; import android.util.TrustedTime;
import com.android.internal.os.AtomicFile; 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_NETWORK_INIT = 1;
private static final int VERSION_UID_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_IDENT = 2;
private static final int VERSION_UID_WITH_TAG = 3;
private final Context mContext; private final Context mContext;
private final INetworkManagementService mNetworkManager; 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: listen for kernel push events through netd instead of polling
// TODO: watch for UID uninstall, and transfer stats into single bucket // 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 KB_IN_BYTES = 1024;
private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
private static final long GB_IN_BYTES = 1024 * MB_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 getNetworkMaxHistory();
public long getUidBucketDuration(); public long getUidBucketDuration();
public long getUidMaxHistory(); public long getUidMaxHistory();
public long getTagMaxHistory();
public long getTimeCacheMaxAge(); public long getTimeCacheMaxAge();
} }
@@ -146,16 +151,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/** Set of historical stats for known networks. */ /** Set of historical stats for known networks. */
private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkStats = Maps.newHashMap(); private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
/** Set of historical stats for known UIDs. */ /** Set of historical stats for known UIDs. */
private HashMap<NetworkIdentitySet, SparseArray<NetworkStatsHistory>> mUidStats = private HashMap<NetworkIdentitySet, LongSparseArray<NetworkStatsHistory>> mUidStats =
Maps.newHashMap(); Maps.newHashMap();
/** Flag if {@link #mUidStats} have been loaded from disk. */ /** Flag if {@link #mUidStats} have been loaded from disk. */
private boolean mUidStatsLoaded = false; private boolean mUidStatsLoaded = false;
private NetworkStats mLastNetworkPoll; private NetworkStats mLastNetworkSnapshot;
private NetworkStats mLastNetworkPersist; private NetworkStats mLastPersistNetworkSnapshot;
private NetworkStats mLastUidPoll; private NetworkStats mLastUidSnapshot;
private final HandlerThread mHandlerThread; private final HandlerThread mHandlerThread;
private final Handler mHandler; private final Handler mHandler;
@@ -274,7 +279,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
for (NetworkIdentitySet ident : mNetworkStats.keySet()) { for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
if (templateMatches(template, ident)) { if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mNetworkStats.get(ident); final NetworkStatsHistory history = mNetworkStats.get(ident);
combined.recordEntireHistory(history); if (history != null) {
combined.recordEntireHistory(history);
}
} }
} }
return combined; return combined;
@@ -282,18 +289,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} }
@Override @Override
public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid) { public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) { synchronized (mStatsLock) {
ensureUidStatsLoadedLocked(); ensureUidStatsLoadedLocked();
final long packed = packUidAndTag(uid, tag);
// combine all interfaces that match template // combine all interfaces that match template
final NetworkStatsHistory combined = new NetworkStatsHistory( final NetworkStatsHistory combined = new NetworkStatsHistory(
mSettings.getUidBucketDuration(), estimateUidBuckets()); mSettings.getUidBucketDuration(), estimateUidBuckets());
for (NetworkIdentitySet ident : mUidStats.keySet()) { for (NetworkIdentitySet ident : mUidStats.keySet()) {
if (templateMatches(template, ident)) { if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mUidStats.get(ident).get(uid); final NetworkStatsHistory history = mUidStats.get(ident).get(packed);
if (history != null) { if (history != null) {
combined.recordEntireHistory(history); combined.recordEntireHistory(history);
} }
@@ -329,7 +337,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} }
@Override @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); mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) { synchronized (mStatsLock) {
@@ -340,12 +349,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
for (NetworkIdentitySet ident : mUidStats.keySet()) { for (NetworkIdentitySet ident : mUidStats.keySet()) {
if (templateMatches(template, ident)) { 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++) { for (int i = 0; i < uidStats.size(); i++) {
final int uid = uidStats.keyAt(i); final long packed = uidStats.keyAt(i);
final NetworkStatsHistory history = uidStats.valueAt(i); final int uid = unpackUid(packed);
total = history.getTotalData(start, end, total); final int tag = unpackTag(packed);
stats.combineEntry(IFACE_ALL, uid, TAG_NONE, total[0], total[1]);
// 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() final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis(); : System.currentTimeMillis();
final NetworkStats ifaceStats; final NetworkStats networkSnapshot;
final NetworkStats uidStats; final NetworkStats uidSnapshot;
try { try {
ifaceStats = mNetworkManager.getNetworkStatsSummary(); networkSnapshot = mNetworkManager.getNetworkStatsSummary();
uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null;
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "problem reading network stats"); Slog.w(TAG, "problem reading network stats");
return; return;
} }
performNetworkPollLocked(ifaceStats, currentTime); performNetworkPollLocked(networkSnapshot, currentTime);
if (detailedPoll) { if (detailedPoll) {
performUidPollLocked(uidStats, currentTime); performUidPollLocked(uidSnapshot, currentTime);
} }
// decide if enough has changed to trigger persist // 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(); final long persistThreshold = mSettings.getPersistThreshold();
for (String iface : persistDelta.getUniqueIfaces()) { for (String iface : persistDelta.getUniqueIfaces()) {
final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE); final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE);
@@ -490,7 +511,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
if (mUidStatsLoaded) { if (mUidStatsLoaded) {
writeUidStatsLocked(); writeUidStatsLocked();
} }
mLastNetworkPersist = ifaceStats; mLastPersistNetworkSnapshot = networkSnapshot;
break; break;
} }
} }
@@ -504,12 +525,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/** /**
* Update {@link #mNetworkStats} historical usage. * 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 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 timeStart = currentTime - delta.elapsedRealtime;
final long maxHistory = mSettings.getNetworkMaxHistory();
for (int i = 0; i < delta.size; i++) { for (int i = 0; i < delta.size; i++) {
final String iface = delta.iface[i]; final String iface = delta.iface[i];
final NetworkIdentitySet ident = mActiveIfaces.get(iface); final NetworkIdentitySet ident = mActiveIfaces.get(iface);
@@ -523,9 +543,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident);
history.recordData(timeStart, currentTime, rx, tx); 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); history.removeBucketsBefore(currentTime - maxHistory);
} }
mLastNetworkPoll = networkStats;
mLastNetworkSnapshot = networkSnapshot;
if (LOGD && unknownIface.size() > 0) { if (LOGD && unknownIface.size() > 0) {
Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); 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. * Update {@link #mUidStats} historical usage.
*/ */
private void performUidPollLocked(NetworkStats uidStats, long currentTime) { private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
ensureUidStatsLoadedLocked(); ensureUidStatsLoadedLocked();
final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats); final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot);
final long timeStart = currentTime - delta.elapsedRealtime; 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++) { for (int i = 0; i < delta.size; i++) {
final String iface = delta.iface[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 uid = delta.uid[i];
final int tag = delta.tag[i];
final long rx = delta.rx[i]; final long rx = delta.rx[i];
final long tx = delta.tx[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.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 // migrate all UID stats into special "removed" bucket
for (NetworkIdentitySet ident : mUidStats.keySet()) { for (NetworkIdentitySet ident : mUidStats.keySet()) {
final SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
final NetworkStatsHistory uidHistory = uidStats.get(uid); for (int i = 0; i < uidStats.size(); i++) {
if (uidHistory != null) { final long packed = uidStats.keyAt(i);
final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( if (unpackUid(packed) == uid) {
ident, UID_REMOVED); // only migrate combined TAG_NONE history
removedHistory.recordEntireHistory(uidHistory); if (unpackTag(packed) == TAG_NONE) {
uidStats.remove(uid); 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) { private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) {
final long bucketDuration = mSettings.getNetworkBucketDuration();
final NetworkStatsHistory existing = mNetworkStats.get(ident); final NetworkStatsHistory existing = mNetworkStats.get(ident);
// update when no existing, or when bucket duration changed // update when no existing, or when bucket duration changed
final long bucketDuration = mSettings.getNetworkBucketDuration();
NetworkStatsHistory updated = null; NetworkStatsHistory updated = null;
if (existing == null) { if (existing == null) {
updated = new NetworkStatsHistory(bucketDuration, 10); 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(); ensureUidStatsLoadedLocked();
// find bucket for identity first, then find uid LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
if (uidStats == null) { if (uidStats == null) {
uidStats = new SparseArray<NetworkStatsHistory>(); uidStats = new LongSparseArray<NetworkStatsHistory>();
mUidStats.put(ident, uidStats); mUidStats.put(ident, uidStats);
} }
final long bucketDuration = mSettings.getUidBucketDuration(); final long packed = packUidAndTag(uid, tag);
final NetworkStatsHistory existing = uidStats.get(uid); final NetworkStatsHistory existing = uidStats.get(packed);
// update when no existing, or when bucket duration changed // update when no existing, or when bucket duration changed
final long bucketDuration = mSettings.getUidBucketDuration();
NetworkStatsHistory updated = null; NetworkStatsHistory updated = null;
if (existing == null) { if (existing == null) {
updated = new NetworkStatsHistory(bucketDuration, 10); updated = new NetworkStatsHistory(bucketDuration, 10);
@@ -635,7 +681,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} }
if (updated != null) { if (updated != null) {
uidStats.put(uid, updated); uidStats.put(packed, updated);
return updated; return updated;
} else { } else {
return existing; return existing;
@@ -719,17 +765,27 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} }
case VERSION_UID_WITH_IDENT: { case VERSION_UID_WITH_IDENT: {
// uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) // 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(); final int ifaceSize = in.readInt();
for (int i = 0; i < ifaceSize; i++) { for (int i = 0; i < ifaceSize; i++) {
final NetworkIdentitySet ident = new NetworkIdentitySet(in); final NetworkIdentitySet ident = new NetworkIdentitySet(in);
final int uidSize = in.readInt(); final int childSize = in.readInt();
final SparseArray<NetworkStatsHistory> uidStats = new SparseArray< final LongSparseArray<NetworkStatsHistory> uidStats = new LongSparseArray<
NetworkStatsHistory>(uidSize); NetworkStatsHistory>(childSize);
for (int j = 0; j < uidSize; j++) { for (int j = 0; j < childSize; j++) {
final int uid = in.readInt(); final int uid = in.readInt();
final int tag = in.readInt();
final long packed = packUidAndTag(uid, tag);
final NetworkStatsHistory history = new NetworkStatsHistory(in); final NetworkStatsHistory history = new NetworkStatsHistory(in);
uidStats.put(uid, history); uidStats.put(packed, history);
} }
mUidStats.put(ident, uidStats); mUidStats.put(ident, uidStats);
@@ -793,19 +849,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final DataOutputStream out = new DataOutputStream(fos); final DataOutputStream out = new DataOutputStream(fos);
out.writeInt(FILE_MAGIC); 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()) { for (NetworkIdentitySet ident : mUidStats.keySet()) {
final SparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident); final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
ident.writeToStream(out); ident.writeToStream(out);
final int size = uidStats.size(); final int childSize = uidStats.size();
out.writeInt(size); out.writeInt(childSize);
for (int i = 0; i < size; i++) { for (int i = 0; i < childSize; 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); final NetworkStatsHistory history = uidStats.valueAt(i);
out.writeInt(uid); out.writeInt(uid);
out.writeInt(tag);
history.writeToStream(out); history.writeToStream(out);
} }
} }
@@ -864,11 +924,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
for (NetworkIdentitySet ident : mUidStats.keySet()) { for (NetworkIdentitySet ident : mUidStats.keySet()) {
pw.print(" ident="); pw.println(ident.toString()); 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++) { 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); 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); history.dump(" ", pw);
} }
} }
@@ -902,7 +965,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
for (ApplicationInfo info : installedApps) { for (ApplicationInfo info : installedApps) {
final int uid = info.uid; final int uid = info.uid;
findOrCreateUidStatsLocked(ident, uid).generateRandom( findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(
uidStart, uidEnd, uidRx, uidTx); uidStart, uidEnd, uidRx, uidTx);
} }
} }
@@ -932,6 +995,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); 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} * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
* in the given {@link NetworkIdentitySet}. * in the given {@link NetworkIdentitySet}.
@@ -978,6 +1058,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public long getUidMaxHistory() { public long getUidMaxHistory() {
return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS); 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() { public long getTimeCacheMaxAge() {
return DAY_IN_MILLIS; return DAY_IN_MILLIS;
} }