Merge "Lightweight checkin output for network stats." into lmp-mr1-dev
This commit is contained in:
@ -34,7 +34,7 @@ import java.util.Objects;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetworkIdentity {
|
||||
public class NetworkIdentity implements Comparable<NetworkIdentity> {
|
||||
/**
|
||||
* When enabled, combine all {@link #mSubType} together under
|
||||
* {@link #SUBTYPE_COMBINED}.
|
||||
@ -76,7 +76,7 @@ public class NetworkIdentity {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder("[");
|
||||
final StringBuilder builder = new StringBuilder("{");
|
||||
builder.append("type=").append(getNetworkTypeName(mType));
|
||||
builder.append(", subType=");
|
||||
if (COMBINE_SUBTYPE_ENABLED) {
|
||||
@ -95,7 +95,7 @@ public class NetworkIdentity {
|
||||
if (mRoaming) {
|
||||
builder.append(", ROAMING");
|
||||
}
|
||||
return builder.append("]").toString();
|
||||
return builder.append("}").toString();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
@ -170,4 +170,22 @@ public class NetworkIdentity {
|
||||
|
||||
return new NetworkIdentity(type, subType, subscriberId, networkId, roaming);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(NetworkIdentity another) {
|
||||
int res = Integer.compare(mType, another.mType);
|
||||
if (res == 0) {
|
||||
res = Integer.compare(mSubType, another.mSubType);
|
||||
}
|
||||
if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) {
|
||||
res = mSubscriberId.compareTo(another.mSubscriberId);
|
||||
}
|
||||
if (res == 0 && mNetworkId != null && another.mNetworkId != null) {
|
||||
res = mNetworkId.compareTo(another.mNetworkId);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Boolean.compare(mRoaming, another.mRoaming);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -732,6 +732,22 @@ public class NetworkStats implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return text description of {@link #set} value.
|
||||
*/
|
||||
public static String setToCheckinString(int set) {
|
||||
switch (set) {
|
||||
case SET_ALL:
|
||||
return "all";
|
||||
case SET_DEFAULT:
|
||||
return "def";
|
||||
case SET_FOREGROUND:
|
||||
return "fg";
|
||||
default:
|
||||
return "unk";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return text description of {@link #tag} value.
|
||||
*/
|
||||
|
@ -26,6 +26,7 @@ import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
|
||||
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
|
||||
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
|
||||
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
|
||||
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
|
||||
import static com.android.internal.util.ArrayUtils.total;
|
||||
|
||||
import android.os.Parcel;
|
||||
@ -38,6 +39,7 @@ import java.io.CharArrayWriter;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
@ -573,8 +575,22 @@ public class NetworkStatsHistory implements Parcelable {
|
||||
return (long) (start + (r.nextFloat() * (end - start)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly determine if this history intersects with given window.
|
||||
*/
|
||||
public boolean intersects(long start, long end) {
|
||||
final long dataStart = getStart();
|
||||
final long dataEnd = getEnd();
|
||||
if (start >= dataStart && start <= dataEnd) return true;
|
||||
if (end >= dataStart && end <= dataEnd) return true;
|
||||
if (dataStart >= start && dataStart <= end) return true;
|
||||
if (dataEnd >= start && dataEnd <= end) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void dump(IndentingPrintWriter pw, boolean fullHistory) {
|
||||
pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration);
|
||||
pw.print("NetworkStatsHistory: bucketDuration=");
|
||||
pw.println(bucketDuration / SECOND_IN_MILLIS);
|
||||
pw.increaseIndent();
|
||||
|
||||
final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
|
||||
@ -583,19 +599,35 @@ public class NetworkStatsHistory implements Parcelable {
|
||||
}
|
||||
|
||||
for (int i = start; i < bucketCount; i++) {
|
||||
pw.print("bucketStart="); pw.print(bucketStart[i]);
|
||||
if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); }
|
||||
if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); }
|
||||
if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); }
|
||||
if (txBytes != null) { pw.print(" txBytes="); pw.print(txBytes[i]); }
|
||||
if (txPackets != null) { pw.print(" txPackets="); pw.print(txPackets[i]); }
|
||||
if (operations != null) { pw.print(" operations="); pw.print(operations[i]); }
|
||||
pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS);
|
||||
if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); }
|
||||
if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); }
|
||||
if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); }
|
||||
if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); }
|
||||
if (operations != null) { pw.print(" op="); pw.print(operations[i]); }
|
||||
pw.println();
|
||||
}
|
||||
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
public void dumpCheckin(PrintWriter pw) {
|
||||
pw.print("d,");
|
||||
pw.print(bucketDuration / SECOND_IN_MILLIS);
|
||||
pw.println();
|
||||
|
||||
for (int i = 0; i < bucketCount; i++) {
|
||||
pw.print("b,");
|
||||
pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(',');
|
||||
if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(',');
|
||||
if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); }
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final CharArrayWriter writer = new CharArrayWriter();
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
|
||||
import static android.net.ConnectivityManager.TYPE_ETHERNET;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
|
||||
@ -34,10 +35,10 @@ import android.content.res.Resources;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Template definition used to generically match {@link NetworkIdentity},
|
||||
* usually when collecting statistics.
|
||||
@ -53,6 +54,7 @@ public class NetworkTemplate implements Parcelable {
|
||||
public static final int MATCH_ETHERNET = 5;
|
||||
public static final int MATCH_MOBILE_WILDCARD = 6;
|
||||
public static final int MATCH_WIFI_WILDCARD = 7;
|
||||
public static final int MATCH_BLUETOOTH = 8;
|
||||
|
||||
/**
|
||||
* Set of {@link NetworkInfo#getType()} that reflect data usage.
|
||||
@ -134,6 +136,14 @@ public class NetworkTemplate implements Parcelable {
|
||||
return new NetworkTemplate(MATCH_ETHERNET, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
|
||||
* networks together.
|
||||
*/
|
||||
public static NetworkTemplate buildTemplateBluetooth() {
|
||||
return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
|
||||
}
|
||||
|
||||
private final int mMatchRule;
|
||||
private final String mSubscriberId;
|
||||
private final String mNetworkId;
|
||||
@ -222,6 +232,8 @@ public class NetworkTemplate implements Parcelable {
|
||||
return matchesMobileWildcard(ident);
|
||||
case MATCH_WIFI_WILDCARD:
|
||||
return matchesWifiWildcard(ident);
|
||||
case MATCH_BLUETOOTH:
|
||||
return matchesBluetooth(ident);
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown network template");
|
||||
}
|
||||
@ -316,6 +328,16 @@ public class NetworkTemplate implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if matches Bluetooth network template.
|
||||
*/
|
||||
private boolean matchesBluetooth(NetworkIdentity ident) {
|
||||
if (ident.mType == TYPE_BLUETOOTH) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getMatchRuleName(int matchRule) {
|
||||
switch (matchRule) {
|
||||
case MATCH_MOBILE_3G_LOWER:
|
||||
@ -332,6 +354,8 @@ public class NetworkTemplate implements Parcelable {
|
||||
return "MOBILE_WILDCARD";
|
||||
case MATCH_WIFI_WILDCARD:
|
||||
return "WIFI_WILDCARD";
|
||||
case MATCH_BLUETOOTH:
|
||||
return "BLUETOOTH";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@ -451,6 +451,40 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
public void testIntersects() throws Exception {
|
||||
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||
|
||||
final long FIRST_START = TEST_START;
|
||||
final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
|
||||
final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
|
||||
final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
|
||||
final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
|
||||
final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
|
||||
|
||||
stats.recordData(FIRST_START, FIRST_END,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||
stats.recordData(SECOND_START, SECOND_END,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||
stats.recordData(THIRD_START, THIRD_END,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||
|
||||
assertFalse(stats.intersects(10, 20));
|
||||
assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1));
|
||||
assertFalse(stats.intersects(Long.MAX_VALUE, Long.MIN_VALUE));
|
||||
|
||||
assertTrue(stats.intersects(Long.MIN_VALUE, Long.MAX_VALUE));
|
||||
assertTrue(stats.intersects(10, TEST_START + YEAR_IN_MILLIS));
|
||||
assertTrue(stats.intersects(TEST_START, TEST_START));
|
||||
assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, TEST_START + DAY_IN_MILLIS + 1));
|
||||
assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, Long.MAX_VALUE));
|
||||
assertTrue(stats.intersects(TEST_START + 1, Long.MAX_VALUE));
|
||||
|
||||
assertFalse(stats.intersects(Long.MIN_VALUE, TEST_START - 1));
|
||||
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START));
|
||||
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
|
||||
}
|
||||
|
||||
private static void assertIndexBeforeAfter(
|
||||
NetworkStatsHistory stats, int before, int after, long time) {
|
||||
assertEquals("unexpected before", before, stats.getIndexBefore(time));
|
||||
|
@ -29,7 +29,8 @@ import java.util.HashSet;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class NetworkIdentitySet extends HashSet<NetworkIdentity> {
|
||||
public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
|
||||
Comparable<NetworkIdentitySet> {
|
||||
private static final int VERSION_INIT = 1;
|
||||
private static final int VERSION_ADD_ROAMING = 2;
|
||||
private static final int VERSION_ADD_NETWORK_ID = 3;
|
||||
@ -92,4 +93,14 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(NetworkIdentitySet another) {
|
||||
if (isEmpty()) return -1;
|
||||
if (another.isEmpty()) return 1;
|
||||
|
||||
final NetworkIdentity ident = iterator().next();
|
||||
final NetworkIdentity anotherIdent = another.iterator().next();
|
||||
return ident.compareTo(anotherIdent);
|
||||
}
|
||||
}
|
||||
|
@ -22,15 +22,20 @@ 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.TrafficStats.UID_REMOVED;
|
||||
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
|
||||
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkIdentity;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.net.TrafficStats;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AtomicFile;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FileRotator;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
@ -44,15 +49,13 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
/**
|
||||
* Collection of {@link NetworkStatsHistory}, stored based on combined key of
|
||||
* {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself.
|
||||
@ -70,7 +73,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
||||
|
||||
private static final int VERSION_UNIFIED_INIT = 16;
|
||||
|
||||
private HashMap<Key, NetworkStatsHistory> mStats = Maps.newHashMap();
|
||||
private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>();
|
||||
|
||||
private final long mBucketDuration;
|
||||
|
||||
@ -145,12 +148,13 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
||||
NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
|
||||
final NetworkStatsHistory combined = new NetworkStatsHistory(
|
||||
mBucketDuration, estimateBuckets(), fields);
|
||||
for (Map.Entry<Key, NetworkStatsHistory> entry : mStats.entrySet()) {
|
||||
final Key key = entry.getKey();
|
||||
for (int i = 0; i < mStats.size(); i++) {
|
||||
final Key key = mStats.keyAt(i);
|
||||
final boolean setMatches = set == SET_ALL || key.set == set;
|
||||
if (key.uid == uid && setMatches && key.tag == tag
|
||||
&& templateMatches(template, key.ident)) {
|
||||
combined.recordHistory(entry.getValue(), start, end);
|
||||
final NetworkStatsHistory value = mStats.valueAt(i);
|
||||
combined.recordHistory(value, start, end);
|
||||
}
|
||||
}
|
||||
return combined;
|
||||
@ -170,11 +174,11 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
||||
// shortcut when we know stats will be empty
|
||||
if (start == end) return stats;
|
||||
|
||||
for (Map.Entry<Key, NetworkStatsHistory> mapEntry : mStats.entrySet()) {
|
||||
final Key key = mapEntry.getKey();
|
||||
for (int i = 0; i < mStats.size(); i++) {
|
||||
final Key key = mStats.keyAt(i);
|
||||
if (templateMatches(template, key.ident)) {
|
||||
final NetworkStatsHistory history = mapEntry.getValue();
|
||||
historyEntry = history.getValues(start, end, now, historyEntry);
|
||||
final NetworkStatsHistory value = mStats.valueAt(i);
|
||||
historyEntry = value.getValues(start, end, now, historyEntry);
|
||||
|
||||
entry.iface = IFACE_ALL;
|
||||
entry.uid = key.uid;
|
||||
@ -225,8 +229,10 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
||||
* into this collection.
|
||||
*/
|
||||
public void recordCollection(NetworkStatsCollection another) {
|
||||
for (Map.Entry<Key, NetworkStatsHistory> entry : another.mStats.entrySet()) {
|
||||
recordHistory(entry.getKey(), entry.getValue());
|
||||
for (int i = 0; i < another.mStats.size(); i++) {
|
||||
final Key key = another.mStats.keyAt(i);
|
||||
final NetworkStatsHistory value = another.mStats.valueAt(i);
|
||||
recordHistory(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,7 +466,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
||||
}
|
||||
|
||||
private int estimateBuckets() {
|
||||
return (int) (Math.min(mEndMillis - mStartMillis, DateUtils.WEEK_IN_MILLIS * 5)
|
||||
return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5)
|
||||
/ mBucketDuration);
|
||||
}
|
||||
|
||||
@ -482,6 +488,54 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpCheckin(PrintWriter pw, long start, long end) {
|
||||
dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell");
|
||||
dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi");
|
||||
dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth");
|
||||
dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt");
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump all contained stats that match requested parameters, but group
|
||||
* together all matching {@link NetworkTemplate} under a single prefix.
|
||||
*/
|
||||
private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate,
|
||||
String groupPrefix) {
|
||||
final ArrayMap<Key, NetworkStatsHistory> grouped = new ArrayMap<>();
|
||||
|
||||
// Walk through all history, grouping by matching network templates
|
||||
for (int i = 0; i < mStats.size(); i++) {
|
||||
final Key key = mStats.keyAt(i);
|
||||
final NetworkStatsHistory value = mStats.valueAt(i);
|
||||
|
||||
if (!templateMatches(groupTemplate, key.ident)) continue;
|
||||
|
||||
final Key groupKey = new Key(null, key.uid, key.set, key.tag);
|
||||
NetworkStatsHistory groupHistory = grouped.get(groupKey);
|
||||
if (groupHistory == null) {
|
||||
groupHistory = new NetworkStatsHistory(value.getBucketDuration());
|
||||
grouped.put(groupKey, groupHistory);
|
||||
}
|
||||
groupHistory.recordHistory(value, start, end);
|
||||
}
|
||||
|
||||
for (int i = 0; i < grouped.size(); i++) {
|
||||
final Key key = grouped.keyAt(i);
|
||||
final NetworkStatsHistory value = grouped.valueAt(i);
|
||||
|
||||
if (value.size() == 0) continue;
|
||||
|
||||
pw.print("c,");
|
||||
pw.print(groupPrefix); pw.print(',');
|
||||
pw.print(key.uid); pw.print(',');
|
||||
pw.print(NetworkStats.setToCheckinString(key.set)); pw.print(',');
|
||||
pw.print(key.tag);
|
||||
pw.println();
|
||||
|
||||
value.dumpCheckin(pw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
|
||||
* in the given {@link NetworkIdentitySet}.
|
||||
@ -528,7 +582,20 @@ public class NetworkStatsCollection implements FileRotator.Reader {
|
||||
|
||||
@Override
|
||||
public int compareTo(Key another) {
|
||||
return Integer.compare(uid, another.uid);
|
||||
int res = 0;
|
||||
if (ident != null && another.ident != null) {
|
||||
res = ident.compareTo(another.ident);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Integer.compare(uid, another.uid);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Integer.compare(set, another.set);
|
||||
}
|
||||
if (res == 0) {
|
||||
res = Integer.compare(tag, another.tag);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@ -124,23 +125,36 @@ public class NetworkStatsRecorder {
|
||||
* as reference is valid.
|
||||
*/
|
||||
public NetworkStatsCollection getOrLoadCompleteLocked() {
|
||||
NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
|
||||
if (complete == null) {
|
||||
if (LOGD) Slog.d(TAG, "getOrLoadCompleteLocked() reading from disk for " + mCookie);
|
||||
try {
|
||||
complete = new NetworkStatsCollection(mBucketDuration);
|
||||
mRotator.readMatching(complete, Long.MIN_VALUE, Long.MAX_VALUE);
|
||||
complete.recordCollection(mPending);
|
||||
mComplete = new WeakReference<NetworkStatsCollection>(complete);
|
||||
} catch (IOException e) {
|
||||
Log.wtf(TAG, "problem completely reading network stats", e);
|
||||
recoverFromWtf();
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.wtf(TAG, "problem completely reading network stats", e);
|
||||
recoverFromWtf();
|
||||
}
|
||||
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
|
||||
if (res == null) {
|
||||
res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
|
||||
mComplete = new WeakReference<NetworkStatsCollection>(res);
|
||||
}
|
||||
return complete;
|
||||
return res;
|
||||
}
|
||||
|
||||
public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
|
||||
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
|
||||
if (res == null) {
|
||||
res = loadLocked(start, end);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private NetworkStatsCollection loadLocked(long start, long end) {
|
||||
if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
|
||||
final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
|
||||
try {
|
||||
mRotator.readMatching(res, start, end);
|
||||
res.recordCollection(mPending);
|
||||
} catch (IOException e) {
|
||||
Log.wtf(TAG, "problem completely reading network stats", e);
|
||||
recoverFromWtf();
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.wtf(TAG, "problem completely reading network stats", e);
|
||||
recoverFromWtf();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -384,6 +398,11 @@ public class NetworkStatsRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpCheckin(PrintWriter pw, long start, long end) {
|
||||
// Only load and dump stats from the requested window
|
||||
getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover from {@link FileRotator} failure by dumping state to
|
||||
* {@link DropBoxManager} and deleting contents.
|
||||
|
@ -104,6 +104,7 @@ import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.EventLog;
|
||||
@ -1094,12 +1095,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
|
||||
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
|
||||
|
||||
long duration = DateUtils.DAY_IN_MILLIS;
|
||||
final HashSet<String> argSet = new HashSet<String>();
|
||||
for (String arg : args) {
|
||||
argSet.add(arg);
|
||||
|
||||
if (arg.startsWith("--duration=")) {
|
||||
try {
|
||||
duration = Long.parseLong(arg.substring(11));
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// usage: dumpsys netstats --full --uid --tag --poll --checkin
|
||||
@ -1109,7 +1118,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail");
|
||||
final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail");
|
||||
|
||||
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
|
||||
final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " ");
|
||||
|
||||
synchronized (mStatsLock) {
|
||||
if (poll) {
|
||||
@ -1119,13 +1128,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
if (checkin) {
|
||||
// list current stats files to verify rotation
|
||||
pw.println("Current files:");
|
||||
pw.increaseIndent();
|
||||
for (String file : mBaseDir.list()) {
|
||||
pw.println(file);
|
||||
final long end = System.currentTimeMillis();
|
||||
final long start = end - duration;
|
||||
|
||||
pw.print("v1,");
|
||||
pw.print(start / SECOND_IN_MILLIS); pw.print(',');
|
||||
pw.print(end / SECOND_IN_MILLIS); pw.println();
|
||||
|
||||
pw.println("xt");
|
||||
mXtRecorder.dumpCheckin(rawWriter, start, end);
|
||||
|
||||
if (includeUid) {
|
||||
pw.println("uid");
|
||||
mUidRecorder.dumpCheckin(rawWriter, start, end);
|
||||
}
|
||||
if (includeTag) {
|
||||
pw.println("tag");
|
||||
mUidTagRecorder.dumpCheckin(rawWriter, start, end);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
return;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user