Skip to content

Commit 1f0b13b

Browse files
committed
DO NOT MERGE: Sample atomic network stats buckets, full poll.
When sampling network stats, always use atomic buckets instead of interpolating. Always poll iface and UID together so we distribute into buckets equally. Move stale bucket trimming to just before writing stats. Bug: 5321340 Change-Id: I78a2226778a79c875f3668336e39ea24a7b4d5c4
1 parent cdd02c5 commit 1f0b13b

File tree

5 files changed

+89
-106
lines changed

5 files changed

+89
-106
lines changed

core/java/android/net/NetworkStatsHistory.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,10 @@ public Entry getValues(long start, long end, long now, Entry recycle) {
441441
final long curStart = bucketStart[i];
442442
final long curEnd = curStart + bucketDuration;
443443

444-
// bucket is older than record; we're finished
445-
if (curEnd < start) break;
446-
// bucket is newer than record; keep looking
447-
if (curStart > end) continue;
444+
// bucket is older than request; we're finished
445+
if (curEnd <= start) break;
446+
// bucket is newer than request; keep looking
447+
if (curStart >= end) continue;
448448

449449
// include full value for active buckets, otherwise only fractional
450450
final boolean activeBucket = curStart < now && curEnd > now;
@@ -466,7 +466,6 @@ public Entry getValues(long start, long end, long now, Entry recycle) {
466466
if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
467467
if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
468468
}
469-
470469
return entry;
471470
}
472471

