Account for interpolation loss in cumulative network stats
Bug: 352537247
Test: atest FrameworksServicesTests:NetworkStatsAccumulatorTest
Flag: com.android.server.stats.accumulate_network_stats_since_boot
Change-Id: I95a04c3b32bc8379f3cb9453f29df67ae87eefae
diff --git a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java
index e798bc4..3f7fcee 100644
--- a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java
+++ b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
+import android.util.Log;
import java.util.Objects;
@@ -33,6 +34,7 @@
*/
public class NetworkStatsAccumulator {
+ private static final String TAG = "NetworkStatsAccumulator";
private final NetworkTemplate mTemplate;
private final boolean mWithTags;
private final long mBucketDurationMillis;
@@ -57,8 +59,9 @@
@NonNull
public NetworkStats queryStats(long currentTimeMillis,
@NonNull StatsQueryFunction queryFunction) {
- maybeExpandSnapshot(currentTimeMillis, queryFunction);
- return snapshotPlusFollowingStats(currentTimeMillis, queryFunction);
+ NetworkStats completeStats = snapshotPlusFollowingStats(currentTimeMillis, queryFunction);
+ maybeExpandSnapshot(currentTimeMillis, completeStats, queryFunction);
+ return completeStats;
}
/**
@@ -72,15 +75,28 @@
* Expands the internal cumulative stats snapshot, if possible, by querying NetworkStats.
*/
private void maybeExpandSnapshot(long currentTimeMillis,
+ NetworkStats completeStatsUntilCurrentTime,
@NonNull StatsQueryFunction queryFunction) {
// Update snapshot only if it is possible to expand it by at least one full bucket, and only
// if the new snapshot's end is not in the active bucket.
long newEndTimeMillis = currentTimeMillis - mBucketDurationMillis;
if (newEndTimeMillis - mSnapshotEndTimeMillis > mBucketDurationMillis) {
- NetworkStats extraStats = queryFunction.queryNetworkStats(mTemplate, mWithTags,
- mSnapshotEndTimeMillis, newEndTimeMillis);
+ Log.v(TAG,
+ "Expanding snapshot (mTemplate=" + mTemplate + ", mWithTags=" + mWithTags
+ + ") from " + mSnapshotEndTimeMillis + " to " + newEndTimeMillis
+ + " at " + currentTimeMillis);
+ NetworkStats extraStats = queryFunction.queryNetworkStats(
+ mTemplate, mWithTags, mSnapshotEndTimeMillis, newEndTimeMillis);
mSnapshot = mSnapshot.add(extraStats);
mSnapshotEndTimeMillis = newEndTimeMillis;
+
+ // NetworkStats queries interpolate historical data using integers maths, which makes
+ // queries non-transitive: Query(t0, t1) + Query(t1, t2) <= Query(t0, t2).
+ // Compute interpolation data loss from moving the snapshot's end-point, and add it to
+ // the snapshot to avoid under-counting.
+ NetworkStats newStats = snapshotPlusFollowingStats(currentTimeMillis, queryFunction);
+ NetworkStats interpolationLoss = completeStatsUntilCurrentTime.subtract(newStats);
+ mSnapshot = mSnapshot.add(interpolationLoss);
}
}