Merge "Dynamically enable/disable watch for RAT type changes" am: 26d523e981
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1315574 Change-Id: Id5c4ad325779322bbf4881816235904a6d454583
This commit is contained in:
@@ -87,6 +87,7 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.database.ContentObserver;
|
||||||
import android.net.DataUsageRequest;
|
import android.net.DataUsageRequest;
|
||||||
import android.net.INetworkManagementEventObserver;
|
import android.net.INetworkManagementEventObserver;
|
||||||
import android.net.INetworkStatsService;
|
import android.net.INetworkStatsService;
|
||||||
@@ -103,6 +104,7 @@ import android.net.NetworkStats.NonMonotonicObserver;
|
|||||||
import android.net.NetworkStatsHistory;
|
import android.net.NetworkStatsHistory;
|
||||||
import android.net.NetworkTemplate;
|
import android.net.NetworkTemplate;
|
||||||
import android.net.TrafficStats;
|
import android.net.TrafficStats;
|
||||||
|
import android.net.Uri;
|
||||||
import android.net.netstats.provider.INetworkStatsProvider;
|
import android.net.netstats.provider.INetworkStatsProvider;
|
||||||
import android.net.netstats.provider.INetworkStatsProviderCallback;
|
import android.net.netstats.provider.INetworkStatsProviderCallback;
|
||||||
import android.net.netstats.provider.NetworkStatsProvider;
|
import android.net.netstats.provider.NetworkStatsProvider;
|
||||||
@@ -213,6 +215,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
|
|
||||||
private final boolean mUseBpfTrafficStats;
|
private final boolean mUseBpfTrafficStats;
|
||||||
|
|
||||||
|
private final ContentObserver mContentObserver;
|
||||||
|
private final ContentResolver mContentResolver;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static final String ACTION_NETWORK_STATS_POLL =
|
public static final String ACTION_NETWORK_STATS_POLL =
|
||||||
"com.android.server.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());
|
mHandler = new NetworkStatsHandler(handlerThread.getLooper());
|
||||||
mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext,
|
mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext,
|
||||||
new HandlerExecutor(mHandler), this);
|
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) ->
|
return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) ->
|
||||||
service.handleOnCollapsedRatTypeChanged());
|
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() {
|
private void registerLocalService() {
|
||||||
@@ -530,11 +557,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
|
mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
|
||||||
mSettings.getPollInterval(), pollIntent);
|
mSettings.getPollInterval(), pollIntent);
|
||||||
|
|
||||||
// TODO: listen to settings changed to support dynamically enable/disable.
|
mContentResolver.registerContentObserver(Settings.Global
|
||||||
// watch for networkType changes
|
.getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED),
|
||||||
if (!mSettings.getCombineSubtypeEnabled()) {
|
false /* notifyForDescendants */, mContentObserver);
|
||||||
mNetworkStatsSubscriptionsMonitor.start();
|
|
||||||
}
|
// 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();
|
registerGlobalAlert();
|
||||||
}
|
}
|
||||||
@@ -560,6 +590,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
mNetworkStatsSubscriptionsMonitor.stop();
|
mNetworkStatsSubscriptionsMonitor.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mContentResolver.unregisterContentObserver(mContentObserver);
|
||||||
|
|
||||||
final long currentTime = mClock.millis();
|
final long currentTime = mClock.millis();
|
||||||
|
|
||||||
// persist any pending stats
|
// persist any pending stats
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import static android.net.NetworkStats.TAG_ALL;
|
|||||||
import static android.net.NetworkStats.TAG_NONE;
|
import static android.net.NetworkStats.TAG_NONE;
|
||||||
import static android.net.NetworkStats.UID_ALL;
|
import static android.net.NetworkStats.UID_ALL;
|
||||||
import static android.net.NetworkStatsHistory.FIELD_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.buildTemplateMobileAll;
|
||||||
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
|
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
|
||||||
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
|
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.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -71,6 +73,7 @@ import android.app.AlarmManager;
|
|||||||
import android.app.usage.NetworkStatsManager;
|
import android.app.usage.NetworkStatsManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.database.ContentObserver;
|
||||||
import android.net.DataUsageRequest;
|
import android.net.DataUsageRequest;
|
||||||
import android.net.INetworkManagementEventObserver;
|
import android.net.INetworkManagementEventObserver;
|
||||||
import android.net.INetworkStatsSession;
|
import android.net.INetworkStatsSession;
|
||||||
@@ -94,6 +97,7 @@ import android.os.Message;
|
|||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.SimpleClock;
|
import android.os.SimpleClock;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
@@ -173,6 +177,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
|
|||||||
private NetworkStatsService mService;
|
private NetworkStatsService mService;
|
||||||
private INetworkStatsSession mSession;
|
private INetworkStatsSession mSession;
|
||||||
private INetworkManagementEventObserver mNetworkObserver;
|
private INetworkManagementEventObserver mNetworkObserver;
|
||||||
|
private ContentObserver mContentObserver;
|
||||||
|
private Handler mHandler;
|
||||||
|
|
||||||
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
|
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
|
||||||
@Override
|
@Override
|
||||||
@@ -212,6 +218,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
|
|||||||
mService.systemReady();
|
mService.systemReady();
|
||||||
// Verify that system ready fetches realtime stats
|
// Verify that system ready fetches realtime stats
|
||||||
verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
|
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();
|
mSession = mService.openSession();
|
||||||
assertNotNull("openSession() failed", mSession);
|
assertNotNull("openSession() failed", mSession);
|
||||||
@@ -238,6 +250,14 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
|
|||||||
|
|
||||||
return mNetworkStatsSubscriptionsMonitor;
|
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);
|
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) {
|
private static File getBaseDir(File statsDir) {
|
||||||
File baseDir = new File(statsDir, "netstats");
|
File baseDir = new File(statsDir, "netstats");
|
||||||
baseDir.mkdirs();
|
baseDir.mkdirs();
|
||||||
@@ -1403,6 +1516,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
|
|||||||
|
|
||||||
private void forcePollAndWaitForIdle() {
|
private void forcePollAndWaitForIdle() {
|
||||||
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
|
||||||
|
waitForIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForIdle() {
|
||||||
HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
|
HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user