Merge "Foreground/background network stats using sets."
This commit is contained in:
@@ -26,7 +26,7 @@ interface INetworkStatsService {
|
||||
/** Return historical network layer stats for traffic that matches template. */
|
||||
NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
|
||||
/** Return historical network layer stats for specific UID traffic that matches template. */
|
||||
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag, int fields);
|
||||
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
|
||||
|
||||
/** Return network layer usage summary for traffic that matches template. */
|
||||
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
|
||||
@@ -38,6 +38,8 @@ interface INetworkStatsService {
|
||||
/** Increment data layer count of operations performed for UID and tag. */
|
||||
void incrementOperationCount(int uid, int tag, int operationCount);
|
||||
|
||||
/** Mark given UID as being in foreground for stats purposes. */
|
||||
void setUidForeground(int uid, boolean uidForeground);
|
||||
/** Force update of statistics. */
|
||||
void forceUpdate();
|
||||
|
||||
|
||||
@@ -42,7 +42,13 @@ public class NetworkStats implements Parcelable {
|
||||
public static final String IFACE_ALL = null;
|
||||
/** {@link #uid} value when UID details unavailable. */
|
||||
public static final int UID_ALL = -1;
|
||||
/** {@link #tag} value for without tag. */
|
||||
/** {@link #set} value when all sets combined. */
|
||||
public static final int SET_ALL = -1;
|
||||
/** {@link #set} value where background data is accounted. */
|
||||
public static final int SET_DEFAULT = 0;
|
||||
/** {@link #set} value where foreground data is accounted. */
|
||||
public static final int SET_FOREGROUND = 1;
|
||||
/** {@link #tag} value for total data across all tags. */
|
||||
public static final int TAG_NONE = 0;
|
||||
|
||||
/**
|
||||
@@ -53,6 +59,7 @@ public class NetworkStats implements Parcelable {
|
||||
private int size;
|
||||
private String[] iface;
|
||||
private int[] uid;
|
||||
private int[] set;
|
||||
private int[] tag;
|
||||
private long[] rxBytes;
|
||||
private long[] rxPackets;
|
||||
@@ -63,6 +70,7 @@ public class NetworkStats implements Parcelable {
|
||||
public static class Entry {
|
||||
public String iface;
|
||||
public int uid;
|
||||
public int set;
|
||||
public int tag;
|
||||
public long rxBytes;
|
||||
public long rxPackets;
|
||||
@@ -71,17 +79,19 @@ public class NetworkStats implements Parcelable {
|
||||
public long operations;
|
||||
|
||||
public Entry() {
|
||||
this(IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
}
|
||||
|
||||
public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
|
||||
this(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, operations);
|
||||
this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
|
||||
operations);
|
||||
}
|
||||
|
||||
public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes,
|
||||
long txPackets, long operations) {
|
||||
public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
|
||||
long txBytes, long txPackets, long operations) {
|
||||
this.iface = iface;
|
||||
this.uid = uid;
|
||||
this.set = set;
|
||||
this.tag = tag;
|
||||
this.rxBytes = rxBytes;
|
||||
this.rxPackets = rxPackets;
|
||||
@@ -96,6 +106,7 @@ public class NetworkStats implements Parcelable {
|
||||
this.size = 0;
|
||||
this.iface = new String[initialSize];
|
||||
this.uid = new int[initialSize];
|
||||
this.set = new int[initialSize];
|
||||
this.tag = new int[initialSize];
|
||||
this.rxBytes = new long[initialSize];
|
||||
this.rxPackets = new long[initialSize];
|
||||
@@ -109,6 +120,7 @@ public class NetworkStats implements Parcelable {
|
||||
size = parcel.readInt();
|
||||
iface = parcel.createStringArray();
|
||||
uid = parcel.createIntArray();
|
||||
set = parcel.createIntArray();
|
||||
tag = parcel.createIntArray();
|
||||
rxBytes = parcel.createLongArray();
|
||||
rxPackets = parcel.createLongArray();
|
||||
@@ -123,6 +135,7 @@ public class NetworkStats implements Parcelable {
|
||||
dest.writeInt(size);
|
||||
dest.writeStringArray(iface);
|
||||
dest.writeIntArray(uid);
|
||||
dest.writeIntArray(set);
|
||||
dest.writeIntArray(tag);
|
||||
dest.writeLongArray(rxBytes);
|
||||
dest.writeLongArray(rxPackets);
|
||||
@@ -131,15 +144,18 @@ public class NetworkStats implements Parcelable {
|
||||
dest.writeLongArray(operations);
|
||||
}
|
||||
|
||||
public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
|
||||
long txBytes, long txPackets) {
|
||||
return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0L);
|
||||
// @VisibleForTesting
|
||||
public NetworkStats addIfaceValues(
|
||||
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
|
||||
return addValues(
|
||||
iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
|
||||
}
|
||||
|
||||
public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
|
||||
long txBytes, long txPackets, long operations) {
|
||||
return addValues(
|
||||
new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
|
||||
// @VisibleForTesting
|
||||
public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
|
||||
long rxPackets, long txBytes, long txPackets, long operations) {
|
||||
return addValues(new Entry(
|
||||
iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,6 +167,7 @@ public class NetworkStats implements Parcelable {
|
||||
final int newLength = Math.max(iface.length, 10) * 3 / 2;
|
||||
iface = Arrays.copyOf(iface, newLength);
|
||||
uid = Arrays.copyOf(uid, newLength);
|
||||
set = Arrays.copyOf(set, newLength);
|
||||
tag = Arrays.copyOf(tag, newLength);
|
||||
rxBytes = Arrays.copyOf(rxBytes, newLength);
|
||||
rxPackets = Arrays.copyOf(rxPackets, newLength);
|
||||
@@ -161,6 +178,7 @@ public class NetworkStats implements Parcelable {
|
||||
|
||||
iface[size] = entry.iface;
|
||||
uid[size] = entry.uid;
|
||||
set[size] = entry.set;
|
||||
tag[size] = entry.tag;
|
||||
rxBytes[size] = entry.rxBytes;
|
||||
rxPackets[size] = entry.rxPackets;
|
||||
@@ -179,6 +197,7 @@ public class NetworkStats implements Parcelable {
|
||||
final Entry entry = recycle != null ? recycle : new Entry();
|
||||
entry.iface = iface[i];
|
||||
entry.uid = uid[i];
|
||||
entry.set = set[i];
|
||||
entry.tag = tag[i];
|
||||
entry.rxBytes = rxBytes[i];
|
||||
entry.rxPackets = rxPackets[i];
|
||||
@@ -201,19 +220,26 @@ public class NetworkStats implements Parcelable {
|
||||
return iface.length;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
|
||||
long txBytes, long txPackets, long operations) {
|
||||
return combineValues(
|
||||
new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
|
||||
iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
|
||||
}
|
||||
|
||||
public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
|
||||
long rxPackets, long txBytes, long txPackets, long operations) {
|
||||
return combineValues(new Entry(
|
||||
iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine given values with an existing row, or create a new row if
|
||||
* {@link #findIndex(String, int, int)} is unable to find match. Can also be
|
||||
* used to subtract values from existing rows.
|
||||
* {@link #findIndex(String, int, int, int)} is unable to find match. Can
|
||||
* also be used to subtract values from existing rows.
|
||||
*/
|
||||
public NetworkStats combineValues(Entry entry) {
|
||||
final int i = findIndex(entry.iface, entry.uid, entry.tag);
|
||||
final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
|
||||
if (i == -1) {
|
||||
// only create new entry when positive contribution
|
||||
addValues(entry);
|
||||
@@ -230,9 +256,10 @@ public class NetworkStats implements Parcelable {
|
||||
/**
|
||||
* Find first stats index that matches the requested parameters.
|
||||
*/
|
||||
public int findIndex(String iface, int uid, int tag) {
|
||||
public int findIndex(String iface, int uid, int set, int tag) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (Objects.equal(iface, this.iface[i]) && uid == this.uid[i] && tag == this.tag[i]) {
|
||||
if (Objects.equal(iface, this.iface[i]) && uid == this.uid[i] && set == this.set[i]
|
||||
&& tag == this.tag[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -246,7 +273,7 @@ public class NetworkStats implements Parcelable {
|
||||
*/
|
||||
public void spliceOperationsFrom(NetworkStats stats) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
final int j = stats.findIndex(IFACE_ALL, uid[i], tag[i]);
|
||||
final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
|
||||
if (j == -1) {
|
||||
operations[i] = 0;
|
||||
} else {
|
||||
@@ -332,10 +359,11 @@ public class NetworkStats implements Parcelable {
|
||||
for (int i = 0; i < size; i++) {
|
||||
entry.iface = iface[i];
|
||||
entry.uid = uid[i];
|
||||
entry.set = set[i];
|
||||
entry.tag = tag[i];
|
||||
|
||||
// find remote row that matches, and subtract
|
||||
final int j = value.findIndex(entry.iface, entry.uid, entry.tag);
|
||||
final int j = value.findIndex(entry.iface, entry.uid, entry.set, entry.tag);
|
||||
if (j == -1) {
|
||||
// newly appearing row, return entire value
|
||||
entry.rxBytes = rxBytes[i];
|
||||
@@ -377,7 +405,8 @@ public class NetworkStats implements Parcelable {
|
||||
pw.print(prefix);
|
||||
pw.print(" iface="); pw.print(iface[i]);
|
||||
pw.print(" uid="); pw.print(uid[i]);
|
||||
pw.print(" tag=0x"); pw.print(Integer.toHexString(tag[i]));
|
||||
pw.print(" set="); pw.print(setToString(set[i]));
|
||||
pw.print(" tag="); pw.print(tagToString(tag[i]));
|
||||
pw.print(" rxBytes="); pw.print(rxBytes[i]);
|
||||
pw.print(" rxPackets="); pw.print(rxPackets[i]);
|
||||
pw.print(" txBytes="); pw.print(txBytes[i]);
|
||||
@@ -386,6 +415,29 @@ public class NetworkStats implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return text description of {@link #set} value.
|
||||
*/
|
||||
public static String setToString(int set) {
|
||||
switch (set) {
|
||||
case SET_ALL:
|
||||
return "ALL";
|
||||
case SET_DEFAULT:
|
||||
return "DEFAULT";
|
||||
case SET_FOREGROUND:
|
||||
return "FOREGROUND";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return text description of {@link #tag} value.
|
||||
*/
|
||||
public static String tagToString(int tag) {
|
||||
return "0x" + Integer.toHexString(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final CharArrayWriter writer = new CharArrayWriter();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.net;
|
||||
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.SET_DEFAULT;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
|
||||
@@ -215,8 +216,8 @@ public class NetworkStatsHistory implements Parcelable {
|
||||
*/
|
||||
@Deprecated
|
||||
public void recordData(long start, long end, long rxBytes, long txBytes) {
|
||||
recordData(start, end,
|
||||
new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
|
||||
recordData(start, end, new NetworkStats.Entry(
|
||||
IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +270,7 @@ public class NetworkStatsHistory implements Parcelable {
|
||||
*/
|
||||
public void recordEntireHistory(NetworkStatsHistory input) {
|
||||
final NetworkStats.Entry entry = new NetworkStats.Entry(
|
||||
IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
for (int i = 0; i < input.bucketCount; i++) {
|
||||
final long start = input.bucketStart[i];
|
||||
final long end = start + input.bucketDuration;
|
||||
@@ -422,7 +423,7 @@ public class NetworkStatsHistory implements Parcelable {
|
||||
ensureBuckets(start, end);
|
||||
|
||||
final NetworkStats.Entry entry = new NetworkStats.Entry(
|
||||
IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
|
||||
final Random r = new Random();
|
||||
while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
|
||||
|| operations > 32) {
|
||||
|
||||
@@ -205,10 +205,6 @@ public class TrafficStats {
|
||||
* @param operationCount Number of operations to increment count by.
|
||||
*/
|
||||
public static void incrementOperationCount(int tag, int operationCount) {
|
||||
if (operationCount < 0) {
|
||||
throw new IllegalArgumentException("operation count can only be incremented");
|
||||
}
|
||||
|
||||
final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
|
||||
final int uid = android.os.Process.myUid();
|
||||
|
||||
@@ -26,6 +26,9 @@ import static android.content.Intent.ACTION_UID_REMOVED;
|
||||
import static android.content.Intent.EXTRA_UID;
|
||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.SET_ALL;
|
||||
import static android.net.NetworkStats.SET_DEFAULT;
|
||||
import static android.net.NetworkStats.SET_FOREGROUND;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.TrafficStats.UID_REMOVED;
|
||||
@@ -40,6 +43,8 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
||||
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
|
||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
|
||||
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.IAlarmManager;
|
||||
@@ -63,17 +68,20 @@ import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
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.SparseIntArray;
|
||||
import android.util.TrustedTime;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.Objects;
|
||||
import com.google.android.collect.Lists;
|
||||
import com.google.android.collect.Maps;
|
||||
import com.google.android.collect.Sets;
|
||||
|
||||
@@ -88,6 +96,8 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -109,6 +119,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
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 static final int VERSION_UID_WITH_SET = 4;
|
||||
|
||||
private static final int MSG_FORCE_UPDATE = 0x1;
|
||||
|
||||
private final Context mContext;
|
||||
private final INetworkManagementService mNetworkManager;
|
||||
@@ -156,8 +169,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
/** Set of historical network layer stats for known networks. */
|
||||
private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
|
||||
/** Set of historical network layer stats for known UIDs. */
|
||||
private HashMap<NetworkIdentitySet, LongSparseArray<NetworkStatsHistory>> mUidStats =
|
||||
Maps.newHashMap();
|
||||
private HashMap<UidStatsKey, NetworkStatsHistory> mUidStats = Maps.newHashMap();
|
||||
|
||||
/** Flag if {@link #mUidStats} have been loaded from disk. */
|
||||
private boolean mUidStatsLoaded = false;
|
||||
@@ -167,6 +179,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
|
||||
private NetworkStats mLastUidSnapshot;
|
||||
|
||||
/** Current counter sets for each UID. */
|
||||
private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
|
||||
|
||||
/** Data layer operation counters for splicing into other structures. */
|
||||
private NetworkStats mOperations = new NetworkStats(0L, 10);
|
||||
private NetworkStats mLastOperationsSnapshot;
|
||||
@@ -177,11 +192,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
private final AtomicFile mNetworkFile;
|
||||
private final AtomicFile mUidFile;
|
||||
|
||||
// TODO: collect detailed uid stats, storing tag-granularity data until next
|
||||
// dropbox, and uid summary for a specific bucket count.
|
||||
|
||||
// TODO: periodically compile statistics and send to dropbox.
|
||||
|
||||
public NetworkStatsService(
|
||||
Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
|
||||
this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
|
||||
@@ -207,7 +217,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
|
||||
mHandlerThread = new HandlerThread(TAG);
|
||||
mHandlerThread.start();
|
||||
mHandler = new Handler(mHandlerThread.getLooper());
|
||||
mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
|
||||
|
||||
mNetworkFile = new AtomicFile(new File(systemDir, "netstats.bin"));
|
||||
mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
|
||||
@@ -246,6 +256,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "unable to register poll alarm");
|
||||
}
|
||||
|
||||
// kick off background poll to bootstrap deltas
|
||||
mHandler.obtainMessage(MSG_FORCE_UPDATE).sendToTarget();
|
||||
}
|
||||
|
||||
private void shutdownLocked() {
|
||||
@@ -302,24 +315,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
|
||||
@Override
|
||||
public NetworkStatsHistory getHistoryForUid(
|
||||
NetworkTemplate template, int uid, int tag, int fields) {
|
||||
NetworkTemplate template, int uid, int set, int tag, int fields) {
|
||||
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(), fields);
|
||||
for (NetworkIdentitySet ident : mUidStats.keySet()) {
|
||||
if (templateMatches(template, ident)) {
|
||||
final NetworkStatsHistory history = mUidStats.get(ident).get(packed);
|
||||
if (history != null) {
|
||||
combined.recordEntireHistory(history);
|
||||
}
|
||||
for (UidStatsKey key : mUidStats.keySet()) {
|
||||
final boolean setMatches = set == SET_ALL || key.set == set;
|
||||
if (templateMatches(template, key.ident) && key.uid == uid && setMatches
|
||||
&& key.tag == tag) {
|
||||
final NetworkStatsHistory history = mUidStats.get(key);
|
||||
combined.recordEntireHistory(history);
|
||||
}
|
||||
}
|
||||
|
||||
return combined;
|
||||
}
|
||||
}
|
||||
@@ -371,33 +384,27 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
final NetworkStats.Entry entry = new NetworkStats.Entry();
|
||||
NetworkStatsHistory.Entry historyEntry = null;
|
||||
|
||||
for (NetworkIdentitySet ident : mUidStats.keySet()) {
|
||||
if (templateMatches(template, ident)) {
|
||||
final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
|
||||
for (int i = 0; i < uidStats.size(); i++) {
|
||||
final long packed = uidStats.keyAt(i);
|
||||
final int uid = unpackUid(packed);
|
||||
final int tag = unpackTag(packed);
|
||||
for (UidStatsKey key : mUidStats.keySet()) {
|
||||
if (templateMatches(template, key.ident)) {
|
||||
// always include summary under TAG_NONE, and include
|
||||
// other tags when requested.
|
||||
if (key.tag == TAG_NONE || includeTags) {
|
||||
final NetworkStatsHistory history = mUidStats.get(key);
|
||||
historyEntry = history.getValues(start, end, now, historyEntry);
|
||||
|
||||
// always include summary under TAG_NONE, and include
|
||||
// other tags when requested.
|
||||
if (tag == TAG_NONE || includeTags) {
|
||||
final NetworkStatsHistory history = uidStats.valueAt(i);
|
||||
historyEntry = history.getValues(start, end, now, historyEntry);
|
||||
entry.iface = IFACE_ALL;
|
||||
entry.uid = key.uid;
|
||||
entry.set = key.set;
|
||||
entry.tag = key.tag;
|
||||
entry.rxBytes = historyEntry.rxBytes;
|
||||
entry.rxPackets = historyEntry.rxPackets;
|
||||
entry.txBytes = historyEntry.txBytes;
|
||||
entry.txPackets = historyEntry.txPackets;
|
||||
entry.operations = historyEntry.operations;
|
||||
|
||||
entry.iface = IFACE_ALL;
|
||||
entry.uid = uid;
|
||||
entry.tag = tag;
|
||||
entry.rxBytes = historyEntry.rxBytes;
|
||||
entry.rxPackets = historyEntry.rxPackets;
|
||||
entry.txBytes = historyEntry.txBytes;
|
||||
entry.txPackets = historyEntry.txPackets;
|
||||
entry.operations = historyEntry.operations;
|
||||
|
||||
if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
|
||||
|| entry.txPackets > 0 || entry.operations > 0) {
|
||||
stats.combineValues(entry);
|
||||
}
|
||||
if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
|
||||
|| entry.txPackets > 0 || entry.operations > 0) {
|
||||
stats.combineValues(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,8 +444,31 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
|
||||
}
|
||||
|
||||
if (operationCount < 0) {
|
||||
throw new IllegalArgumentException("operation count can only be incremented");
|
||||
}
|
||||
if (tag == TAG_NONE) {
|
||||
throw new IllegalArgumentException("operation count must have specific tag");
|
||||
}
|
||||
|
||||
synchronized (mStatsLock) {
|
||||
mOperations.combineValues(IFACE_ALL, uid, tag, 0L, 0L, 0L, 0L, operationCount);
|
||||
final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
|
||||
mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
|
||||
mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUidForeground(int uid, boolean uidForeground) {
|
||||
mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
|
||||
|
||||
synchronized (mStatsLock) {
|
||||
final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
|
||||
final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
|
||||
if (oldSet != set) {
|
||||
mActiveUidCounterSet.put(uid, set);
|
||||
setKernelCounterSet(uid, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +631,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
|
||||
NetworkStats.Entry entry = null;
|
||||
for (String iface : persistDelta.getUniqueIfaces()) {
|
||||
final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE);
|
||||
final int index = persistDelta.findIndex(iface, UID_ALL, SET_DEFAULT, TAG_NONE);
|
||||
entry = persistDelta.getValues(index, entry);
|
||||
if (forcePersist || entry.rxBytes > persistThreshold
|
||||
|| entry.txBytes > persistThreshold) {
|
||||
@@ -676,31 +706,28 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
// splice in operation counts since last poll
|
||||
final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.tag);
|
||||
final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag);
|
||||
if (j != -1) {
|
||||
operationsEntry = operationsDelta.getValues(j, operationsEntry);
|
||||
entry.operations = operationsEntry.operations;
|
||||
}
|
||||
|
||||
final NetworkStatsHistory history = findOrCreateUidStatsLocked(
|
||||
ident, entry.uid, entry.tag);
|
||||
ident, entry.uid, entry.set, entry.tag);
|
||||
history.recordData(timeStart, currentTime, entry);
|
||||
}
|
||||
|
||||
// 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);
|
||||
for (UidStatsKey key : mUidStats.keySet()) {
|
||||
final NetworkStatsHistory history = mUidStats.get(key);
|
||||
|
||||
// detailed tags are trimmed sooner than summary in TAG_NONE
|
||||
if (unpackTag(packed) == TAG_NONE) {
|
||||
history.removeBucketsBefore(currentTime - maxUidHistory);
|
||||
} else {
|
||||
history.removeBucketsBefore(currentTime - maxTagHistory);
|
||||
}
|
||||
// detailed tags are trimmed sooner than summary in TAG_NONE
|
||||
if (key.tag == TAG_NONE) {
|
||||
history.removeBucketsBefore(currentTime - maxUidHistory);
|
||||
} else {
|
||||
history.removeBucketsBefore(currentTime - maxTagHistory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,26 +742,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
private void removeUidLocked(int uid) {
|
||||
ensureUidStatsLoadedLocked();
|
||||
|
||||
final ArrayList<UidStatsKey> knownKeys = Lists.newArrayList();
|
||||
knownKeys.addAll(mUidStats.keySet());
|
||||
|
||||
// migrate all UID stats into special "removed" bucket
|
||||
for (NetworkIdentitySet ident : mUidStats.keySet()) {
|
||||
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);
|
||||
for (UidStatsKey key : knownKeys) {
|
||||
if (key.uid == uid) {
|
||||
// only migrate combined TAG_NONE history
|
||||
if (key.tag == TAG_NONE) {
|
||||
final NetworkStatsHistory uidHistory = mUidStats.get(key);
|
||||
final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
|
||||
key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
|
||||
removedHistory.recordEntireHistory(uidHistory);
|
||||
}
|
||||
mUidStats.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: push kernel event to wipe stats for UID, otherwise we risk
|
||||
// picking them up again during next poll.
|
||||
// clear kernel stats associated with UID
|
||||
resetKernelUidStats(uid);
|
||||
|
||||
// since this was radical rewrite, push to disk
|
||||
writeUidStatsLocked();
|
||||
@@ -763,17 +789,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
private NetworkStatsHistory findOrCreateUidStatsLocked(
|
||||
NetworkIdentitySet ident, int uid, int tag) {
|
||||
NetworkIdentitySet ident, int uid, int set, int tag) {
|
||||
ensureUidStatsLoadedLocked();
|
||||
|
||||
LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
|
||||
if (uidStats == null) {
|
||||
uidStats = new LongSparseArray<NetworkStatsHistory>();
|
||||
mUidStats.put(ident, uidStats);
|
||||
}
|
||||
|
||||
final long packed = packUidAndTag(uid, tag);
|
||||
final NetworkStatsHistory existing = uidStats.get(packed);
|
||||
final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
|
||||
final NetworkStatsHistory existing = mUidStats.get(key);
|
||||
|
||||
// update when no existing, or when bucket duration changed
|
||||
final long bucketDuration = mSettings.getUidBucketDuration();
|
||||
@@ -787,7 +807,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
if (updated != null) {
|
||||
uidStats.put(packed, updated);
|
||||
mUidStats.put(key, updated);
|
||||
return updated;
|
||||
} else {
|
||||
return existing;
|
||||
@@ -874,25 +894,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
// 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++) {
|
||||
case VERSION_UID_WITH_TAG:
|
||||
case VERSION_UID_WITH_SET: {
|
||||
// uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
|
||||
final int identSize = in.readInt();
|
||||
for (int i = 0; i < identSize; i++) {
|
||||
final NetworkIdentitySet ident = new NetworkIdentitySet(in);
|
||||
|
||||
final int childSize = in.readInt();
|
||||
final LongSparseArray<NetworkStatsHistory> uidStats = new LongSparseArray<
|
||||
NetworkStatsHistory>(childSize);
|
||||
for (int j = 0; j < childSize; j++) {
|
||||
final int size = in.readInt();
|
||||
for (int j = 0; j < size; j++) {
|
||||
final int uid = in.readInt();
|
||||
final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
|
||||
: SET_DEFAULT;
|
||||
final int tag = in.readInt();
|
||||
final long packed = packUidAndTag(uid, tag);
|
||||
|
||||
final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
|
||||
final NetworkStatsHistory history = new NetworkStatsHistory(in);
|
||||
uidStats.put(packed, history);
|
||||
mUidStats.put(key, history);
|
||||
}
|
||||
|
||||
mUidStats.put(ident, uidStats);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -949,29 +968,36 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
|
||||
// TODO: consider duplicating stats and releasing lock while writing
|
||||
|
||||
// build UidStatsKey lists grouped by ident
|
||||
final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
|
||||
for (UidStatsKey key : mUidStats.keySet()) {
|
||||
ArrayList<UidStatsKey> keys = keysByIdent.get(key.ident);
|
||||
if (keys == null) {
|
||||
keys = Lists.newArrayList();
|
||||
keysByIdent.put(key.ident, keys);
|
||||
}
|
||||
keys.add(key);
|
||||
}
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = mUidFile.startWrite();
|
||||
final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
|
||||
|
||||
out.writeInt(FILE_MAGIC);
|
||||
out.writeInt(VERSION_UID_WITH_TAG);
|
||||
out.writeInt(VERSION_UID_WITH_SET);
|
||||
|
||||
final int size = mUidStats.size();
|
||||
out.writeInt(size);
|
||||
for (NetworkIdentitySet ident : mUidStats.keySet()) {
|
||||
final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
|
||||
out.writeInt(keysByIdent.size());
|
||||
for (NetworkIdentitySet ident : keysByIdent.keySet()) {
|
||||
final ArrayList<UidStatsKey> keys = keysByIdent.get(ident);
|
||||
ident.writeToStream(out);
|
||||
|
||||
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);
|
||||
out.writeInt(keys.size());
|
||||
for (UidStatsKey key : keys) {
|
||||
final NetworkStatsHistory history = mUidStats.get(key);
|
||||
out.writeInt(key.uid);
|
||||
out.writeInt(key.set);
|
||||
out.writeInt(key.tag);
|
||||
history.writeToStream(out);
|
||||
}
|
||||
}
|
||||
@@ -1030,20 +1056,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
// from disk if not already in memory.
|
||||
ensureUidStatsLoadedLocked();
|
||||
|
||||
pw.println("Detailed UID stats:");
|
||||
for (NetworkIdentitySet ident : mUidStats.keySet()) {
|
||||
pw.print(" ident="); pw.println(ident.toString());
|
||||
final ArrayList<UidStatsKey> keys = Lists.newArrayList();
|
||||
keys.addAll(mUidStats.keySet());
|
||||
Collections.sort(keys);
|
||||
|
||||
final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
|
||||
for (int i = 0; i < uidStats.size(); 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.print(uid);
|
||||
pw.print(" tag=0x"); pw.println(Integer.toHexString(tag));
|
||||
history.dump(" ", pw, fullHistory);
|
||||
}
|
||||
pw.println("Detailed UID stats:");
|
||||
for (UidStatsKey key : keys) {
|
||||
pw.print(" ident="); pw.print(key.ident.toString());
|
||||
pw.print(" uid="); pw.print(key.uid);
|
||||
pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
|
||||
pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
|
||||
|
||||
final NetworkStatsHistory history = mUidStats.get(key);
|
||||
history.dump(" ", pw, fullHistory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1080,8 +1105,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
|
||||
for (ApplicationInfo info : installedApps) {
|
||||
final int uid = info.uid;
|
||||
findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(UID_START, UID_END,
|
||||
UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, UID_TX_PACKETS, UID_OPERATIONS);
|
||||
findOrCreateUidStatsLocked(ident, uid, SET_DEFAULT, TAG_NONE).generateRandom(
|
||||
UID_START, UID_END, UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES,
|
||||
UID_TX_PACKETS, UID_OPERATIONS);
|
||||
findOrCreateUidStatsLocked(ident, uid, SET_FOREGROUND, TAG_NONE).generateRandom(
|
||||
UID_START, UID_END, UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES,
|
||||
UID_TX_PACKETS, UID_OPERATIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1116,23 +1145,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
return (int) (existing.size() * existing.getBucketDuration() / 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}.
|
||||
@@ -1146,6 +1158,58 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
private Handler.Callback mHandlerCallback = new Handler.Callback() {
|
||||
/** {@inheritDoc} */
|
||||
public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_FORCE_UPDATE: {
|
||||
forceUpdate();
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
|
||||
*/
|
||||
private static class UidStatsKey implements Comparable<UidStatsKey> {
|
||||
public final NetworkIdentitySet ident;
|
||||
public final int uid;
|
||||
public final int set;
|
||||
public final int tag;
|
||||
|
||||
public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) {
|
||||
this.ident = ident;
|
||||
this.uid = uid;
|
||||
this.set = set;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(ident, uid, set, tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof UidStatsKey) {
|
||||
final UidStatsKey key = (UidStatsKey) obj;
|
||||
return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set
|
||||
&& tag == key.tag;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(UidStatsKey another) {
|
||||
return Integer.compare(uid, another.uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default external settings that read from {@link Settings.Secure}.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user