Loading core/java/android/net/NetworkStats.java +16 −0 Original line number Diff line number Diff line Loading @@ -312,6 +312,22 @@ public class NetworkStats implements Parcelable { return result; } /** * Return total bytes represented by this snapshot object, usually used when * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. */ public long getTotalBytes() { long totalBytes = 0; for (int i = 0; i < size; i++) { // skip specific tags, since already counted in TAG_NONE if (tag[i] != TAG_NONE) continue; totalBytes += rxBytes[i]; totalBytes += txBytes[i]; } return totalBytes; } /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over Loading core/tests/coretests/src/android/net/NetworkStatsTest.java +41 −0 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package android.net; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import android.test.suitebuilder.annotation.SmallTest; Loading @@ -27,6 +29,7 @@ import junit.framework.TestCase; public class NetworkStatsTest extends TestCase { private static final String TEST_IFACE = "test0"; private static final String TEST_IFACE2 = "test2"; private static final int TEST_UID = 1001; private static final long TEST_START = 1194220800000L; Loading Loading @@ -135,6 +138,44 @@ public class NetworkStatsTest extends TestCase { assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); } public void testSubtractMissingRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); final NetworkStats after = new NetworkStats(TEST_START, 1) .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); final NetworkStats result = after.subtract(before); // should silently drop omitted rows assertEquals(1, result.size()); assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 1L, 2L, 3L, 4L, 0); assertEquals(4L, result.getTotalBytes()); } public void testTotalBytes() throws Exception { final NetworkStats iface = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); assertEquals(384L, iface.getTotalBytes()); final NetworkStats uidSet = new NetworkStats(TEST_START, 3) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidSet.getTotalBytes()); final NetworkStats uidTag = new NetworkStats(TEST_START, 3) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); assertEquals(64L, uidTag.getTotalBytes()); } private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) { final NetworkStats.Entry entry = stats.getValues(index, null); Loading services/java/com/android/server/NetworkManagementService.java +8 −1 Original line number Diff line number Diff line Loading @@ -69,7 +69,8 @@ import libcore.io.IoUtils; /** * @hide */ class NetworkManagementService extends INetworkManagementService.Stub implements Watchdog.Monitor { public class NetworkManagementService extends INetworkManagementService.Stub implements Watchdog.Monitor { private static final String TAG = "NetworkManagementService"; private static final boolean DBG = false; private static final String NETD_TAG = "NetdConnector"; Loading @@ -87,6 +88,12 @@ class NetworkManagementService extends INetworkManagementService.Stub implements /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */ private final File mStatsXtIface; /** * Name representing {@link #setGlobalAlert(long)} limit when delivered to * {@link INetworkManagementEventObserver#limitReached(String, String)}. */ public static final String LIMIT_GLOBAL_ALERT = "globalAlert"; /** {@link #mStatsXtUid} headers. */ private static final String KEY_IFACE = "iface"; private static final String KEY_UID = "uid_tag_int"; Loading services/java/com/android/server/net/NetworkPolicyManagerService.java +8 −3 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeL import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import android.app.IActivityManager; import android.app.INotificationManager; Loading Loading @@ -454,7 +455,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); synchronized (mRulesLock) { if (mMeteredIfaces.contains(iface)) { if (mMeteredIfaces.contains(iface) && !LIMIT_GLOBAL_ALERT.equals(limitName)) { try { // force stats update to make sure we have numbers that // caused alert to trigger. Loading Loading @@ -763,7 +764,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // disable data connection when over limit and not snoozed final boolean overLimit = policy.limitBytes != LIMIT_DISABLED && totalBytes > policy.limitBytes && policy.lastSnooze < start; setNetworkTemplateEnabled(policy.template, !overLimit); final boolean enabled = !overLimit; if (LOGD) { Slog.d(TAG, "setting template=" + policy.template + " enabled=" + enabled); } setNetworkTemplateEnabled(policy.template, enabled); } } Loading @@ -772,7 +778,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * for the given {@link NetworkTemplate}. */ private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) { if (LOGD) Slog.d(TAG, "setting template=" + template + " enabled=" + enabled); switch (template.getMatchRule()) { case MATCH_MOBILE_3G_LOWER: case MATCH_MOBILE_4G: Loading services/java/com/android/server/net/NetworkStatsService.java +134 −58 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; Loading @@ -56,6 +57,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkInfo; Loading Loading @@ -121,7 +123,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_UID_WITH_TAG = 3; private static final int VERSION_UID_WITH_SET = 4; private static final int MSG_FORCE_UPDATE = 0x1; private static final int MSG_PERFORM_POLL = 0x1; private static final int MSG_PERFORM_POLL_DETAILED = 0x2; private final Context mContext; private final INetworkManagementService mNetworkManager; Loading @@ -141,7 +144,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; // TODO: listen for kernel push events through netd instead of polling // TODO: trim empty history objects entirely private static final long KB_IN_BYTES = 1024; Loading Loading @@ -174,17 +176,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; private NetworkStats mLastNetworkSnapshot; private NetworkStats mLastPersistNetworkSnapshot; private NetworkStats mLastPollNetworkSnapshot; private NetworkStats mLastPollUidSnapshot; private NetworkStats mLastPollOperationsSnapshot; private NetworkStats mLastUidSnapshot; private NetworkStats mLastPersistNetworkSnapshot; private NetworkStats mLastPersistUidSnapshot; /** Current counter sets for each UID. */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); /** Data layer operation counters for splicing into other structures. */ private NetworkStats mOperations = new NetworkStats(0L, 10); private NetworkStats mLastOperationsSnapshot; private final HandlerThread mHandlerThread; private final Handler mHandler; Loading Loading @@ -252,13 +255,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.registerReceiver(mShutdownReceiver, shutdownFilter); try { registerPollAlarmLocked(); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { Slog.w(TAG, "unable to register poll alarm"); // ouch, no push updates means we fall back to // ACTION_NETWORK_STATS_POLL intervals. Slog.e(TAG, "unable to register INetworkManagementEventObserver", e); } // kick off background poll to bootstrap deltas mHandler.obtainMessage(MSG_FORCE_UPDATE).sendToTarget(); registerPollAlarmLocked(); registerGlobalAlert(); // bootstrap initial stats to prevent double-counting later bootstrapStats(); } private void shutdownLocked() { Loading @@ -280,7 +288,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}. */ private void registerPollAlarmLocked() throws RemoteException { private void registerPollAlarmLocked() { try { if (mPollIntent != null) { mAlarmManager.remove(mPollIntent); } Loading @@ -291,6 +300,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentRealtime = SystemClock.elapsedRealtime(); mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), mPollIntent); } catch (RemoteException e) { Slog.w(TAG, "problem registering for poll alarm: " + e); } } /** * Register for a global alert that is delivered through * {@link INetworkManagementEventObserver} once a threshold amount of data * has been transferred. */ private void registerGlobalAlert() { try { final long alertBytes = mSettings.getPersistThreshold(); mNetworkManager.setGlobalAlert(alertBytes); } catch (IllegalStateException e) { Slog.w(TAG, "problem registering for global alert: " + e); } catch (RemoteException e) { Slog.w(TAG, "problem registering for global alert: " + e); } } @Override Loading Loading @@ -475,10 +503,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { performPollLocked(true, false); } performPoll(true, false); } /** Loading Loading @@ -507,14 +532,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. synchronized (mStatsLock) { mWakeLock.acquire(); try { performPollLocked(true, false); } finally { mWakeLock.release(); } } performPoll(true, false); // verify that we're watching global alert registerGlobalAlert(); } }; Loading Loading @@ -546,6 +567,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; /** * Observer that watches for {@link INetworkManagementService} alerts. */ private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats; UID stats // are handled during normal polling interval. mHandler.obtainMessage(MSG_PERFORM_POLL).sendToTarget(); // re-arm global alert for next update registerGlobalAlert(); } } }; /** * Inspect all current {@link NetworkState} to derive mapping from {@code * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} Loading Loading @@ -587,6 +628,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } /** * Bootstrap initial stats snapshot, usually during {@link #systemReady()} * so we have baseline values without double-counting. */ private void bootstrapStats() { try { mLastPollNetworkSnapshot = mNetworkManager.getNetworkStatsSummary(); mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); mLastPollOperationsSnapshot = new NetworkStats(0L, 0); } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats: " + e); } } private void performPoll(boolean detailedPoll, boolean forcePersist) { synchronized (mStatsLock) { mWakeLock.acquire(); try { performPollLocked(detailedPoll, forcePersist); } finally { mWakeLock.release(); } } } /** * Periodic poll operation, reading current statistics and recording into * {@link NetworkStatsHistory}. Loading @@ -596,6 +664,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private void performPollLocked(boolean detailedPoll, boolean forcePersist) { if (LOGV) Slog.v(TAG, "performPollLocked()"); final long startRealtime = SystemClock.elapsedRealtime(); // try refreshing time source when stale if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { Loading @@ -605,6 +674,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider marking "untrusted" times in historical stats final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); final long persistThreshold = mSettings.getPersistThreshold(); final NetworkStats networkSnapshot; final NetworkStats uidSnapshot; Loading @@ -620,30 +690,32 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } performNetworkPollLocked(networkSnapshot, currentTime); if (detailedPoll) { performUidPollLocked(uidSnapshot, currentTime); } // decide if enough has changed to trigger persist final NetworkStats persistDelta = computeStatsDelta( // persist when enough network data has occurred final NetworkStats persistNetworkDelta = computeStatsDelta( mLastPersistNetworkSnapshot, networkSnapshot, true); final long persistThreshold = mSettings.getPersistThreshold(); NetworkStats.Entry entry = null; for (String iface : persistDelta.getUniqueIfaces()) { final int index = persistDelta.findIndex(iface, UID_ALL, SET_DEFAULT, TAG_NONE); entry = persistDelta.getValues(index, entry); if (forcePersist || entry.rxBytes > persistThreshold || entry.txBytes > persistThreshold) { if (forcePersist || persistNetworkDelta.getTotalBytes() > persistThreshold) { writeNetworkStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); mLastPersistNetworkSnapshot = networkSnapshot; } if (detailedPoll) { performUidPollLocked(uidSnapshot, currentTime); // persist when enough network data has occurred final NetworkStats persistUidDelta = computeStatsDelta( mLastPersistUidSnapshot, uidSnapshot, true); if (forcePersist || persistUidDelta.getTotalBytes() > persistThreshold) { writeUidStatsLocked(); mLastPersistNetworkSnapshot = networkSnapshot; break; } } if (LOGV) { final long duration = SystemClock.elapsedRealtime() - startRealtime; Slog.v(TAG, "performPollLocked() took " + duration + "ms"); } // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); Loading @@ -656,7 +728,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) { final HashSet<String> unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot, false); final NetworkStats delta = computeStatsDelta(mLastPollNetworkSnapshot, networkSnapshot, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; Loading @@ -678,7 +750,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.removeBucketsBefore(currentTime - maxHistory); } mLastNetworkSnapshot = networkSnapshot; mLastPollNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); Loading @@ -691,9 +763,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot, false); final NetworkStats delta = computeStatsDelta(mLastPollUidSnapshot, uidSnapshot, false); final NetworkStats operationsDelta = computeStatsDelta( mLastOperationsSnapshot, mOperations, false); mLastPollOperationsSnapshot, mOperations, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; Loading Loading @@ -731,8 +803,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } mLastUidSnapshot = uidSnapshot; mLastOperationsSnapshot = mOperations; mLastPollUidSnapshot = uidSnapshot; mLastPollOperationsSnapshot = mOperations; mOperations = new NetworkStats(0L, 10); } Loading Loading @@ -1162,8 +1234,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** {@inheritDoc} */ public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_FORCE_UPDATE: { forceUpdate(); case MSG_PERFORM_POLL: { performPoll(false, false); return true; } case MSG_PERFORM_POLL_DETAILED: { performPoll(true, false); return true; } default: { Loading Loading @@ -1226,10 +1302,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } public long getPersistThreshold() { return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES); return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 512 * KB_IN_BYTES); } public long getNetworkBucketDuration() { return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS); Loading Loading
core/java/android/net/NetworkStats.java +16 −0 Original line number Diff line number Diff line Loading @@ -312,6 +312,22 @@ public class NetworkStats implements Parcelable { return result; } /** * Return total bytes represented by this snapshot object, usually used when * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. */ public long getTotalBytes() { long totalBytes = 0; for (int i = 0; i < size; i++) { // skip specific tags, since already counted in TAG_NONE if (tag[i] != TAG_NONE) continue; totalBytes += rxBytes[i]; totalBytes += txBytes[i]; } return totalBytes; } /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over Loading
core/tests/coretests/src/android/net/NetworkStatsTest.java +41 −0 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package android.net; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import android.test.suitebuilder.annotation.SmallTest; Loading @@ -27,6 +29,7 @@ import junit.framework.TestCase; public class NetworkStatsTest extends TestCase { private static final String TEST_IFACE = "test0"; private static final String TEST_IFACE2 = "test2"; private static final int TEST_UID = 1001; private static final long TEST_START = 1194220800000L; Loading Loading @@ -135,6 +138,44 @@ public class NetworkStatsTest extends TestCase { assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); } public void testSubtractMissingRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); final NetworkStats after = new NetworkStats(TEST_START, 1) .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); final NetworkStats result = after.subtract(before); // should silently drop omitted rows assertEquals(1, result.size()); assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 1L, 2L, 3L, 4L, 0); assertEquals(4L, result.getTotalBytes()); } public void testTotalBytes() throws Exception { final NetworkStats iface = new NetworkStats(TEST_START, 2) .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); assertEquals(384L, iface.getTotalBytes()); final NetworkStats uidSet = new NetworkStats(TEST_START, 3) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidSet.getTotalBytes()); final NetworkStats uidTag = new NetworkStats(TEST_START, 3) .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); assertEquals(64L, uidTag.getTotalBytes()); } private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) { final NetworkStats.Entry entry = stats.getValues(index, null); Loading
services/java/com/android/server/NetworkManagementService.java +8 −1 Original line number Diff line number Diff line Loading @@ -69,7 +69,8 @@ import libcore.io.IoUtils; /** * @hide */ class NetworkManagementService extends INetworkManagementService.Stub implements Watchdog.Monitor { public class NetworkManagementService extends INetworkManagementService.Stub implements Watchdog.Monitor { private static final String TAG = "NetworkManagementService"; private static final boolean DBG = false; private static final String NETD_TAG = "NetdConnector"; Loading @@ -87,6 +88,12 @@ class NetworkManagementService extends INetworkManagementService.Stub implements /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */ private final File mStatsXtIface; /** * Name representing {@link #setGlobalAlert(long)} limit when delivered to * {@link INetworkManagementEventObserver#limitReached(String, String)}. */ public static final String LIMIT_GLOBAL_ALERT = "globalAlert"; /** {@link #mStatsXtUid} headers. */ private static final String KEY_IFACE = "iface"; private static final String KEY_UID = "uid_tag_int"; Loading
services/java/com/android/server/net/NetworkPolicyManagerService.java +8 −3 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeL import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import android.app.IActivityManager; import android.app.INotificationManager; Loading Loading @@ -454,7 +455,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); synchronized (mRulesLock) { if (mMeteredIfaces.contains(iface)) { if (mMeteredIfaces.contains(iface) && !LIMIT_GLOBAL_ALERT.equals(limitName)) { try { // force stats update to make sure we have numbers that // caused alert to trigger. Loading Loading @@ -763,7 +764,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // disable data connection when over limit and not snoozed final boolean overLimit = policy.limitBytes != LIMIT_DISABLED && totalBytes > policy.limitBytes && policy.lastSnooze < start; setNetworkTemplateEnabled(policy.template, !overLimit); final boolean enabled = !overLimit; if (LOGD) { Slog.d(TAG, "setting template=" + policy.template + " enabled=" + enabled); } setNetworkTemplateEnabled(policy.template, enabled); } } Loading @@ -772,7 +778,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * for the given {@link NetworkTemplate}. */ private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) { if (LOGD) Slog.d(TAG, "setting template=" + template + " enabled=" + enabled); switch (template.getMatchRule()) { case MATCH_MOBILE_3G_LOWER: case MATCH_MOBILE_4G: Loading
services/java/com/android/server/net/NetworkStatsService.java +134 −58 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; Loading @@ -56,6 +57,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkInfo; Loading Loading @@ -121,7 +123,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_UID_WITH_TAG = 3; private static final int VERSION_UID_WITH_SET = 4; private static final int MSG_FORCE_UPDATE = 0x1; private static final int MSG_PERFORM_POLL = 0x1; private static final int MSG_PERFORM_POLL_DETAILED = 0x2; private final Context mContext; private final INetworkManagementService mNetworkManager; Loading @@ -141,7 +144,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; // TODO: listen for kernel push events through netd instead of polling // TODO: trim empty history objects entirely private static final long KB_IN_BYTES = 1024; Loading Loading @@ -174,17 +176,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; private NetworkStats mLastNetworkSnapshot; private NetworkStats mLastPersistNetworkSnapshot; private NetworkStats mLastPollNetworkSnapshot; private NetworkStats mLastPollUidSnapshot; private NetworkStats mLastPollOperationsSnapshot; private NetworkStats mLastUidSnapshot; private NetworkStats mLastPersistNetworkSnapshot; private NetworkStats mLastPersistUidSnapshot; /** Current counter sets for each UID. */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); /** Data layer operation counters for splicing into other structures. */ private NetworkStats mOperations = new NetworkStats(0L, 10); private NetworkStats mLastOperationsSnapshot; private final HandlerThread mHandlerThread; private final Handler mHandler; Loading Loading @@ -252,13 +255,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.registerReceiver(mShutdownReceiver, shutdownFilter); try { registerPollAlarmLocked(); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { Slog.w(TAG, "unable to register poll alarm"); // ouch, no push updates means we fall back to // ACTION_NETWORK_STATS_POLL intervals. Slog.e(TAG, "unable to register INetworkManagementEventObserver", e); } // kick off background poll to bootstrap deltas mHandler.obtainMessage(MSG_FORCE_UPDATE).sendToTarget(); registerPollAlarmLocked(); registerGlobalAlert(); // bootstrap initial stats to prevent double-counting later bootstrapStats(); } private void shutdownLocked() { Loading @@ -280,7 +288,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}. */ private void registerPollAlarmLocked() throws RemoteException { private void registerPollAlarmLocked() { try { if (mPollIntent != null) { mAlarmManager.remove(mPollIntent); } Loading @@ -291,6 +300,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentRealtime = SystemClock.elapsedRealtime(); mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), mPollIntent); } catch (RemoteException e) { Slog.w(TAG, "problem registering for poll alarm: " + e); } } /** * Register for a global alert that is delivered through * {@link INetworkManagementEventObserver} once a threshold amount of data * has been transferred. */ private void registerGlobalAlert() { try { final long alertBytes = mSettings.getPersistThreshold(); mNetworkManager.setGlobalAlert(alertBytes); } catch (IllegalStateException e) { Slog.w(TAG, "problem registering for global alert: " + e); } catch (RemoteException e) { Slog.w(TAG, "problem registering for global alert: " + e); } } @Override Loading Loading @@ -475,10 +503,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { performPollLocked(true, false); } performPoll(true, false); } /** Loading Loading @@ -507,14 +532,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. synchronized (mStatsLock) { mWakeLock.acquire(); try { performPollLocked(true, false); } finally { mWakeLock.release(); } } performPoll(true, false); // verify that we're watching global alert registerGlobalAlert(); } }; Loading Loading @@ -546,6 +567,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; /** * Observer that watches for {@link INetworkManagementService} alerts. */ private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats; UID stats // are handled during normal polling interval. mHandler.obtainMessage(MSG_PERFORM_POLL).sendToTarget(); // re-arm global alert for next update registerGlobalAlert(); } } }; /** * Inspect all current {@link NetworkState} to derive mapping from {@code * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} Loading Loading @@ -587,6 +628,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } /** * Bootstrap initial stats snapshot, usually during {@link #systemReady()} * so we have baseline values without double-counting. */ private void bootstrapStats() { try { mLastPollNetworkSnapshot = mNetworkManager.getNetworkStatsSummary(); mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); mLastPollOperationsSnapshot = new NetworkStats(0L, 0); } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats: " + e); } } private void performPoll(boolean detailedPoll, boolean forcePersist) { synchronized (mStatsLock) { mWakeLock.acquire(); try { performPollLocked(detailedPoll, forcePersist); } finally { mWakeLock.release(); } } } /** * Periodic poll operation, reading current statistics and recording into * {@link NetworkStatsHistory}. Loading @@ -596,6 +664,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private void performPollLocked(boolean detailedPoll, boolean forcePersist) { if (LOGV) Slog.v(TAG, "performPollLocked()"); final long startRealtime = SystemClock.elapsedRealtime(); // try refreshing time source when stale if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { Loading @@ -605,6 +674,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider marking "untrusted" times in historical stats final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); final long persistThreshold = mSettings.getPersistThreshold(); final NetworkStats networkSnapshot; final NetworkStats uidSnapshot; Loading @@ -620,30 +690,32 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } performNetworkPollLocked(networkSnapshot, currentTime); if (detailedPoll) { performUidPollLocked(uidSnapshot, currentTime); } // decide if enough has changed to trigger persist final NetworkStats persistDelta = computeStatsDelta( // persist when enough network data has occurred final NetworkStats persistNetworkDelta = computeStatsDelta( mLastPersistNetworkSnapshot, networkSnapshot, true); final long persistThreshold = mSettings.getPersistThreshold(); NetworkStats.Entry entry = null; for (String iface : persistDelta.getUniqueIfaces()) { final int index = persistDelta.findIndex(iface, UID_ALL, SET_DEFAULT, TAG_NONE); entry = persistDelta.getValues(index, entry); if (forcePersist || entry.rxBytes > persistThreshold || entry.txBytes > persistThreshold) { if (forcePersist || persistNetworkDelta.getTotalBytes() > persistThreshold) { writeNetworkStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); mLastPersistNetworkSnapshot = networkSnapshot; } if (detailedPoll) { performUidPollLocked(uidSnapshot, currentTime); // persist when enough network data has occurred final NetworkStats persistUidDelta = computeStatsDelta( mLastPersistUidSnapshot, uidSnapshot, true); if (forcePersist || persistUidDelta.getTotalBytes() > persistThreshold) { writeUidStatsLocked(); mLastPersistNetworkSnapshot = networkSnapshot; break; } } if (LOGV) { final long duration = SystemClock.elapsedRealtime() - startRealtime; Slog.v(TAG, "performPollLocked() took " + duration + "ms"); } // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); Loading @@ -656,7 +728,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) { final HashSet<String> unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot, false); final NetworkStats delta = computeStatsDelta(mLastPollNetworkSnapshot, networkSnapshot, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; Loading @@ -678,7 +750,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.removeBucketsBefore(currentTime - maxHistory); } mLastNetworkSnapshot = networkSnapshot; mLastPollNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); Loading @@ -691,9 +763,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot, false); final NetworkStats delta = computeStatsDelta(mLastPollUidSnapshot, uidSnapshot, false); final NetworkStats operationsDelta = computeStatsDelta( mLastOperationsSnapshot, mOperations, false); mLastPollOperationsSnapshot, mOperations, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; Loading Loading @@ -731,8 +803,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } mLastUidSnapshot = uidSnapshot; mLastOperationsSnapshot = mOperations; mLastPollUidSnapshot = uidSnapshot; mLastPollOperationsSnapshot = mOperations; mOperations = new NetworkStats(0L, 10); } Loading Loading @@ -1162,8 +1234,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** {@inheritDoc} */ public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_FORCE_UPDATE: { forceUpdate(); case MSG_PERFORM_POLL: { performPoll(false, false); return true; } case MSG_PERFORM_POLL_DETAILED: { performPoll(true, false); return true; } default: { Loading Loading @@ -1226,10 +1302,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } public long getPersistThreshold() { return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES); return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 512 * KB_IN_BYTES); } public long getNetworkBucketDuration() { return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS); Loading