Network stats with varint, omit parcel fields.

Persist NetworkStatsHistory using variable-length encoding; since
most buckets have small numbers, we can encode them tighter. Initial
test showed 44% space savings. Also persist packet and operation
counters.

Let NetworkStatsHistory consumers request which fields they actually
need to reduce parcel overhead.

Tests for verify varint and history field requests, also verify end-
to-end by persisting history into byte[] and restoring. Expose
bandwidth control enabled state. Extend random generation to create
packet and operation counts. Moved operation counts to long.

Fix bug that miscalculated bytes since last persist, which would
cause partial stats loss when battery pulled.

Bug: 4581977, 5023706, 5023635, 5096903
Change-Id: If61e89f681ffa11fe5711471fd9f7c238d3d37b0
This commit is contained in:
Jeff Sharkey
2011-08-03 17:04:22 -07:00
parent e2a8a0b310
commit c76817d370
4 changed files with 238 additions and 144 deletions

View File

@@ -24,9 +24,9 @@ import android.net.NetworkTemplate;
interface INetworkStatsService {
/** Return historical network layer stats for traffic that matches template. */
NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate 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);
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag, int fields);
/** Return network layer usage summary for traffic that matches template. */
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);

View File

@@ -58,7 +58,7 @@ public class NetworkStats implements Parcelable {
private long[] rxPackets;
private long[] txBytes;
private long[] txPackets;
private int[] operations;
private long[] operations;
public static class Entry {
public String iface;
@@ -68,13 +68,18 @@ public class NetworkStats implements Parcelable {
public long rxPackets;
public long txBytes;
public long txPackets;
public int operations;
public long operations;
public Entry() {
this(IFACE_ALL, UID_ALL, 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);
}
public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes,
long txPackets, int operations) {
long txPackets, long operations) {
this.iface = iface;
this.uid = uid;
this.tag = tag;
@@ -96,7 +101,7 @@ public class NetworkStats implements Parcelable {
this.rxPackets = new long[initialSize];
this.txBytes = new long[initialSize];
this.txPackets = new long[initialSize];
this.operations = new int[initialSize];
this.operations = new long[initialSize];
}
public NetworkStats(Parcel parcel) {
@@ -109,7 +114,7 @@ public class NetworkStats implements Parcelable {
rxPackets = parcel.createLongArray();
txBytes = parcel.createLongArray();
txPackets = parcel.createLongArray();
operations = parcel.createIntArray();
operations = parcel.createLongArray();
}
/** {@inheritDoc} */
@@ -123,16 +128,16 @@ public class NetworkStats implements Parcelable {
dest.writeLongArray(rxPackets);
dest.writeLongArray(txBytes);
dest.writeLongArray(txPackets);
dest.writeIntArray(operations);
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, 0);
return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0L);
}
public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) {
long txBytes, long txPackets, long operations) {
return addValues(
new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
}
@@ -197,7 +202,7 @@ public class NetworkStats implements Parcelable {
}
public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) {
long txBytes, long txPackets, long operations) {
return combineValues(
new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
}

View File

@@ -19,11 +19,11 @@ package android.net;
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.NetworkStatsHistory.DataStreamUtils.readLongArray;
import static android.net.NetworkStatsHistory.DataStreamUtils.writeLongArray;
import static android.net.NetworkStatsHistory.ParcelUtils.readIntArray;
import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray;
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.writeIntArray;
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
import android.os.Parcel;
@@ -51,42 +51,53 @@ import java.util.Random;
*/
public class NetworkStatsHistory implements Parcelable {
private static final int VERSION_INIT = 1;
private static final int VERSION_ADD_PACKETS = 2;
// TODO: teach about varint encoding to use less disk space
// TODO: teach about omitting entire fields to reduce parcel pressure
// TODO: persist/restore packet and operation counts
public static final int FIELD_RX_BYTES = 0x01;
public static final int FIELD_RX_PACKETS = 0x02;
public static final int FIELD_TX_BYTES = 0x04;
public static final int FIELD_TX_PACKETS = 0x08;
public static final int FIELD_OPERATIONS = 0x10;
private final long bucketDuration;
public static final int FIELD_ALL = 0xFFFFFFFF;
private long bucketDuration;
private int bucketCount;
private long[] bucketStart;
private long[] rxBytes;
private long[] rxPackets;
private long[] txBytes;
private long[] txPackets;
private int[] operations;
private long[] operations;
public static class Entry {
public static final long UNKNOWN = -1;
public long bucketStart;
public long bucketDuration;
public long rxBytes;
public long rxPackets;
public long txBytes;
public long txPackets;
public int operations;
public long operations;
}
public NetworkStatsHistory(long bucketDuration) {
this(bucketDuration, 10);
this(bucketDuration, 10, FIELD_ALL);
}
public NetworkStatsHistory(long bucketDuration, int initialSize) {
this(bucketDuration, initialSize, FIELD_ALL);
}
public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
this.bucketDuration = bucketDuration;
bucketStart = new long[initialSize];
rxBytes = new long[initialSize];
rxPackets = new long[initialSize];
txBytes = new long[initialSize];
txPackets = new long[initialSize];
operations = new int[initialSize];
if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
bucketCount = 0;
}
@@ -97,7 +108,7 @@ public class NetworkStatsHistory implements Parcelable {
rxPackets = readLongArray(in);
txBytes = readLongArray(in);
txPackets = readLongArray(in);
operations = readIntArray(in);
operations = readLongArray(in);
bucketCount = bucketStart.length;
}
@@ -109,21 +120,31 @@ public class NetworkStatsHistory implements Parcelable {
writeLongArray(out, rxPackets, bucketCount);
writeLongArray(out, txBytes, bucketCount);
writeLongArray(out, txPackets, bucketCount);
writeIntArray(out, operations, bucketCount);
writeLongArray(out, operations, bucketCount);
}
public NetworkStatsHistory(DataInputStream in) throws IOException {
// TODO: read packet and operation counts
final int version = in.readInt();
switch (version) {
case VERSION_INIT: {
bucketDuration = in.readLong();
bucketStart = readLongArray(in);
rxBytes = readLongArray(in);
bucketStart = readFullLongArray(in);
rxBytes = readFullLongArray(in);
rxPackets = new long[bucketStart.length];
txBytes = readLongArray(in);
txBytes = readFullLongArray(in);
txPackets = new long[bucketStart.length];
operations = new int[bucketStart.length];
operations = new long[bucketStart.length];
bucketCount = bucketStart.length;
break;
}
case VERSION_ADD_PACKETS: {
bucketDuration = in.readLong();
bucketStart = readVarLongArray(in);
rxBytes = readVarLongArray(in);
rxPackets = readVarLongArray(in);
txBytes = readVarLongArray(in);
txPackets = readVarLongArray(in);
operations = readVarLongArray(in);
bucketCount = bucketStart.length;
break;
}
@@ -134,12 +155,14 @@ public class NetworkStatsHistory implements Parcelable {
}
public void writeToStream(DataOutputStream out) throws IOException {
// TODO: write packet and operation counts
out.writeInt(VERSION_INIT);
out.writeInt(VERSION_ADD_PACKETS);
out.writeLong(bucketDuration);
writeLongArray(out, bucketStart, bucketCount);
writeLongArray(out, rxBytes, bucketCount);
writeLongArray(out, txBytes, bucketCount);
writeVarLongArray(out, bucketStart, bucketCount);
writeVarLongArray(out, rxBytes, bucketCount);
writeVarLongArray(out, rxPackets, bucketCount);
writeVarLongArray(out, txBytes, bucketCount);
writeVarLongArray(out, txPackets, bucketCount);
writeVarLongArray(out, operations, bucketCount);
}
/** {@inheritDoc} */
@@ -178,11 +201,11 @@ public class NetworkStatsHistory implements Parcelable {
final Entry entry = recycle != null ? recycle : new Entry();
entry.bucketStart = bucketStart[i];
entry.bucketDuration = bucketDuration;
entry.rxBytes = rxBytes[i];
entry.rxPackets = rxPackets[i];
entry.txBytes = txBytes[i];
entry.txPackets = txPackets[i];
entry.operations = operations[i];
entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
entry.txBytes = getLong(txBytes, i, UNKNOWN);
entry.txPackets = getLong(txPackets, i, UNKNOWN);
entry.operations = getLong(operations, i, UNKNOWN);
return entry;
}
@@ -193,7 +216,7 @@ 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, 0));
new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
}
/**
@@ -230,11 +253,11 @@ public class NetworkStatsHistory implements Parcelable {
final long fracTxPackets = entry.txPackets * overlap / duration;
final int fracOperations = (int) (entry.operations * overlap / duration);
rxBytes[i] += fracRxBytes; entry.rxBytes -= fracRxBytes;
rxPackets[i] += fracRxPackets; entry.rxPackets -= fracRxPackets;
txBytes[i] += fracTxBytes; entry.txBytes -= fracTxBytes;
txPackets[i] += fracTxPackets; entry.txPackets -= fracTxPackets;
operations[i] += fracOperations; entry.operations -= fracOperations;
addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes;
addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets;
addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes;
addLong(txPackets, i, fracTxPackets); entry.txPackets -= fracTxPackets;
addLong(operations, i, fracOperations); entry.operations -= fracOperations;
duration -= overlap;
}
@@ -246,16 +269,16 @@ 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, 0);
IFACE_ALL, UID_ALL, 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;
entry.rxBytes = input.rxBytes[i];
entry.rxPackets = input.rxPackets[i];
entry.txBytes = input.txBytes[i];
entry.txPackets = input.txPackets[i];
entry.operations = input.operations[i];
entry.rxBytes = getLong(input.rxBytes, i, 0L);
entry.rxPackets = getLong(input.rxPackets, i, 0L);
entry.txBytes = getLong(input.txBytes, i, 0L);
entry.txPackets = getLong(input.txPackets, i, 0L);
entry.operations = getLong(input.operations, i, 0L);
recordData(start, end, entry);
}
@@ -287,11 +310,11 @@ public class NetworkStatsHistory implements Parcelable {
if (bucketCount >= bucketStart.length) {
final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
bucketStart = Arrays.copyOf(bucketStart, newLength);
rxBytes = Arrays.copyOf(rxBytes, newLength);
rxPackets = Arrays.copyOf(rxPackets, newLength);
txBytes = Arrays.copyOf(txBytes, newLength);
txPackets = Arrays.copyOf(txPackets, newLength);
operations = Arrays.copyOf(operations, newLength);
if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
if (operations != null) operations = Arrays.copyOf(operations, newLength);
}
// create gap when inserting bucket in middle
@@ -300,19 +323,19 @@ public class NetworkStatsHistory implements Parcelable {
final int length = bucketCount - index;
System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
System.arraycopy(txBytes, index, txBytes, dstPos, length);
System.arraycopy(txPackets, index, txPackets, dstPos, length);
System.arraycopy(operations, index, operations, dstPos, length);
if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
}
bucketStart[index] = start;
rxBytes[index] = 0;
rxPackets[index] = 0;
txBytes[index] = 0;
txPackets[index] = 0;
operations[index] = 0;
setLong(rxBytes, index, 0L);
setLong(rxPackets, index, 0L);
setLong(txBytes, index, 0L);
setLong(txPackets, index, 0L);
setLong(operations, index, 0L);
bucketCount++;
}
@@ -333,11 +356,11 @@ public class NetworkStatsHistory implements Parcelable {
if (i > 0) {
final int length = bucketStart.length;
bucketStart = Arrays.copyOfRange(bucketStart, i, length);
rxBytes = Arrays.copyOfRange(rxBytes, i, length);
rxPackets = Arrays.copyOfRange(rxPackets, i, length);
txBytes = Arrays.copyOfRange(txBytes, i, length);
txPackets = Arrays.copyOfRange(txPackets, i, length);
operations = Arrays.copyOfRange(operations, i, length);
if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
bucketCount -= i;
}
}
@@ -358,11 +381,11 @@ public class NetworkStatsHistory implements Parcelable {
final Entry entry = recycle != null ? recycle : new Entry();
entry.bucketStart = start;
entry.bucketDuration = end - start;
entry.rxBytes = 0;
entry.rxPackets = 0;
entry.txBytes = 0;
entry.txPackets = 0;
entry.operations = 0;
entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
entry.txBytes = txBytes != null ? 0 : UNKNOWN;
entry.txPackets = txPackets != null ? 0 : UNKNOWN;
entry.operations = operations != null ? 0 : UNKNOWN;
for (int i = bucketCount - 1; i >= 0; i--) {
final long curStart = bucketStart[i];
@@ -380,11 +403,11 @@ public class NetworkStatsHistory implements Parcelable {
if (overlap <= 0) continue;
// integer math each time is faster than floating point
entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
entry.txBytes += txBytes[i] * overlap / bucketDuration;
entry.txPackets += txPackets[i] * overlap / bucketDuration;
entry.operations += operations[i] * overlap / bucketDuration;
if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration;
if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
}
return entry;
@@ -394,19 +417,29 @@ public class NetworkStatsHistory implements Parcelable {
* @deprecated only for temporary testing
*/
@Deprecated
public void generateRandom(long start, long end, long rx, long tx) {
public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
long txPackets, long operations) {
ensureBuckets(start, end);
final NetworkStats.Entry entry = new NetworkStats.Entry(
IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0);
IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
final Random r = new Random();
while (rx > 1024 && tx > 1024) {
while (rxBytes > 1024 && rxPackets > 128 && txBytes > 1024 && txPackets > 128
&& operations > 32) {
final long curStart = randomLong(r, start, end);
final long curEnd = randomLong(r, curStart, end);
entry.rxBytes = randomLong(r, 0, rx);
entry.txBytes = randomLong(r, 0, tx);
rx -= entry.rxBytes;
tx -= entry.txBytes;
entry.rxBytes = randomLong(r, 0, rxBytes);
entry.rxPackets = randomLong(r, 0, rxPackets);
entry.txBytes = randomLong(r, 0, txBytes);
entry.txPackets = randomLong(r, 0, txPackets);
entry.operations = randomLong(r, 0, operations);
rxBytes -= entry.rxBytes;
rxPackets -= entry.rxPackets;
txBytes -= entry.txBytes;
txPackets -= entry.txPackets;
operations -= entry.operations;
recordData(curStart, curEnd, entry);
}
@@ -429,11 +462,12 @@ public class NetworkStatsHistory implements Parcelable {
for (int i = start; i < bucketCount; i++) {
pw.print(prefix);
pw.print(" bucketStart="); pw.print(bucketStart[i]);
pw.print(" rxBytes="); pw.print(rxBytes[i]);
pw.print(" rxPackets="); pw.print(rxPackets[i]);
pw.print(" txBytes="); pw.print(txBytes[i]);
pw.print(" txPackets="); pw.print(txPackets[i]);
pw.print(" operations="); pw.println(operations[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.println();
}
}
@@ -454,12 +488,25 @@ public class NetworkStatsHistory implements Parcelable {
}
};
private static long getLong(long[] array, int i, long value) {
return array != null ? array[i] : value;
}
private static void setLong(long[] array, int i, long value) {
if (array != null) array[i] = value;
}
private static void addLong(long[] array, int i, long value) {
if (array != null) array[i] += value;
}
/**
* Utility methods for interacting with {@link DataInputStream} and
* {@link DataOutputStream}, mostly dealing with writing partial arrays.
*/
public static class DataStreamUtils {
public static long[] readLongArray(DataInputStream in) throws IOException {
@Deprecated
public static long[] readFullLongArray(DataInputStream in) throws IOException {
final int size = in.readInt();
final long[] values = new long[size];
for (int i = 0; i < values.length; i++) {
@@ -468,14 +515,59 @@ public class NetworkStatsHistory implements Parcelable {
return values;
}
public static void writeLongArray(DataOutputStream out, long[] values, int size)
/**
* Read variable-length {@link Long} using protobuf-style approach.
*/
public static long readVarLong(DataInputStream in) throws IOException {
int shift = 0;
long result = 0;
while (shift < 64) {
byte b = in.readByte();
result |= (long) (b & 0x7F) << shift;
if ((b & 0x80) == 0)
return result;
shift += 7;
}
throw new ProtocolException("malformed long");
}
/**
* Write variable-length {@link Long} using protobuf-style approach.
*/
public static void writeVarLong(DataOutputStream out, long value) throws IOException {
while (true) {
if ((value & ~0x7FL) == 0) {
out.writeByte((int) value);
return;
} else {
out.writeByte(((int) value & 0x7F) | 0x80);
value >>>= 7;
}
}
}
public static long[] readVarLongArray(DataInputStream in) throws IOException {
final int size = in.readInt();
if (size == -1) return null;
final long[] values = new long[size];
for (int i = 0; i < values.length; i++) {
values[i] = readVarLong(in);
}
return values;
}
public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
throws IOException {
if (values == null) {
out.writeInt(-1);
return;
}
if (size > values.length) {
throw new IllegalArgumentException("size larger than length");
}
out.writeInt(size);
for (int i = 0; i < size; i++) {
out.writeLong(values[i]);
writeVarLong(out, values[i]);
}
}
}
@@ -487,6 +579,7 @@ public class NetworkStatsHistory implements Parcelable {
public static class ParcelUtils {
public static long[] readLongArray(Parcel in) {
final int size = in.readInt();
if (size == -1) return null;
final long[] values = new long[size];
for (int i = 0; i < values.length; i++) {
values[i] = in.readLong();
@@ -495,6 +588,10 @@ public class NetworkStatsHistory implements Parcelable {
}
public static void writeLongArray(Parcel out, long[] values, int size) {
if (values == null) {
out.writeInt(-1);
return;
}
if (size > values.length) {
throw new IllegalArgumentException("size larger than length");
}
@@ -503,25 +600,6 @@ public class NetworkStatsHistory implements Parcelable {
out.writeLong(values[i]);
}
}
public static int[] readIntArray(Parcel in) {
final int size = in.readInt();
final int[] values = new int[size];
for (int i = 0; i < values.length; i++) {
values[i] = in.readInt();
}
return values;
}
public static void writeIntArray(Parcel out, int[] values, int size) {
if (size > values.length) {
throw new IllegalArgumentException("size larger than length");
}
out.writeInt(size);
for (int i = 0; i < size; i++) {
out.writeInt(values[i]);
}
}
}
}

View File

@@ -16,10 +16,10 @@
package com.android.server.net;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
@@ -68,7 +68,6 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.NtpTrustedTime;
import android.util.Slog;
@@ -282,13 +281,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template) {
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) {
// combine all interfaces that match template
final NetworkStatsHistory combined = new NetworkStatsHistory(
mSettings.getNetworkBucketDuration(), estimateNetworkBuckets());
mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mNetworkStats.get(ident);
@@ -302,7 +301,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) {
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int tag, int fields) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) {
@@ -311,7 +311,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// combine all interfaces that match template
final NetworkStatsHistory combined = new NetworkStatsHistory(
mSettings.getUidBucketDuration(), estimateUidBuckets());
mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
for (NetworkIdentitySet ident : mUidStats.keySet()) {
if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mUidStats.get(ident).get(packed);
@@ -596,7 +596,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// decide if enough has changed to trigger persist
final NetworkStats persistDelta = computeStatsDelta(
mLastPersistNetworkSnapshot, networkSnapshot);
mLastPersistNetworkSnapshot, networkSnapshot, true);
final long persistThreshold = mSettings.getPersistThreshold();
NetworkStats.Entry entry = null;
@@ -626,7 +626,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) {
final HashSet<String> unknownIface = Sets.newHashSet();
final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot);
final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot, false);
final long timeStart = currentTime - delta.getElapsedRealtime();
NetworkStats.Entry entry = null;
@@ -661,9 +661,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
ensureUidStatsLoadedLocked();
final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot);
final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot, false);
final NetworkStats operationsDelta = computeStatsDelta(
mLastOperationsSnapshot, mOperations);
mLastOperationsSnapshot, mOperations, false);
final long timeStart = currentTime - delta.getElapsedRealtime();
NetworkStats.Entry entry = null;
@@ -932,6 +932,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
out.flush();
mNetworkFile.finishWrite(fos);
} catch (IOException e) {
Slog.w(TAG, "problem writing stats: ", e);
if (fos != null) {
mNetworkFile.failWrite(fos);
}
@@ -978,6 +979,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
out.flush();
mUidFile.finishWrite(fos);
} catch (IOException e) {
Slog.w(TAG, "problem writing stats: ", e);
if (fos != null) {
mUidFile.failWrite(fos);
}
@@ -1052,15 +1054,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
*/
@Deprecated
private void generateRandomLocked() {
long networkEnd = System.currentTimeMillis();
long networkStart = networkEnd - mSettings.getNetworkMaxHistory();
long networkRx = 3 * GB_IN_BYTES;
long networkTx = 2 * GB_IN_BYTES;
final long NET_END = System.currentTimeMillis();
final long NET_START = NET_END - mSettings.getNetworkMaxHistory();
final long NET_RX_BYTES = 3 * GB_IN_BYTES;
final long NET_RX_PACKETS = NET_RX_BYTES / 1024;
final long NET_TX_BYTES = 2 * GB_IN_BYTES;
final long NET_TX_PACKETS = NET_TX_BYTES / 1024;
long uidEnd = System.currentTimeMillis();
long uidStart = uidEnd - mSettings.getUidMaxHistory();
long uidRx = 500 * MB_IN_BYTES;
long uidTx = 100 * MB_IN_BYTES;
final long UID_END = System.currentTimeMillis();
final long UID_START = UID_END - mSettings.getUidMaxHistory();
final long UID_RX_BYTES = 500 * MB_IN_BYTES;
final long UID_RX_PACKETS = UID_RX_BYTES / 1024;
final long UID_TX_BYTES = 100 * MB_IN_BYTES;
final long UID_TX_PACKETS = UID_TX_BYTES / 1024;
final long UID_OPERATIONS = UID_RX_BYTES / 2048;
final List<ApplicationInfo> installedApps = mContext
.getPackageManager().getInstalledApplications(0);
@@ -1068,13 +1075,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mNetworkStats.clear();
mUidStats.clear();
for (NetworkIdentitySet ident : mActiveIfaces.values()) {
findOrCreateNetworkStatsLocked(ident).generateRandom(
networkStart, networkEnd, networkRx, networkTx);
findOrCreateNetworkStatsLocked(ident).generateRandom(NET_START, NET_END, NET_RX_BYTES,
NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L);
for (ApplicationInfo info : installedApps) {
final int uid = info.uid;
findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(
uidStart, uidEnd, uidRx, uidTx);
findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(UID_START, UID_END,
UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, UID_TX_PACKETS, UID_OPERATIONS);
}
}
}
@@ -1083,9 +1090,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* Return the delta between two {@link NetworkStats} snapshots, where {@code
* before} can be {@code null}.
*/
private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) {
private static NetworkStats computeStatsDelta(
NetworkStats before, NetworkStats current, boolean collectStale) {
if (before != null) {
return current.subtractClamped(before);
} else if (collectStale) {
// caller is okay collecting stale stats for first call.
return current;
} else {
// this is first snapshot; to prevent from double-counting we only
// observe traffic occuring between known snapshots.