core/java/android/provider/Settings.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4031,8 +4031,6 @@ public static final String getBluetoothInputDevicePriorityKey(String address) {
40314031
public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history";
40324032
/** {@hide} */
40334033
public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history";
4034-
/** {@hide} */
4035-
public static final String NETSTATS_FORCE_COMPLETE_POLL = "netstats_force_complete_poll";
40364034

40374035
/** Preferred NTP server. {@hide} */
40384036
public static final String NTP_SERVER = "ntp_server";

services/java/com/android/server/EventLogTags.logtags

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,5 @@ option java_package com.android.server
142142
# ---------------------------
143143
# NetworkStatsService.java
144144
# ---------------------------
145-
51100 netstats_mobile_sample (iface_rx|2|2),(iface_tx|2|2),(uid_rx|2|2),(uid_tx|2|2)
146-
51101 netstats_wifi_sample (iface_rx|2|2),(iface_tx|2|2),(uid_rx|2|2),(uid_tx|2|2)
145+
51100 netstats_mobile_sample (iface_rx_bytes|2|2),(iface_tx_bytes|2|2),(iface_rx_pkts|2|1),(iface_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1)
146+
51101 netstats_wifi_sample (iface_rx_bytes|2|2),(iface_tx_bytes|2|2),(iface_rx_pkts|2|1),(iface_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1)

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

Lines changed: 78 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import static android.net.NetworkTemplate.buildTemplateWifi;
3737
import static android.net.TrafficStats.UID_REMOVED;
3838
import static android.net.TrafficStats.UID_TETHERING;
39-
import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL;
4039
import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
4140
import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
4241
import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
@@ -136,15 +135,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
136135
private static final int MSG_PERFORM_POLL = 0x1;
137136

138137
/** Flags to control detail level of poll event. */
139-
private static final int FLAG_POLL_NETWORK = 0x1;
140-
private static final int FLAG_POLL_UID = 0x2;
141-
private static final int FLAG_POLL_TETHER = 0x3;
142138
private static final int FLAG_PERSIST_NETWORK = 0x10;
143139
private static final int FLAG_PERSIST_UID = 0x20;
144-
private static final int FLAG_FORCE_PERSIST = 0x100;
145-
146-
private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID | FLAG_POLL_TETHER;
147140
private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
141+
private static final int FLAG_PERSIST_FORCE = 0x100;
148142

149143
private final Context mContext;
150144
private final INetworkManagementService mNetworkManager;
@@ -182,7 +176,6 @@ public interface NetworkStatsSettings {
182176
public long getUidMaxHistory();
183177
public long getTagMaxHistory();
184178
public long getTimeCacheMaxAge();
185-
public boolean getForceCompletePoll();
186179
}
187180

188181
private final Object mStatsLock = new Object();
@@ -529,7 +522,7 @@ public void setUidForeground(int uid, boolean uidForeground) {
529522
@Override
530523
public void forceUpdate() {
531524
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
532-
performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL);
525+
performPoll(FLAG_PERSIST_ALL);
533526
}
534527

535528
/**
@@ -561,7 +554,7 @@ public void onReceive(Context context, Intent intent) {
561554
public void onReceive(Context context, Intent intent) {
562555
// on background handler thread, and verified CONNECTIVITY_INTERNAL
563556
// permission above.
564-
performPoll(FLAG_POLL_TETHER);
557+
performPoll(FLAG_PERSIST_NETWORK);
565558
}
566559
};
567560

@@ -570,7 +563,7 @@ public void onReceive(Context context, Intent intent) {
570563
public void onReceive(Context context, Intent intent) {
571564
// on background handler thread, and verified UPDATE_DEVICE_STATS
572565
// permission above.
573-
performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL);
566+
performPoll(FLAG_PERSIST_ALL);
574567

575568
// verify that we're watching global alert
576569
registerGlobalAlert();
@@ -617,7 +610,7 @@ public void limitReached(String limitName, String iface) {
617610
if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
618611
// kick off background poll to collect network stats; UID stats
619612
// are handled during normal polling interval.
620-
final int flags = FLAG_POLL_NETWORK | FLAG_PERSIST_NETWORK;
613+
final int flags = FLAG_PERSIST_NETWORK;
621614
mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
622615

623616
// re-arm global alert for next update
@@ -639,10 +632,9 @@ private void updateIfacesLocked() {
639632
// isn't perfect, since the kernel may already be counting traffic from
640633
// the updated network.
641634

642-
// poll both network and UID stats, but only persist network stats,
643-
// since this codepath should stay fast. UID stats will be persisted
644-
// during next alarm poll event.
645-
performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_NETWORK);
635+
// poll, but only persist network stats to keep codepath fast. UID stats
636+
// will be persisted during next alarm poll event.
637+
performPollLocked(FLAG_PERSIST_NETWORK);
646638

647639
final NetworkState[] states;
648640
try {
@@ -706,21 +698,9 @@ private void performPollLocked(int flags) {
706698
if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
707699
final long startRealtime = SystemClock.elapsedRealtime();
708700

709-
boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0;
710-
boolean pollUid = (flags & FLAG_POLL_UID) != 0;
711-
boolean pollTether = (flags & FLAG_POLL_TETHER) != 0;
712-
713-
// when complete poll requested, any partial poll enables everything
714-
final boolean forceCompletePoll = mSettings.getForceCompletePoll();
715-
if (forceCompletePoll && (pollNetwork || pollUid || pollTether)) {
716-
pollNetwork = true;
717-
pollUid = true;
718-
pollTether = true;
719-
}
720-
721701
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
722702
final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
723-
final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0;
703+
final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
724704

725705
// try refreshing time source when stale
726706
if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
@@ -733,41 +713,36 @@ private void performPollLocked(int flags) {
733713
final long threshold = mSettings.getPersistThreshold();
734714

735715
try {
736-
if (pollNetwork) {
737-
final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary();
738-
performNetworkPollLocked(networkSnapshot, currentTime);
739-
740-
// persist when enough network data has occurred
741-
final NetworkStats persistNetworkDelta = computeStatsDelta(
742-
mLastPersistNetworkSnapshot, networkSnapshot, true);
743-
final boolean pastThreshold = persistNetworkDelta.getTotalBytes() > threshold;
744-
if (forcePersist || (persistNetwork && pastThreshold)) {
745-
writeNetworkStatsLocked();
746-
mLastPersistNetworkSnapshot = networkSnapshot;
747-
}
716+
// record network stats
717+
final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary();
718+
performNetworkPollLocked(networkSnapshot, currentTime);
719+
720+
// persist when enough network data has occurred
721+
final NetworkStats persistNetworkDelta = computeStatsDelta(
722+
mLastPersistNetworkSnapshot, networkSnapshot, true);
723+
final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold;
724+
if (persistForce || (persistNetwork && networkPastThreshold)) {
725+
writeNetworkStatsLocked();
726+
mLastPersistNetworkSnapshot = networkSnapshot;
748727
}
749728

750-
if (pollTether) {
751-
final String[] ifacePairs = mConnManager.getTetheredIfacePairs();
752-
final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
753-
ifacePairs);
754-
performTetherPollLocked(tetherSnapshot, currentTime);
755-
756-
// persisted during normal UID cycle below
757-
}
758-
759-
if (pollUid) {
760-
final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
761-
performUidPollLocked(uidSnapshot, currentTime);
762-
763-
// persist when enough network data has occurred
764-
final NetworkStats persistUidDelta = computeStatsDelta(
765-
mLastPersistUidSnapshot, uidSnapshot, true);
766-
final boolean pastThreshold = persistUidDelta.getTotalBytes() > threshold;
767-
if (forcePersist || (persistUid && pastThreshold)) {
768-
writeUidStatsLocked();
769-
mLastPersistUidSnapshot = uidSnapshot;
770-
}
729+
// record tethering stats; persisted during normal UID cycle below
730+
final String[] ifacePairs = mConnManager.getTetheredIfacePairs();
731+
final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
732+
ifacePairs);
733+
performTetherPollLocked(tetherSnapshot, currentTime);
734+
735+
// record uid stats
736+
final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
737+
performUidPollLocked(uidSnapshot, currentTime);
738+
739+
// persist when enough network data has occurred
740+
final NetworkStats persistUidDelta = computeStatsDelta(
741+
mLastPersistUidSnapshot, uidSnapshot, true);
742+
final boolean uidPastThreshold = persistUidDelta.getTotalBytes() > threshold;
743+
if (persistForce || (persistUid && uidPastThreshold)) {
744+
writeUidStatsLocked();
745+
mLastPersistUidSnapshot = uidSnapshot;
771746
}
772747
} catch (IllegalStateException e) {
773748
Log.wtf(TAG, "problem reading network stats", e);
@@ -781,9 +756,7 @@ private void performPollLocked(int flags) {
781756
}
782757

783758
// sample stats after each full poll
784-
if (pollNetwork && pollUid) {
785-
performSample();
786-
}
759+
performSample();
787760

788761
// finally, dispatch updated event to any listeners
789762
final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
@@ -813,12 +786,6 @@ private void performNetworkPollLocked(NetworkStats networkSnapshot, long current
813786
history.recordData(timeStart, currentTime, entry);
814787
}
815788

816-
// trim any history beyond max
817-
final long maxHistory = mSettings.getNetworkMaxHistory();
818-
for (NetworkStatsHistory history : mNetworkStats.values()) {
819-
history.removeBucketsBefore(currentTime - maxHistory);
820-
}
821-
822789
mLastPollNetworkSnapshot = networkSnapshot;
823790

824791
if (LOGD && unknownIface.size() > 0) {
@@ -862,20 +829,6 @@ private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
862829
history.recordData(timeStart, currentTime, entry);
863830
}
864831

865-
// trim any history beyond max
866-
final long maxUidHistory = mSettings.getUidMaxHistory();
867-
final long maxTagHistory = mSettings.getTagMaxHistory();
868-
for (UidStatsKey key : mUidStats.keySet()) {
869-
final NetworkStatsHistory history = mUidStats.get(key);
870-
871-
// detailed tags are trimmed sooner than summary in TAG_NONE
872-
if (key.tag == TAG_NONE) {
873-
history.removeBucketsBefore(currentTime - maxUidHistory);
874-
} else {
875-
history.removeBucketsBefore(currentTime - maxTagHistory);
876-
}
877-
}
878-
879832
mLastPollUidSnapshot = uidSnapshot;
880833
mLastPollOperationsSnapshot = mOperations;
881834
mOperations = new NetworkStats(0L, 10);
@@ -917,9 +870,13 @@ private void performTetherPollLocked(NetworkStats tetherSnapshot, long currentTi
917870
* Sample recent statistics summary into {@link EventLog}.
918871
*/
919872
private void performSample() {
920-
// take sample as total over last 4 hours
921-
final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
922-
final long start = end - (4 * HOUR_IN_MILLIS);
873+
final long largestBucketSize = Math.max(
874+
mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration());
875+
876+
// take sample as atomic buckets
877+
final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
878+
final long end = now - (now % largestBucketSize) + largestBucketSize;
879+
final long start = end - largestBucketSize;
923880

924881
NetworkTemplate template = null;
925882
NetworkStats.Entry ifaceTotal = null;
@@ -929,15 +886,17 @@ private void performSample() {
929886
template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
930887
ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
931888
uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
932-
EventLogTags.writeNetstatsMobileSample(
933-
ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes);
889+
EventLogTags.writeNetstatsMobileSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets,
890+
ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets,
891+
uidTotal.txBytes, uidTotal.rxPackets);
934892

935893
// collect wifi sample
936894
template = buildTemplateWifi();
937895
ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
938896
uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
939-
EventLogTags.writeNetstatsWifiSample(
940-
ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes);
897+
EventLogTags.writeNetstatsWifiSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets,
898+
ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets,
899+
uidTotal.txBytes, uidTotal.rxPackets);
941900
}
942901

