Skip to content

Commit 70c7053

Browse files
committed
Transition from DEV network stats to XT.
When XT stats are available, transition to prefer them over DEV, since they aren't subject to hardware driver bugs. Only switches at the first atomic XT bucket, and adds a Settings.Secure flag to force back to DEV if needed. Includes tests to cover transition. Fix tests where device overlay would change which network types reflected data usage. Test both history and summary APIs. Fixed collection timestamps to reflect full buckets. Bug: 6504744 Change-Id: Idd7f3b2fdb064c36547c85c51c214fd938c59b7e
1 parent 559146f commit 70c7053

File tree

8 files changed

+248
-15
lines changed

8 files changed

+248
-15
lines changed

core/java/android/net/NetworkStats.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ public boolean isEmpty() {
111111
&& operations == 0;
112112
}
113113

114+
public void add(Entry another) {
115+
this.rxBytes += another.rxBytes;
116+
this.rxPackets += another.rxPackets;
117+
this.txBytes += another.txBytes;
118+
this.txPackets += another.txPackets;
119+
this.operations += another.operations;
120+
}
121+
114122
@Override
115123
public String toString() {
116124
final StringBuilder builder = new StringBuilder();

core/java/android/net/NetworkStatsHistory.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,19 +342,31 @@ public void recordData(long start, long end, NetworkStats.Entry entry) {
342342
* for combining together stats for external reporting.
343343
*/
344344
public void recordEntireHistory(NetworkStatsHistory input) {
345+
recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE);
346+
}
347+
348+
/**
349+
* Record given {@link NetworkStatsHistory} into this history, copying only
350+
* buckets that atomically occur in the inclusive time range. Doesn't
351+
* interpolate across partial buckets.
352+
*/
353+
public void recordHistory(NetworkStatsHistory input, long start, long end) {
345354
final NetworkStats.Entry entry = new NetworkStats.Entry(
346355
IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
347356
for (int i = 0; i < input.bucketCount; i++) {
348-
final long start = input.bucketStart[i];
349-
final long end = start + input.bucketDuration;
357+
final long bucketStart = input.bucketStart[i];
358+
final long bucketEnd = bucketStart + input.bucketDuration;
359+
360+
// skip when bucket is outside requested range
361+
if (bucketStart < start || bucketEnd > end) continue;
350362

351363
entry.rxBytes = getLong(input.rxBytes, i, 0L);
352364
entry.rxPackets = getLong(input.rxPackets, i, 0L);
353365
entry.txBytes = getLong(input.txBytes, i, 0L);
354366
entry.txPackets = getLong(input.txPackets, i, 0L);
355367
entry.operations = getLong(input.operations, i, 0L);
356368

357-
recordData(start, end, entry);
369+
recordData(bucketStart, bucketEnd, entry);
358370
}
359371
}
360372

core/java/android/net/NetworkTemplate.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ public class NetworkTemplate implements Parcelable {
6161
com.android.internal.R.array.config_data_usage_network_types);
6262
}
6363

64+
private static boolean sForceAllNetworkTypes = false;
65+
66+
// @VisibleForTesting
67+
public static void forceAllNetworkTypes() {
68+
sForceAllNetworkTypes = true;
69+
}
70+
6471
/**
6572
* Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
6673
* the given IMSI.
@@ -225,7 +232,7 @@ private boolean matchesMobile(NetworkIdentity ident) {
225232
// TODO: consider matching against WiMAX subscriber identity
226233
return true;
227234
} else {
228-
return (contains(DATA_USAGE_NETWORK_TYPES, ident.mType)
235+
return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType))
229236
&& Objects.equal(mSubscriberId, ident.mSubscriberId));
230237
}
231238
}
@@ -291,7 +298,7 @@ private boolean matchesMobileWildcard(NetworkIdentity ident) {
291298
if (ident.mType == TYPE_WIMAX) {
292299
return true;
293300
} else {
294-
return contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
301+
return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
295302
}
296303
}
297304

core/java/android/provider/Settings.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4210,6 +4210,8 @@ public static final String getBluetoothInputDevicePriorityKey(String address) {
42104210
public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
42114211
/** {@hide} */
42124212
public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
4213+
/** {@hide} */
4214+
public static final String NETSTATS_REPORT_XT_OVER_DEV = "netstats_report_xt_over_dev";
42134215

42144216
/** {@hide} */
42154217
public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";

services/java/com/android/server/net/NetworkStatsCollection.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
7171

7272
private HashMap<Key, NetworkStatsHistory> mStats = Maps.newHashMap();
7373

74-
private long mBucketDuration;
74+
private final long mBucketDuration;
7575

7676
private long mStartMillis;
7777
private long mEndMillis;
@@ -95,6 +95,18 @@ public long getStartMillis() {
9595
return mStartMillis;
9696
}
9797

98+
/**
99+
* Return first atomic bucket in this collection, which is more conservative
100+
* than {@link #mStartMillis}.
101+
*/
102+
public long getFirstAtomicBucketMillis() {
103+
if (mStartMillis == Long.MAX_VALUE) {
104+
return Long.MAX_VALUE;
105+
} else {
106+
return mStartMillis + mBucketDuration;
107+
}
108+
}
109+
98110
public long getEndMillis() {
99111
return mEndMillis;
100112
}
@@ -121,14 +133,23 @@ public boolean isEmpty() {
121133
*/
122134
public NetworkStatsHistory getHistory(
123135
NetworkTemplate template, int uid, int set, int tag, int fields) {
136+
return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE);
137+
}
138+
139+
/**
140+
* Combine all {@link NetworkStatsHistory} in this collection which match
141+
* the requested parameters.
142+
*/
143+
public NetworkStatsHistory getHistory(
144+
NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
124145
final NetworkStatsHistory combined = new NetworkStatsHistory(
125146
mBucketDuration, estimateBuckets(), fields);
126147
for (Map.Entry<Key, NetworkStatsHistory> entry : mStats.entrySet()) {
127148
final Key key = entry.getKey();
128149
final boolean setMatches = set == SET_ALL || key.set == set;
129150
if (key.uid == uid && setMatches && key.tag == tag
130151
&& templateMatches(template, key.ident)) {
131-
combined.recordEntireHistory(entry.getValue());
152+
combined.recordHistory(entry.getValue(), start, end);
132153
}
133154
}
134155
return combined;
@@ -145,6 +166,9 @@ public NetworkStats getSummary(NetworkTemplate template, long start, long end) {
145166
final NetworkStats.Entry entry = new NetworkStats.Entry();
146167
NetworkStatsHistory.Entry historyEntry = null;
147168

169+
// shortcut when we know stats will be empty
170+
if (start == end) return stats;
171+
148172
for (Map.Entry<Key, NetworkStatsHistory> mapEntry : mStats.entrySet()) {
149173
final Key key = mapEntry.getKey();
150174
if (templateMatches(template, key.ident)) {
@@ -175,8 +199,9 @@ public NetworkStats getSummary(NetworkTemplate template, long start, long end) {
175199
*/
176200
public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start,
177201
long end, NetworkStats.Entry entry) {
178-
noteRecordedHistory(start, end, entry.rxBytes + entry.txBytes);
179-
findOrCreateHistory(ident, uid, set, tag).recordData(start, end, entry);
202+
final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag);
203+
history.recordData(start, end, entry);
204+
noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes);
180205
}
181206

182207
/**

services/java/com/android/server/net/NetworkStatsService.java

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import static android.provider.Settings.Secure.NETSTATS_DEV_ROTATE_AGE;
4545
import static android.provider.Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES;
4646
import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
47+
import static android.provider.Settings.Secure.NETSTATS_REPORT_XT_OVER_DEV;
4748
import static android.provider.Settings.Secure.NETSTATS_SAMPLE_ENABLED;
4849
import static android.provider.Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE;
4950
import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
@@ -177,6 +178,7 @@ public interface NetworkStatsSettings {
177178
public long getPollInterval();
178179
public long getTimeCacheMaxAge();
179180
public boolean getSampleEnabled();
181+
public boolean getReportXtOverDev();
180182

181183
public static class Config {
182184
public final long bucketDuration;
@@ -221,6 +223,8 @@ public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) {
221223

222224
/** Cached {@link #mDevRecorder} stats. */
223225
private NetworkStatsCollection mDevStatsCached;
226+
/** Cached {@link #mXtRecorder} stats. */
227+
private NetworkStatsCollection mXtStatsCached;
224228

225229
/** Current counter sets for each UID. */
226230
private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
@@ -295,6 +299,7 @@ public void systemReady() {
295299
// read historical network stats from disk, since policy service
296300
// might need them right away.
297301
mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked();
302+
mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked();
298303

299304
// bootstrap initial stats to prevent double-counting later
300305
bootstrapStatsLocked();
@@ -371,6 +376,7 @@ private void shutdownLocked() {
371376
mUidTagRecorder = null;
372377

373378
mDevStatsCached = null;
379+
mXtStatsCached = null;
374380

375381
mSystemReady = false;
376382
}
@@ -469,12 +475,12 @@ private NetworkStatsCollection getUidTagComplete() {
469475
@Override
470476
public NetworkStats getSummaryForNetwork(
471477
NetworkTemplate template, long start, long end) {
472-
return mDevStatsCached.getSummary(template, start, end);
478+
return internalGetSummaryForNetwork(template, start, end);
473479
}
474480

475481
@Override
476482
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
477-
return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
483+
return internalGetHistoryForNetwork(template, fields);
478484
}
479485

480486
@Override
@@ -507,11 +513,56 @@ public void close() {
507513
};
508514
}
509515

516+
/**
517+
* Return network summary, splicing between {@link #mDevStatsCached}
518+
* and {@link #mXtStatsCached} when appropriate.
519+
*/
520+
private NetworkStats internalGetSummaryForNetwork(
521+
NetworkTemplate template, long start, long end) {
522+
if (!mSettings.getReportXtOverDev()) {
523+
// shortcut when XT reporting disabled
524+
return mDevStatsCached.getSummary(template, start, end);
525+
}
526+
527+
// splice stats between DEV and XT, switching over from DEV to XT at
528+
// first atomic bucket.
529+
final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
530+
final NetworkStats dev = mDevStatsCached.getSummary(
531+
template, Math.min(start, firstAtomicBucket), Math.min(end, firstAtomicBucket));
532+
final NetworkStats xt = mXtStatsCached.getSummary(
533+
template, Math.max(start, firstAtomicBucket), Math.max(end, firstAtomicBucket));
534+
535+
xt.combineAllValues(dev);
536+
return xt;
537+
}
538+
539+
/**
540+
* Return network history, splicing between {@link #mDevStatsCached}
541+
* and {@link #mXtStatsCached} when appropriate.
542+
*/
543+
private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) {
544+
if (!mSettings.getReportXtOverDev()) {
545+
// shortcut when XT reporting disabled
546+
return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
547+
}
548+
549+
// splice stats between DEV and XT, switching over from DEV to XT at
550+
// first atomic bucket.
551+
final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
552+
final NetworkStatsHistory dev = mDevStatsCached.getHistory(
553+
template, UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, firstAtomicBucket);
554+
final NetworkStatsHistory xt = mXtStatsCached.getHistory(
555+
template, UID_ALL, SET_ALL, TAG_NONE, fields, firstAtomicBucket, Long.MAX_VALUE);
556+
557+
xt.recordEntireHistory(dev);
558+
return xt;
559+
}
560+
510561
@Override
511562
public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
512563
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
513564
assertBandwidthControlEnabled();
514-
return mDevStatsCached.getSummary(template, start, end).getTotalBytes();
565+
return internalGetSummaryForNetwork(template, start, end).getTotalBytes();
515566
}
516567

517568
@Override
@@ -1190,6 +1241,10 @@ public boolean getSampleEnabled() {
11901241
return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true);
11911242
}
11921243
@Override
1244+
public boolean getReportXtOverDev() {
1245+
return getSecureBoolean(NETSTATS_REPORT_XT_OVER_DEV, true);
1246+
}
1247+
@Override
11931248
public Config getDevConfig() {
11941249
return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
11951250
getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),

0 commit comments

Comments
 (0)