Merge "Sample atomic network stats buckets, full poll."

This commit is contained in:
Jeff Sharkey
2011-09-18 17:03:15 -07:00
committed by Android (Google) Code Review
4 changed files with 84 additions and 107 deletions

View File

@@ -441,10 +441,10 @@ public class NetworkStatsHistory implements Parcelable {
final long curStart = bucketStart[i]; final long curStart = bucketStart[i];
final long curEnd = curStart + bucketDuration; final long curEnd = curStart + bucketDuration;
// bucket is older than record; we're finished // bucket is older than request; we're finished
if (curEnd < start) break; if (curEnd <= start) break;
// bucket is newer than record; keep looking // bucket is newer than request; keep looking
if (curStart > end) continue; if (curStart >= end) continue;
// include full value for active buckets, otherwise only fractional // include full value for active buckets, otherwise only fractional
final boolean activeBucket = curStart < now && curEnd > now; final boolean activeBucket = curStart < now && curEnd > now;
@@ -466,7 +466,6 @@ public class NetworkStatsHistory implements Parcelable {
if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
} }
return entry; return entry;
} }

View File

@@ -4031,8 +4031,6 @@ public final class Settings {
public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history"; public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history";
/** {@hide} */ /** {@hide} */
public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history"; public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history";
/** {@hide} */
public static final String NETSTATS_FORCE_COMPLETE_POLL = "netstats_force_complete_poll";
/** Preferred NTP server. {@hide} */ /** Preferred NTP server. {@hide} */
public static final String NTP_SERVER = "ntp_server"; public static final String NTP_SERVER = "ntp_server";

View File

@@ -36,7 +36,6 @@ import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING; import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
@@ -136,15 +135,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private static final int MSG_PERFORM_POLL = 0x1; private static final int MSG_PERFORM_POLL = 0x1;
/** Flags to control detail level of poll event. */ /** Flags to control detail level of poll event. */
private static final int FLAG_POLL_NETWORK = 0x1;
private static final int FLAG_POLL_UID = 0x2;
private static final int FLAG_POLL_TETHER = 0x3;
private static final int FLAG_PERSIST_NETWORK = 0x10; private static final int FLAG_PERSIST_NETWORK = 0x10;
private static final int FLAG_PERSIST_UID = 0x20; private static final int FLAG_PERSIST_UID = 0x20;
private static final int FLAG_FORCE_PERSIST = 0x100;
private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID | FLAG_POLL_TETHER;
private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
private static final int FLAG_PERSIST_FORCE = 0x100;
private final Context mContext; private final Context mContext;
private final INetworkManagementService mNetworkManager; private final INetworkManagementService mNetworkManager;
@@ -182,7 +176,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public long getUidMaxHistory(); public long getUidMaxHistory();
public long getTagMaxHistory(); public long getTagMaxHistory();
public long getTimeCacheMaxAge(); public long getTimeCacheMaxAge();
public boolean getForceCompletePoll();
} }
private final Object mStatsLock = new Object(); private final Object mStatsLock = new Object();
@@ -529,7 +522,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override @Override
public void forceUpdate() { public void forceUpdate() {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); performPoll(FLAG_PERSIST_ALL);
} }
/** /**
@@ -561,7 +554,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// on background handler thread, and verified CONNECTIVITY_INTERNAL // on background handler thread, and verified CONNECTIVITY_INTERNAL
// permission above. // permission above.
performPoll(FLAG_POLL_TETHER); performPoll(FLAG_PERSIST_NETWORK);
} }
}; };
@@ -570,7 +563,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// on background handler thread, and verified UPDATE_DEVICE_STATS // on background handler thread, and verified UPDATE_DEVICE_STATS
// permission above. // permission above.
performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); performPoll(FLAG_PERSIST_ALL);
// verify that we're watching global alert // verify that we're watching global alert
registerGlobalAlert(); registerGlobalAlert();
@@ -617,7 +610,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
if (LIMIT_GLOBAL_ALERT.equals(limitName)) { if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
// kick off background poll to collect network stats; UID stats // kick off background poll to collect network stats; UID stats
// are handled during normal polling interval. // are handled during normal polling interval.
final int flags = FLAG_POLL_NETWORK | FLAG_PERSIST_NETWORK; final int flags = FLAG_PERSIST_NETWORK;
mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
// re-arm global alert for next update // re-arm global alert for next update
@@ -639,10 +632,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// isn't perfect, since the kernel may already be counting traffic from // isn't perfect, since the kernel may already be counting traffic from
// the updated network. // the updated network.
// poll both network and UID stats, but only persist network stats, // poll, but only persist network stats to keep codepath fast. UID stats
// since this codepath should stay fast. UID stats will be persisted // will be persisted during next alarm poll event.
// during next alarm poll event. performPollLocked(FLAG_PERSIST_NETWORK);
performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_NETWORK);
final NetworkState[] states; final NetworkState[] states;
try { try {
@@ -706,21 +698,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
final long startRealtime = SystemClock.elapsedRealtime(); final long startRealtime = SystemClock.elapsedRealtime();
boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0;
boolean pollUid = (flags & FLAG_POLL_UID) != 0;
boolean pollTether = (flags & FLAG_POLL_TETHER) != 0;
// when complete poll requested, any partial poll enables everything
final boolean forceCompletePoll = mSettings.getForceCompletePoll();
if (forceCompletePoll && (pollNetwork || pollUid || pollTether)) {
pollNetwork = true;
pollUid = true;
pollTether = true;
}
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0; final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
// try refreshing time source when stale // try refreshing time source when stale
if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
@@ -733,41 +713,36 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final long threshold = mSettings.getPersistThreshold(); final long threshold = mSettings.getPersistThreshold();
try { try {
if (pollNetwork) { // record network stats
final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary();
performNetworkPollLocked(networkSnapshot, currentTime); performNetworkPollLocked(networkSnapshot, currentTime);
// persist when enough network data has occurred // persist when enough network data has occurred
final NetworkStats persistNetworkDelta = computeStatsDelta( final NetworkStats persistNetworkDelta = computeStatsDelta(
mLastPersistNetworkSnapshot, networkSnapshot, true); mLastPersistNetworkSnapshot, networkSnapshot, true);
final boolean pastThreshold = persistNetworkDelta.getTotalBytes() > threshold; final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold;
if (forcePersist || (persistNetwork && pastThreshold)) { if (persistForce || (persistNetwork && networkPastThreshold)) {
writeNetworkStatsLocked(); writeNetworkStatsLocked();
mLastPersistNetworkSnapshot = networkSnapshot; mLastPersistNetworkSnapshot = networkSnapshot;
}
} }
if (pollTether) { // record tethering stats; persisted during normal UID cycle below
final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); final String[] ifacePairs = mConnManager.getTetheredIfacePairs();
final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
ifacePairs); ifacePairs);
performTetherPollLocked(tetherSnapshot, currentTime); performTetherPollLocked(tetherSnapshot, currentTime);
// persisted during normal UID cycle below // record uid stats
} final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
performUidPollLocked(uidSnapshot, currentTime);
if (pollUid) { // persist when enough network data has occurred
final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); final NetworkStats persistUidDelta = computeStatsDelta(
performUidPollLocked(uidSnapshot, currentTime); mLastPersistUidSnapshot, uidSnapshot, true);
final boolean uidPastThreshold = persistUidDelta.getTotalBytes() > threshold;
// persist when enough network data has occurred if (persistForce || (persistUid && uidPastThreshold)) {
final NetworkStats persistUidDelta = computeStatsDelta( writeUidStatsLocked();
mLastPersistUidSnapshot, uidSnapshot, true); mLastPersistUidSnapshot = uidSnapshot;
final boolean pastThreshold = persistUidDelta.getTotalBytes() > threshold;
if (forcePersist || (persistUid && pastThreshold)) {
writeUidStatsLocked();
mLastPersistUidSnapshot = uidSnapshot;
}
} }
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
Log.wtf(TAG, "problem reading network stats", e); Log.wtf(TAG, "problem reading network stats", e);
@@ -781,9 +756,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} }
// sample stats after each full poll // sample stats after each full poll
if (pollNetwork && pollUid) { performSample();
performSample();
}
// finally, dispatch updated event to any listeners // finally, dispatch updated event to any listeners
final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
@@ -813,12 +786,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
history.recordData(timeStart, currentTime, entry); history.recordData(timeStart, currentTime, entry);
} }
// trim any history beyond max
final long maxHistory = mSettings.getNetworkMaxHistory();
for (NetworkStatsHistory history : mNetworkStats.values()) {
history.removeBucketsBefore(currentTime - maxHistory);
}
mLastPollNetworkSnapshot = networkSnapshot; mLastPollNetworkSnapshot = networkSnapshot;
if (LOGD && unknownIface.size() > 0) { if (LOGD && unknownIface.size() > 0) {
@@ -862,20 +829,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
history.recordData(timeStart, currentTime, entry); history.recordData(timeStart, currentTime, entry);
} }
// trim any history beyond max
final long maxUidHistory = mSettings.getUidMaxHistory();
final long maxTagHistory = mSettings.getTagMaxHistory();
for (UidStatsKey key : mUidStats.keySet()) {
final NetworkStatsHistory history = mUidStats.get(key);
// detailed tags are trimmed sooner than summary in TAG_NONE
if (key.tag == TAG_NONE) {
history.removeBucketsBefore(currentTime - maxUidHistory);
} else {
history.removeBucketsBefore(currentTime - maxTagHistory);
}
}
mLastPollUidSnapshot = uidSnapshot; mLastPollUidSnapshot = uidSnapshot;
mLastPollOperationsSnapshot = mOperations; mLastPollOperationsSnapshot = mOperations;
mOperations = new NetworkStats(0L, 10); mOperations = new NetworkStats(0L, 10);
@@ -917,9 +870,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* Sample recent statistics summary into {@link EventLog}. * Sample recent statistics summary into {@link EventLog}.
*/ */
private void performSample() { private void performSample() {
// take sample as total over last 4 hours final long largestBucketSize = Math.max(
final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration());
final long start = end - (4 * HOUR_IN_MILLIS);
// take sample as atomic buckets
final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
final long end = now - (now % largestBucketSize) + largestBucketSize;
final long start = end - largestBucketSize;
NetworkTemplate template = null; NetworkTemplate template = null;
NetworkStats.Entry ifaceTotal = null; NetworkStats.Entry ifaceTotal = null;
@@ -929,21 +886,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
EventLogTags.writeNetstatsMobileSample( EventLogTags.writeNetstatsMobileSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets,
ifaceTotal.rxBytes, ifaceTotal.txBytes, ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets,
ifaceTotal.rxPackets, ifaceTotal.txPackets, uidTotal.txBytes, uidTotal.rxPackets);
uidTotal.rxBytes, uidTotal.txBytes,
uidTotal.rxPackets, uidTotal.txPackets);
// collect wifi sample // collect wifi sample
template = buildTemplateWifi(); template = buildTemplateWifi();
ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
EventLogTags.writeNetstatsWifiSample( EventLogTags.writeNetstatsWifiSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets,
ifaceTotal.rxBytes, ifaceTotal.txBytes, ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets,
ifaceTotal.rxPackets, ifaceTotal.txPackets, uidTotal.txBytes, uidTotal.rxPackets);
uidTotal.rxBytes, uidTotal.txBytes,
uidTotal.rxPackets, uidTotal.txPackets);
} }
/** /**
@@ -1143,6 +1096,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// TODO: consider duplicating stats and releasing lock while writing // TODO: consider duplicating stats and releasing lock while writing
// trim any history beyond max
if (mTime.hasCache()) {
final long currentTime = mTime.currentTimeMillis();
final long maxHistory = mSettings.getNetworkMaxHistory();
for (NetworkStatsHistory history : mNetworkStats.values()) {
history.removeBucketsBefore(currentTime - maxHistory);
}
}
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
fos = mNetworkFile.startWrite(); fos = mNetworkFile.startWrite();
@@ -1178,6 +1140,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// TODO: consider duplicating stats and releasing lock while writing // TODO: consider duplicating stats and releasing lock while writing
// trim any history beyond max
if (mTime.hasCache()) {
final long currentTime = mTime.currentTimeMillis();
final long maxUidHistory = mSettings.getUidMaxHistory();
final long maxTagHistory = mSettings.getTagMaxHistory();
for (UidStatsKey key : mUidStats.keySet()) {
final NetworkStatsHistory history = mUidStats.get(key);
// detailed tags are trimmed sooner than summary in TAG_NONE
if (key.tag == TAG_NONE) {
history.removeBucketsBefore(currentTime - maxUidHistory);
} else {
history.removeBucketsBefore(currentTime - maxTagHistory);
}
}
}
// build UidStatsKey lists grouped by ident // build UidStatsKey lists grouped by ident
final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap(); final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
for (UidStatsKey key : mUidStats.keySet()) { for (UidStatsKey key : mUidStats.keySet()) {
@@ -1242,7 +1221,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} }
if (argSet.contains("poll")) { if (argSet.contains("poll")) {
performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_ALL | FLAG_FORCE_PERSIST); performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
pw.println("Forced poll"); pw.println("Forced poll");
return; return;
} }
@@ -1470,8 +1449,5 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public long getTimeCacheMaxAge() { public long getTimeCacheMaxAge() {
return DAY_IN_MILLIS; return DAY_IN_MILLIS;
} }
public boolean getForceCompletePoll() {
return getSecureBoolean(NETSTATS_FORCE_COMPLETE_POLL, false);
}
} }
} }

View File

@@ -272,7 +272,11 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
// graceful shutdown system, which should trigger persist of stats, and // graceful shutdown system, which should trigger persist of stats, and
// clear any values in memory. // clear any values in memory.
expectCurrentTime();
expectDefaultSettings();
replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN)); mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
verifyAndReset();
// talk with zombie service to assert stats have gone; and assert that // talk with zombie service to assert stats have gone; and assert that
// we persisted them to file. // we persisted them to file.
@@ -487,6 +491,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
// now pretend two UIDs are uninstalled, which should migrate stats to // now pretend two UIDs are uninstalled, which should migrate stats to
// special "removed" bucket. // special "removed" bucket.
expectCurrentTime();
expectDefaultSettings(); expectDefaultSettings();
replay(); replay();
final Intent intent = new Intent(ACTION_UID_REMOVED); final Intent intent = new Intent(ACTION_UID_REMOVED);
@@ -758,7 +763,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes(); expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes();
expect(mSettings.getTagMaxHistory()).andReturn(maxHistory).anyTimes(); expect(mSettings.getTagMaxHistory()).andReturn(maxHistory).anyTimes();
expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes(); expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
expect(mSettings.getForceCompletePoll()).andReturn(false).anyTimes();
} }
private void expectCurrentTime() throws Exception { private void expectCurrentTime() throws Exception {