summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Aaron Huang <huangaaron@google.com> 2020-05-20 15:21:28 +0800
committer Chalard Jean <jchalard@google.com> 2020-06-17 17:09:10 +0900
commit3a2e972406d4bd23ccd8ee1007c2be1eaa2e5934 (patch)
treec02c9d288b21ebe7d9d033cc7c1671a69c3d0bb9
parent5218a1f9e5d9285f7a93a6a37f8db93a01eaa2f8 (diff)
Dynamically enable/disable watch for RAT type changes
Add ContentObserver to observe the status of NETSTATS_COMBINE_SUBTYPE_ENABLED to determine that NetworkStatsSubscriptionsMonitor start or stop monitoring data usage per RAT type changes. Bug: 154080515 Test: atest NetworkStatsServiceTest#testDynamicWatchForNetworkRatTypeChanges Change-Id: I272d589633c9186b45753228b05aa0b40b7c7b89
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java42
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java117
2 files changed, 154 insertions, 5 deletions
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ba538e1cd826..6e01592c51a0 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -87,6 +87,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
import android.net.DataUsageRequest;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
@@ -103,6 +104,7 @@ import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.net.Uri;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProvider;
@@ -213,6 +215,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final boolean mUseBpfTrafficStats;
+ private final ContentObserver mContentObserver;
+ private final ContentResolver mContentResolver;
+
@VisibleForTesting
public static final String ACTION_NETWORK_STATS_POLL =
"com.android.server.action.NETWORK_STATS_POLL";
@@ -438,6 +443,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mHandler = new NetworkStatsHandler(handlerThread.getLooper());
mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext,
new HandlerExecutor(mHandler), this);
+ mContentResolver = mContext.getContentResolver();
+ mContentObserver = mDeps.makeContentObserver(mHandler, mSettings,
+ mNetworkStatsSubscriptionsMonitor);
}
/**
@@ -466,6 +474,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) ->
service.handleOnCollapsedRatTypeChanged());
}
+
+ /**
+ * Create a ContentObserver instance which is used to observe settings changes,
+ * and dispatch onChange events on handler thread.
+ */
+ public @NonNull ContentObserver makeContentObserver(@NonNull Handler handler,
+ @NonNull NetworkStatsSettings settings,
+ @NonNull NetworkStatsSubscriptionsMonitor monitor) {
+ return new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange, @NonNull Uri uri) {
+ if (!settings.getCombineSubtypeEnabled()) {
+ monitor.start();
+ } else {
+ monitor.stop();
+ }
+ }
+ };
+ }
}
private void registerLocalService() {
@@ -530,11 +557,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
mSettings.getPollInterval(), pollIntent);
- // TODO: listen to settings changed to support dynamically enable/disable.
- // watch for networkType changes
- if (!mSettings.getCombineSubtypeEnabled()) {
- mNetworkStatsSubscriptionsMonitor.start();
- }
+ mContentResolver.registerContentObserver(Settings.Global
+ .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED),
+ false /* notifyForDescendants */, mContentObserver);
+
+ // Post a runnable on handler thread to call onChange(). It's for getting current value of
+ // NETSTATS_COMBINE_SUBTYPE_ENABLED to decide start or stop monitoring RAT type changes.
+ mHandler.post(() -> mContentObserver.onChange(false, Settings.Global
+ .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED)));
registerGlobalAlert();
}
@@ -560,6 +590,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mNetworkStatsSubscriptionsMonitor.stop();
}
+ mContentResolver.unregisterContentObserver(mContentObserver);
+
final long currentTime = mClock.millis();
// persist any pending stats
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index a1bb0d586916..9c0d33fe5a37 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -41,6 +41,7 @@ import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
+import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
@@ -62,6 +63,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -71,6 +73,7 @@ import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.DataUsageRequest;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsSession;
@@ -94,6 +97,7 @@ import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
import android.os.SimpleClock;
+import android.provider.Settings;
import android.telephony.TelephonyManager;
import androidx.test.InstrumentationRegistry;
@@ -173,6 +177,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
private NetworkStatsService mService;
private INetworkStatsSession mSession;
private INetworkManagementEventObserver mNetworkObserver;
+ private ContentObserver mContentObserver;
+ private Handler mHandler;
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
@Override
@@ -212,6 +218,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
mService.systemReady();
// Verify that system ready fetches realtime stats
verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
+ // Wait for posting onChange() event to handler thread and verify that when system ready,
+ // start monitoring data usage per RAT type because the settings value is mock as false
+ // by default in expectSettings().
+ waitForIdle();
+ verify(mNetworkStatsSubscriptionsMonitor).start();
+ reset(mNetworkStatsSubscriptionsMonitor);
mSession = mService.openSession();
assertNotNull("openSession() failed", mSession);
@@ -238,6 +250,14 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
return mNetworkStatsSubscriptionsMonitor;
}
+
+ @Override
+ public ContentObserver makeContentObserver(Handler handler,
+ NetworkStatsSettings settings, NetworkStatsSubscriptionsMonitor monitor) {
+ mHandler = handler;
+ return mContentObserver = super.makeContentObserver(handler, settings, monitor);
+ }
+
};
}
@@ -1191,6 +1211,99 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
provider.expectOnSetAlert(MB_IN_BYTES);
}
+ private void setCombineSubtypeEnabled(boolean enable) {
+ when(mSettings.getCombineSubtypeEnabled()).thenReturn(enable);
+ mHandler.post(() -> mContentObserver.onChange(false, Settings.Global
+ .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED)));
+ waitForIdle();
+ if (enable) {
+ verify(mNetworkStatsSubscriptionsMonitor).stop();
+ } else {
+ verify(mNetworkStatsSubscriptionsMonitor).start();
+ }
+ }
+
+ @Test
+ public void testDynamicWatchForNetworkRatTypeChanges() throws Exception {
+ // Build 3G template, type unknown template to get stats while network type is unknown
+ // and type all template to get the sum of all network type stats.
+ final NetworkTemplate template3g =
+ buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
+ final NetworkTemplate templateUnknown =
+ buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ final NetworkTemplate templateAll =
+ buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
+ final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+
+ // 3G network comes online.
+ setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new VpnInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 12L, 18L, 14L, 1L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // Since CombineSubtypeEnabled is false by default in unit test, the generated traffic
+ // will be split by RAT type. Verify 3G templates gets stats, while template with unknown
+ // RAT type gets nothing, and template with NETWORK_TYPE_ALL gets all stats.
+ assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+ assertUidTotal(templateUnknown, UID_RED, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(templateAll, UID_RED, 12L, 18L, 14L, 1L, 0);
+
+ // Stop monitoring data usage per RAT type changes NetworkStatsService records data
+ // to {@link TelephonyManager#NETWORK_TYPE_UNKNOWN}.
+ setCombineSubtypeEnabled(true);
+
+ // Call handleOnCollapsedRatTypeChanged manually to simulate the callback fired
+ // when stopping monitor, this is needed by NetworkStatsService to trigger updateIfaces.
+ mService.handleOnCollapsedRatTypeChanged();
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ // Append more traffic on existing snapshot.
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 12L + 4L, 18L + 4L, 14L + 3L, 1L + 1L, 0L))
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
+ 35L, 29L, 7L, 11L, 1L)));
+ forcePollAndWaitForIdle();
+
+ // Verify 3G counters do not increase, while template with unknown RAT type gets new
+ // traffic and template with NETWORK_TYPE_ALL gets all stats.
+ assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+ assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1);
+ assertUidTotal(templateAll, UID_RED, 16L + 35L, 22L + 29L, 17L + 7L, 2L + 11L, 1);
+
+ // Start monitoring data usage per RAT type changes and NetworkStatsService records data
+ // by a granular subtype representative of the actual subtype
+ setCombineSubtypeEnabled(false);
+
+ mService.handleOnCollapsedRatTypeChanged();
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ // Append more traffic on existing snapshot.
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 22L, 26L, 19L, 5L, 0L))
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
+ 35L, 29L, 7L, 11L, 1L)));
+ forcePollAndWaitForIdle();
+
+ // Verify traffic is split by RAT type, no increase on template with unknown RAT type
+ // and template with NETWORK_TYPE_ALL gets all stats.
+ assertUidTotal(template3g, UID_RED, 6L + 12L , 4L + 18L, 2L + 14L, 3L + 1L, 0);
+ assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1);
+ assertUidTotal(templateAll, UID_RED, 22L + 35L, 26L + 29L, 19L + 7L, 5L + 11L, 1);
+ }
+
private static File getBaseDir(File statsDir) {
File baseDir = new File(statsDir, "netstats");
baseDir.mkdirs();
@@ -1403,6 +1516,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
private void forcePollAndWaitForIdle() {
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ waitForIdle();
+ }
+
+ private void waitForIdle() {
HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
}