Merge "Network stats with varint, omit parcel fields."
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -239,6 +239,11 @@ interface INetworkManagementService
|
||||
*/
|
||||
void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
|
||||
|
||||
/**
|
||||
* Return status of bandwidth control module.
|
||||
*/
|
||||
boolean isBandwidthControlEnabled();
|
||||
|
||||
/**
|
||||
* Configures bandwidth throttling on an interface.
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.net.NetworkStatsHistory.FIELD_ALL;
|
||||
import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
|
||||
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
|
||||
import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
|
||||
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
|
||||
import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
|
||||
import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
|
||||
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
|
||||
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;
|
||||
@@ -30,7 +38,10 @@ import android.util.Log;
|
||||
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.util.Random;
|
||||
|
||||
@SmallTest
|
||||
@@ -39,6 +50,10 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
|
||||
private static final long TEST_START = 1194220800000L;
|
||||
|
||||
private static final long KB_IN_BYTES = 1024;
|
||||
private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
|
||||
private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
|
||||
|
||||
private NetworkStatsHistory stats;
|
||||
|
||||
@Override
|
||||
@@ -80,10 +95,11 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||
|
||||
// record data into narrow window to get single bucket
|
||||
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
|
||||
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
|
||||
|
||||
assertEquals(1, stats.size());
|
||||
assertValues(stats, 0, 1024L, 2048L);
|
||||
assertValues(stats, 0, 1024L, 10L, 2048L, 20L, 2L);
|
||||
}
|
||||
|
||||
public void testRecordEqualBuckets() throws Exception {
|
||||
@@ -92,11 +108,12 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
|
||||
// split equally across two buckets
|
||||
final long recordStart = TEST_START + (bucketDuration / 2);
|
||||
stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L);
|
||||
stats.recordData(recordStart, recordStart + bucketDuration,
|
||||
new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
|
||||
|
||||
assertEquals(2, stats.size());
|
||||
assertValues(stats, 0, 512L, 64L);
|
||||
assertValues(stats, 1, 512L, 64L);
|
||||
assertValues(stats, 0, 512L, 5L, 64L, 1L, 1L);
|
||||
assertValues(stats, 1, 512L, 5L, 64L, 1L, 1L);
|
||||
}
|
||||
|
||||
public void testRecordTouchingBuckets() throws Exception {
|
||||
@@ -107,15 +124,16 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
// overlap into neighboring buckets. total record is 20 minutes.
|
||||
final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
|
||||
final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
|
||||
stats.recordData(recordStart, recordEnd, 1000L, 5000L);
|
||||
stats.recordData(recordStart, recordEnd,
|
||||
new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
|
||||
|
||||
assertEquals(3, stats.size());
|
||||
// first bucket should have (1/20 of value)
|
||||
assertValues(stats, 0, 50L, 250L);
|
||||
assertValues(stats, 0, 50L, 100L, 250L, 500L, 5L);
|
||||
// second bucket should have (15/20 of value)
|
||||
assertValues(stats, 1, 750L, 3750L);
|
||||
assertValues(stats, 1, 750L, 1500L, 3750L, 7500L, 75L);
|
||||
// final bucket should have (4/20 of value)
|
||||
assertValues(stats, 2, 200L, 1000L);
|
||||
assertValues(stats, 2, 200L, 400L, 1000L, 2000L, 20L);
|
||||
}
|
||||
|
||||
public void testRecordGapBuckets() throws Exception {
|
||||
@@ -125,25 +143,28 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
// record some data today and next week with large gap
|
||||
final long firstStart = TEST_START;
|
||||
final long lastStart = TEST_START + WEEK_IN_MILLIS;
|
||||
stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS, 128L, 256L);
|
||||
stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, 64L, 512L);
|
||||
stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
|
||||
new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
|
||||
stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
|
||||
new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
|
||||
|
||||
// we should have two buckets, far apart from each other
|
||||
assertEquals(2, stats.size());
|
||||
assertValues(stats, 0, 128L, 256L);
|
||||
assertValues(stats, 1, 64L, 512L);
|
||||
assertValues(stats, 0, 128L, 2L, 256L, 4L, 1L);
|
||||
assertValues(stats, 1, 64L, 1L, 512L, 8L, 2L);
|
||||
|
||||
// now record something in middle, spread across two buckets
|
||||
final long middleStart = TEST_START + DAY_IN_MILLIS;
|
||||
final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
|
||||
stats.recordData(middleStart, middleEnd, 2048L, 2048L);
|
||||
stats.recordData(middleStart, middleEnd,
|
||||
new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
|
||||
|
||||
// now should have four buckets, with new record in middle two buckets
|
||||
assertEquals(4, stats.size());
|
||||
assertValues(stats, 0, 128L, 256L);
|
||||
assertValues(stats, 1, 1024L, 1024L);
|
||||
assertValues(stats, 2, 1024L, 1024L);
|
||||
assertValues(stats, 3, 64L, 512L);
|
||||
assertValues(stats, 0, 128L, 2L, 256L, 4L, 1L);
|
||||
assertValues(stats, 1, 1024L, 2L, 1024L, 2L, 1L);
|
||||
assertValues(stats, 2, 1024L, 2L, 1024L, 2L, 1L);
|
||||
assertValues(stats, 3, 64L, 1L, 512L, 8L, 2L);
|
||||
}
|
||||
|
||||
public void testRecordOverlapBuckets() throws Exception {
|
||||
@@ -151,14 +172,16 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||
|
||||
// record some data in one bucket, and another overlapping buckets
|
||||
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L);
|
||||
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
|
||||
new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
|
||||
final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
|
||||
stats.recordData(midStart, midStart + HOUR_IN_MILLIS, 1024L, 1024L);
|
||||
stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
|
||||
new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
|
||||
|
||||
// should have two buckets, with some data mixed together
|
||||
assertEquals(2, stats.size());
|
||||
assertValues(stats, 0, 768L, 768L);
|
||||
assertValues(stats, 1, 512L, 512L);
|
||||
assertValues(stats, 0, 768L, 7L, 768L, 7L, 6L);
|
||||
assertValues(stats, 1, 512L, 5L, 512L, 5L, 5L);
|
||||
}
|
||||
|
||||
public void testRecordEntireGapIdentical() throws Exception {
|
||||
@@ -283,6 +306,7 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
public void testFuzzing() throws Exception {
|
||||
try {
|
||||
// fuzzing with random events, looking for crashes
|
||||
final NetworkStats.Entry entry = new NetworkStats.Entry();
|
||||
final Random r = new Random();
|
||||
for (int i = 0; i < 500; i++) {
|
||||
stats = new NetworkStatsHistory(r.nextLong());
|
||||
@@ -291,7 +315,12 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
// add range
|
||||
final long start = r.nextLong();
|
||||
final long end = start + r.nextInt();
|
||||
stats.recordData(start, end, r.nextLong(), r.nextLong());
|
||||
entry.rxBytes = nextPositiveLong(r);
|
||||
entry.rxPackets = nextPositiveLong(r);
|
||||
entry.txBytes = nextPositiveLong(r);
|
||||
entry.txPackets = nextPositiveLong(r);
|
||||
entry.operations = nextPositiveLong(r);
|
||||
stats.recordData(start, end, entry);
|
||||
} else {
|
||||
// trim something
|
||||
stats.removeBucketsBefore(r.nextLong());
|
||||
@@ -305,6 +334,88 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private static long nextPositiveLong(Random r) {
|
||||
final long value = r.nextLong();
|
||||
return value < 0 ? -value : value;
|
||||
}
|
||||
|
||||
public void testIgnoreFields() throws Exception {
|
||||
final NetworkStatsHistory history = new NetworkStatsHistory(
|
||||
MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
|
||||
|
||||
history.recordData(0, MINUTE_IN_MILLIS,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||
history.recordData(0, MINUTE_IN_MILLIS * 2,
|
||||
new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
|
||||
|
||||
assertValues(
|
||||
history, Long.MIN_VALUE, Long.MAX_VALUE, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
|
||||
}
|
||||
|
||||
public void testIgnoreFieldsRecordIn() throws Exception {
|
||||
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
|
||||
final NetworkStatsHistory partial = new NetworkStatsHistory(
|
||||
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
|
||||
|
||||
full.recordData(0, MINUTE_IN_MILLIS,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||
partial.recordEntireHistory(full);
|
||||
|
||||
assertValues(partial, Long.MIN_VALUE, Long.MAX_VALUE, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
|
||||
}
|
||||
|
||||
public void testIgnoreFieldsRecordOut() throws Exception {
|
||||
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
|
||||
final NetworkStatsHistory partial = new NetworkStatsHistory(
|
||||
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
|
||||
|
||||
partial.recordData(0, MINUTE_IN_MILLIS,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||
full.recordEntireHistory(partial);
|
||||
|
||||
assertValues(full, Long.MIN_VALUE, Long.MAX_VALUE, 0L, 10L, 0L, 0L, 4L);
|
||||
}
|
||||
|
||||
public void testSerialize() throws Exception {
|
||||
final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
|
||||
before.recordData(0, MINUTE_IN_MILLIS * 4,
|
||||
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
|
||||
before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
|
||||
new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
|
||||
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
before.writeToStream(new DataOutputStream(out));
|
||||
out.close();
|
||||
|
||||
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
|
||||
|
||||
// must have identical totals before and after
|
||||
assertValues(before, Long.MIN_VALUE, Long.MAX_VALUE, 1034L, 30L, 2078L, 60L, 54L);
|
||||
assertValues(after, Long.MIN_VALUE, Long.MAX_VALUE, 1034L, 30L, 2078L, 60L, 54L);
|
||||
}
|
||||
|
||||
public void testVarLong() throws Exception {
|
||||
assertEquals(0L, performVarLong(0L));
|
||||
assertEquals(-1L, performVarLong(-1L));
|
||||
assertEquals(1024L, performVarLong(1024L));
|
||||
assertEquals(-1024L, performVarLong(-1024L));
|
||||
assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
|
||||
assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
|
||||
assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
|
||||
assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
|
||||
assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
|
||||
assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
|
||||
}
|
||||
|
||||
private static long performVarLong(long before) throws Exception {
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
writeVarLong(new DataOutputStream(out), before);
|
||||
|
||||
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
return readVarLong(new DataInputStream(in));
|
||||
}
|
||||
|
||||
private static void assertConsistent(NetworkStatsHistory stats) {
|
||||
// verify timestamps are monotonic
|
||||
long lastStart = Long.MIN_VALUE;
|
||||
@@ -330,4 +441,23 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
|
||||
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
|
||||
}
|
||||
|
||||
private static void assertValues(NetworkStatsHistory stats, int index, long rxBytes,
|
||||
long rxPackets, long txBytes, long txPackets, long operations) {
|
||||
final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
|
||||
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
|
||||
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
|
||||
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
|
||||
assertEquals("unexpected txPackets", txPackets, entry.txPackets);
|
||||
assertEquals("unexpected operations", operations, entry.operations);
|
||||
}
|
||||
|
||||
private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes,
|
||||
long rxPackets, long txBytes, long txPackets, long operations) {
|
||||
final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
|
||||
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
|
||||
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
|
||||
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
|
||||
assertEquals("unexpected txPackets", txPackets, entry.txPackets);
|
||||
assertEquals("unexpected operations", operations, entry.operations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1231,6 +1231,13 @@ class NetworkManagementService extends INetworkManagementService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBandwidthControlEnabled() {
|
||||
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
|
||||
return mBandwidthControlEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkStats getNetworkStatsUidDetail(int uid) {
|
||||
if (Binder.getCallingUid() != uid) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.net.ConnectivityManager.TYPE_WIMAX;
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.NetworkStatsHistory.FIELD_ALL;
|
||||
import static android.net.NetworkTemplate.buildTemplateMobileAll;
|
||||
import static android.net.NetworkTemplate.buildTemplateWifi;
|
||||
import static android.net.TrafficStats.UID_REMOVED;
|
||||
@@ -302,7 +303,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||
|
||||
// verify service recorded history
|
||||
history = mService.getHistoryForNetwork(sTemplateWifi);
|
||||
history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
|
||||
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
|
||||
assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
|
||||
assertEquals(2, history.size());
|
||||
@@ -319,7 +320,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||
|
||||
// verify identical stats, but spread across 4 buckets now
|
||||
history = mService.getHistoryForNetwork(sTemplateWifi);
|
||||
history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
|
||||
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
|
||||
assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
|
||||
assertEquals(4, history.size());
|
||||
@@ -631,14 +632,15 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
|
||||
|
||||
private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
|
||||
long txBytes, long txPackets, int operations) {
|
||||
final NetworkStatsHistory history = mService.getHistoryForNetwork(template);
|
||||
final NetworkStatsHistory history = mService.getHistoryForNetwork(template, FIELD_ALL);
|
||||
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
|
||||
txPackets, operations);
|
||||
}
|
||||
|
||||
private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
|
||||
long txBytes, long txPackets, int operations) {
|
||||
final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE);
|
||||
final NetworkStatsHistory history = mService.getHistoryForUid(
|
||||
template, uid, TAG_NONE, FIELD_ALL);
|
||||
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
|
||||
txPackets, operations);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user