Persist network stats using AtomicFile.
Implements read/write of network stats using AtomicFile, along with
magic number and versioning. Stores in "/data/system/netstats.bin"
for now. Tests to verify that stats are persisted across a simulated
reboot, and to verify that TEMPLATE_WIFI is working.
Fixed bug where kernel counters rolling backwards would cause negative
stats to be recorded; now we clamp deltas at 0.
Change-Id: I53bce26fc8fd3f4ab1e34ce135d302edfa34db34
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index d38d16c..d05c9d3 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -28,6 +28,6 @@
NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate);
/** Return usage summary per UID for traffic that matches template. */
- NetworkStats getSummaryPerUid(long start, long end, int networkTemplate);
+ NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate);
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index ee415fa..6354e9a 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -158,10 +158,37 @@
* between two snapshots in time. Assumes that statistics rows collect over
* time, and that none of them have disappeared.
*
+ * @throws IllegalArgumentException when given {@link NetworkStats} is
+ * non-monotonic.
+ */
+ public NetworkStats subtract(NetworkStats value) {
+ return subtract(value, true, false);
+ }
+
+ /**
+ * Subtract the given {@link NetworkStats}, effectively leaving the delta
+ * between two snapshots in time. Assumes that statistics rows collect over
+ * time, and that none of them have disappeared.
+ * <p>
+ * Instead of throwing when counters are non-monotonic, this variant clamps
+ * results to never be negative.
+ */
+ public NetworkStats subtractClamped(NetworkStats value) {
+ return subtract(value, false, true);
+ }
+
+ /**
+ * Subtract the given {@link NetworkStats}, effectively leaving the delta
+ * between two snapshots in time. Assumes that statistics rows collect over
+ * time, and that none of them have disappeared.
+ *
* @param enforceMonotonic Validate that incoming value is strictly
* monotonic compared to this object.
+ * @param clampNegative Instead of throwing like {@code enforceMonotonic},
+ * clamp resulting counters at 0 to prevent negative values.
*/
- public NetworkStats subtract(NetworkStats value, boolean enforceMonotonic) {
+ private NetworkStats subtract(
+ NetworkStats value, boolean enforceMonotonic, boolean clampNegative) {
final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
if (enforceMonotonic && deltaRealtime < 0) {
throw new IllegalArgumentException("found non-monotonic realtime");
@@ -181,11 +208,15 @@
result.addEntry(iface, uid, this.rx[i], this.tx[i]);
} else {
// existing row, subtract remote value
- final long rx = this.rx[i] - value.rx[j];
- final long tx = this.tx[i] - value.tx[j];
+ long rx = this.rx[i] - value.rx[j];
+ long tx = this.tx[i] - value.tx[j];
if (enforceMonotonic && (rx < 0 || tx < 0)) {
throw new IllegalArgumentException("found non-monotonic values");
}
+ if (clampNegative) {
+ rx = Math.max(0, rx);
+ tx = Math.max(0, tx);
+ }
result.addEntry(iface, uid, rx, tx);
}
}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 5edbf58..a697e96 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -218,7 +218,7 @@
* Return interpolated data usage across the requested range. Interpolates
* across buckets, so values may be rounded slightly.
*/
- public void getTotalData(long start, long end, long[] outTotal) {
+ public long[] getTotalData(long start, long end, long[] outTotal) {
long rx = 0;
long tx = 0;
@@ -238,8 +238,12 @@
}
}
+ if (outTotal == null || outTotal.length != 2) {
+ outTotal = new long[2];
+ }
outTotal[0] = rx;
outTotal[1] = tx;
+ return outTotal;
}
/**
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index a0738c1..8a688d5 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -177,8 +177,8 @@
// subtract starting values and return delta
final NetworkStats profilingStop = getNetworkStatsForUid(context);
- final NetworkStats profilingDelta = profilingStop.subtract(
- sActiveProfilingStart, false);
+ final NetworkStats profilingDelta = profilingStop.subtractClamped(
+ sActiveProfilingStart);
sActiveProfilingStart = null;
return profilingDelta;
}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 23eb9cf..8a3e871 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -47,7 +47,7 @@
.addEntry(TEST_IFACE, 100, 1024, 0)
.addEntry(TEST_IFACE, 101, 0, 1024).build();
- final NetworkStats result = after.subtract(before, true);
+ final NetworkStats result = after.subtract(before);
// identical data should result in zero delta
assertEquals(0, result.rx[0]);
@@ -65,7 +65,7 @@
.addEntry(TEST_IFACE, 100, 1025, 2)
.addEntry(TEST_IFACE, 101, 3, 1028).build();
- final NetworkStats result = after.subtract(before, true);
+ final NetworkStats result = after.subtract(before);
// expect delta between measurements
assertEquals(1, result.rx[0]);
@@ -84,7 +84,7 @@
.addEntry(TEST_IFACE, 101, 0, 1024)
.addEntry(TEST_IFACE, 102, 1024, 1024).build();
- final NetworkStats result = after.subtract(before, true);
+ final NetworkStats result = after.subtract(before);
// its okay to have new rows
assertEquals(0, result.rx[0]);