943902
/**
@@ -1137,6 +1096,15 @@ private void writeNetworkStatsLocked() {
11371096

11381097
// TODO: consider duplicating stats and releasing lock while writing
11391098

1099+
// trim any history beyond max
1100+
if (mTime.hasCache()) {
1101+
final long currentTime = mTime.currentTimeMillis();
1102+
final long maxHistory = mSettings.getNetworkMaxHistory();
1103+
for (NetworkStatsHistory history : mNetworkStats.values()) {
1104+
history.removeBucketsBefore(currentTime - maxHistory);
1105+
}
1106+
}
1107+
11401108
FileOutputStream fos = null;
11411109
try {
11421110
fos = mNetworkFile.startWrite();
@@ -1172,6 +1140,23 @@ private void writeUidStatsLocked() {
11721140

11731141
// TODO: consider duplicating stats and releasing lock while writing
11741142

1143+
// trim any history beyond max
1144+
if (mTime.hasCache()) {
1145+
final long currentTime = mTime.currentTimeMillis();
1146+
final long maxUidHistory = mSettings.getUidMaxHistory();
1147+
final long maxTagHistory = mSettings.getTagMaxHistory();
1148+
for (UidStatsKey key : mUidStats.keySet()) {
1149+
final NetworkStatsHistory history = mUidStats.get(key);
1150+
1151+
// detailed tags are trimmed sooner than summary in TAG_NONE
1152+
if (key.tag == TAG_NONE) {
1153+
history.removeBucketsBefore(currentTime - maxUidHistory);
1154+
} else {
1155+
history.removeBucketsBefore(currentTime - maxTagHistory);
1156+
}
1157+
}
1158+
}
1159+
11751160
// build UidStatsKey lists grouped by ident
11761161
final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
11771162
for (UidStatsKey key : mUidStats.keySet()) {
@@ -1236,7 +1221,7 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
12361221
}
12371222

12381223
if (argSet.contains("poll")) {
1239-
performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_ALL | FLAG_FORCE_PERSIST);
1224+
performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
12401225
pw.println("Forced poll");
12411226
return;
12421227
}
@@ -1464,8 +1449,5 @@ public long getTagMaxHistory() {
14641449
public long getTimeCacheMaxAge() {
14651450
return DAY_IN_MILLIS;
14661451
}
1467-
public boolean getForceCompletePoll() {
1468-
return getSecureBoolean(NETSTATS_FORCE_COMPLETE_POLL, false);
1469-
}
14701452
}
14711453
}

services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,11 @@ public void testStatsRebootPersist() throws Exception {
272272

273273
// graceful shutdown system, which should trigger persist of stats, and
274274
// clear any values in memory.
275+
expectCurrentTime();
276+
expectDefaultSettings();
277+
replay();
275278
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
279+
verifyAndReset();
276280

277281
// talk with zombie service to assert stats have gone; and assert that
278282
// we persisted them to file.
@@ -487,6 +491,7 @@ public void testUidRemovedIsMoved() throws Exception {
487491

488492
// now pretend two UIDs are uninstalled, which should migrate stats to
489493
// special "removed" bucket.
494+
expectCurrentTime();
490495
expectDefaultSettings();
491496
replay();
492497
final Intent intent = new Intent(ACTION_UID_REMOVED);
@@ -758,7 +763,6 @@ private void expectSettings(long persistThreshold, long bucketDuration, long max
758763
expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes();
759764
expect(mSettings.getTagMaxHistory()).andReturn(maxHistory).anyTimes();
760765
expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
761-
expect(mSettings.getForceCompletePoll()).andReturn(false).anyTimes();
762766
}
763767

764768
private void expectCurrentTime() throws Exception {

0 commit comments

Comments
 (0)