Clamp non-monotonic stats instead of dropping.
When encountering non-monotonic stats rows, recover remaining data by
clamping to 0. In particular, this avoids edge-case where persisting
threshold checks would never trigger. Also recover when tethering
snapshots are missing.
Bug: 5600785, 5433871, 5600678
Change-Id: I1871954ce3955cc4ac8846f9841bae0066176ffe
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 3605652..f6e627c 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -464,6 +464,19 @@
* time, and that none of them have disappeared.
*/
public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
+ return subtract(value, 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.
+ *
+ * @param clampNonMonotonic When non-monotonic stats are found, just clamp
+ * to 0 instead of throwing {@link NonMonotonicException}.
+ */
+ public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic)
+ throws NonMonotonicException {
final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
if (deltaRealtime < 0) {
throw new NonMonotonicException(this, value);
@@ -497,7 +510,15 @@
if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
|| entry.txPackets < 0 || entry.operations < 0) {
- throw new NonMonotonicException(this, i, value, j);
+ if (clampNonMonotonic) {
+ entry.rxBytes = Math.max(entry.rxBytes, 0);
+ entry.rxPackets = Math.max(entry.rxPackets, 0);
+ entry.txBytes = Math.max(entry.txBytes, 0);
+ entry.txPackets = Math.max(entry.txPackets, 0);
+ entry.operations = Math.max(entry.operations, 0);
+ } else {
+ throw new NonMonotonicException(this, i, value, j);
+ }
}
}