diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 986e2acf60..0d289ea3bc 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -70,6 +70,7 @@ import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.PendingIntent; +import android.app.usage.NetworkStatsManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -95,7 +96,6 @@ import android.net.INetworkActivityListener; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.INetworkPolicyListener; -import android.net.INetworkStatsService; import android.net.IOnSetOemNetworkPreferenceListener; import android.net.IQosCallback; import android.net.ISocketKeepaliveCallback; @@ -331,7 +331,7 @@ public class ConnectivityService extends IConnectivityManager.Stub protected IDnsResolver mDnsResolver; @VisibleForTesting protected INetd mNetd; - private INetworkStatsService mStatsService; + private NetworkStatsManager mStatsManager; private NetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; private final NetdCallback mNetdCallback; @@ -1042,15 +1042,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - public ConnectivityService(Context context, INetworkStatsService statsService) { - this(context, statsService, getDnsResolver(context), new IpConnectivityLog(), + public ConnectivityService(Context context) { + this(context, getDnsResolver(context), new IpConnectivityLog(), NetdService.getInstance(), new Dependencies()); } @VisibleForTesting - protected ConnectivityService(Context context, INetworkStatsService statsService, - IDnsResolver dnsresolver, IpConnectivityLog logger, - INetd netd, Dependencies deps) { + protected ConnectivityService(Context context, IDnsResolver dnsresolver, + IpConnectivityLog logger, INetd netd, Dependencies deps) { if (DBG) log("ConnectivityService starting up"); mDeps = Objects.requireNonNull(deps, "missing Dependencies"); @@ -1096,7 +1095,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: Consider making the timer customizable. mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS; - mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService"); + mStatsManager = mContext.getSystemService(NetworkStatsManager.class); mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); mPolicyManagerInternal = Objects.requireNonNull( LocalServices.getService(NetworkPolicyManagerInternal.class), @@ -7913,7 +7912,8 @@ public class ConnectivityService extends IConnectivityManager.Stub * * Must be called on the handler thread. */ - private Network[] getDefaultNetworks() { + @NonNull + private ArrayList getDefaultNetworks() { ensureRunningOnConnectivityServiceThread(); final ArrayList defaultNetworks = new ArrayList<>(); final Set activeNetIds = new ArraySet<>(); @@ -7927,7 +7927,7 @@ public class ConnectivityService extends IConnectivityManager.Stub defaultNetworks.add(nai.network); } } - return defaultNetworks.toArray(new Network[0]); + return defaultNetworks; } /** @@ -7952,8 +7952,8 @@ public class ConnectivityService extends IConnectivityManager.Stub state.legacyNetworkType); snapshots.add(snapshot); } - mStatsService.forceUpdateIfaces(getDefaultNetworks(), snapshots.toArray( - new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos); + mStatsManager.notifyNetworkStatus(getDefaultNetworks(), + snapshots, activeIface, Arrays.asList(underlyingNetworkInfos)); } catch (Exception ignored) { } } diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java index 097441f706..b992208710 100644 --- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java +++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java @@ -20,8 +20,6 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import android.content.Context; -import android.net.INetworkStatsService; -import android.os.ServiceManager; import android.util.Log; /** @@ -37,7 +35,7 @@ public final class ConnectivityServiceInitializer extends SystemService { // Load JNI libraries used by ConnectivityService and its dependencies System.loadLibrary("service-connectivity"); // TODO: Define formal APIs to get the needed services. - mConnectivity = new ConnectivityService(context, getNetworkStatsService()); + mConnectivity = new ConnectivityService(context); } @Override @@ -46,9 +44,4 @@ public final class ConnectivityServiceInitializer extends SystemService { publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); } - - private INetworkStatsService getNetworkStatsService() { - return INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); - } } diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index c10c573aa0..2a2dc5628e 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -16,6 +16,7 @@ package com.android.server.net.integrationtests +import android.app.usage.NetworkStatsManager import android.content.ComponentName import android.content.Context import android.content.Context.BIND_AUTO_CREATE @@ -25,7 +26,6 @@ import android.content.ServiceConnection import android.net.ConnectivityManager import android.net.IDnsResolver import android.net.INetd -import android.net.INetworkStatsService import android.net.LinkProperties import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET @@ -37,7 +37,6 @@ import android.net.Uri import android.net.metrics.IpConnectivityLog import android.os.ConditionVariable import android.os.IBinder -import android.os.INetworkManagementService import android.os.SystemConfigManager import android.os.UserHandle import android.testing.TestableContext @@ -87,9 +86,7 @@ class ConnectivityServiceIntegrationTest { // lateinit used here for mocks as they need to be reinitialized between each test and the test // should crash if they are used before being initialized. @Mock - private lateinit var netManager: INetworkManagementService - @Mock - private lateinit var statsService: INetworkStatsService + private lateinit var statsManager: NetworkStatsManager @Mock private lateinit var log: IpConnectivityLog @Mock @@ -172,12 +169,13 @@ class ConnectivityServiceIntegrationTest { service = TestConnectivityService(makeDependencies()) cm = ConnectivityManager(context, service) context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm) + context.addMockSystemService(Context.NETWORK_STATS_SERVICE, statsManager) service.systemReadyInternal() } private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService( - context, statsService, dnsResolver, log, netd, deps) + context, dnsResolver, log, netd, deps) private fun makeDependencies(): ConnectivityService.Dependencies { val deps = spy(ConnectivityService.Dependencies()) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c7e8282c8e..ea0c144104 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -148,6 +148,7 @@ import android.app.AlarmManager; import android.app.AppOpsManager; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.usage.NetworkStatsManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; @@ -179,7 +180,6 @@ import android.net.INetd; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.INetworkPolicyListener; -import android.net.INetworkStatsService; import android.net.IOnSetOemNetworkPreferenceListener; import android.net.IQosCallback; import android.net.InetAddresses; @@ -202,7 +202,6 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStackClient; -import android.net.NetworkStateSnapshot; import android.net.NetworkTestResultParcelable; import android.net.OemNetworkPreferences; import android.net.ProxyInfo; @@ -421,7 +420,7 @@ public class ConnectivityServiceTest { @Mock DeviceIdleInternal mDeviceIdleInternal; @Mock INetworkManagementService mNetworkManagementService; - @Mock INetworkStatsService mStatsService; + @Mock NetworkStatsManager mStatsManager; @Mock IBatteryStats mBatteryStatsService; @Mock IDnsResolver mMockDnsResolver; @Mock INetd mMockNetd; @@ -537,6 +536,7 @@ public class ConnectivityServiceTest { if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager; if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager; if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager; + if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager; return super.getSystemService(name); } @@ -1469,7 +1469,6 @@ public class ConnectivityServiceTest { mDeps = makeDependencies(); returnRealCallingUid(); mService = new ConnectivityService(mServiceContext, - mStatsService, mMockDnsResolver, mock(IpConnectivityLog.class), mMockNetd, @@ -5483,18 +5482,19 @@ public class ConnectivityServiceTest { assertEquals(expectedSet, actualSet); } - private void expectForceUpdateIfaces(Network[] networks, String defaultIface, + private void expectNetworkStatus(Network[] networks, String defaultIface, Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception { - ArgumentCaptor networksCaptor = ArgumentCaptor.forClass(Network[].class); - ArgumentCaptor vpnInfosCaptor = ArgumentCaptor.forClass( - UnderlyingNetworkInfo[].class); + ArgumentCaptor> networksCaptor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor> vpnInfosCaptor = + ArgumentCaptor.forClass(List.class); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(), - any(NetworkStateSnapshot[].class), eq(defaultIface), vpnInfosCaptor.capture()); + verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(), + any(List.class), eq(defaultIface), vpnInfosCaptor.capture()); - assertSameElementsNoDuplicates(networksCaptor.getValue(), networks); + assertSameElementsNoDuplicates(networksCaptor.getValue().toArray(), networks); - UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue(); + UnderlyingNetworkInfo[] infos = + vpnInfosCaptor.getValue().toArray(new UnderlyingNetworkInfo[0]); if (vpnUid != null) { assertEquals("Should have exactly one VPN:", 1, infos.length); UnderlyingNetworkInfo info = infos[0]; @@ -5508,8 +5508,9 @@ public class ConnectivityServiceTest { } } - private void expectForceUpdateIfaces(Network[] networks, String defaultIface) throws Exception { - expectForceUpdateIfaces(networks, defaultIface, null, null, new String[0]); + private void expectNetworkStatus( + Network[] networks, String defaultIface) throws Exception { + expectNetworkStatus(networks, defaultIface, null, null, new String[0]); } @Test @@ -5529,46 +5530,46 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(false); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME); - reset(mStatsService); + expectNetworkStatus(onlyCell, MOBILE_IFNAME); + reset(mStatsManager); // Default network switch should update ifaces. mWiFiNetworkAgent.connect(false); mWiFiNetworkAgent.sendLinkProperties(wifiLp); waitForIdle(); assertEquals(wifiLp, mService.getActiveLinkProperties()); - expectForceUpdateIfaces(onlyWifi, WIFI_IFNAME); - reset(mStatsService); + expectNetworkStatus(onlyWifi, WIFI_IFNAME); + reset(mStatsManager); // Disconnect should update ifaces. mWiFiNetworkAgent.disconnect(); waitForIdle(); - expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME); - reset(mStatsService); + expectNetworkStatus(onlyCell, MOBILE_IFNAME); + reset(mStatsManager); // Metered change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME); - reset(mStatsService); + expectNetworkStatus(onlyCell, MOBILE_IFNAME); + reset(mStatsManager); mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME); - reset(mStatsService); + expectNetworkStatus(onlyCell, MOBILE_IFNAME); + reset(mStatsManager); // Temp metered change shouldn't update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED); waitForIdle(); - verify(mStatsService, never()).forceUpdateIfaces(eq(onlyCell), any( - NetworkStateSnapshot[].class), eq(MOBILE_IFNAME), eq(new UnderlyingNetworkInfo[0])); - reset(mStatsService); + verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)), + any(List.class), eq(MOBILE_IFNAME), any(List.class)); + reset(mStatsManager); // Roaming change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); waitForIdle(); - expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME); - reset(mStatsService); + expectNetworkStatus(onlyCell, MOBILE_IFNAME); + reset(mStatsManager); // Test VPNs. final LinkProperties lp = new LinkProperties(); @@ -5581,7 +5582,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()}; // A VPN with default (null) underlying networks sets the underlying network's interfaces... - expectForceUpdateIfaces(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + expectNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, new String[]{MOBILE_IFNAME}); // ...and updates them as the default network switches. @@ -5598,9 +5599,9 @@ public class ConnectivityServiceTest { waitForIdle(); assertEquals(wifiLp, mService.getActiveLinkProperties()); - expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, + expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, new String[]{WIFI_IFNAME}); - reset(mStatsService); + reset(mStatsManager); // A VPN that sets its underlying networks passes the underlying interfaces, and influences // the default interface sent to NetworkStatsService by virtue of applying to the system @@ -5610,22 +5611,22 @@ public class ConnectivityServiceTest { // applies to the system server UID should not have any bearing on network stats. mMockVpn.setUnderlyingNetworks(onlyCell); waitForIdle(); - expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, new String[]{MOBILE_IFNAME}); - reset(mStatsService); + reset(mStatsManager); mMockVpn.setUnderlyingNetworks(cellAndWifi); waitForIdle(); - expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, new String[]{MOBILE_IFNAME, WIFI_IFNAME}); - reset(mStatsService); + reset(mStatsManager); // Null underlying networks are ignored. mMockVpn.setUnderlyingNetworks(cellNullAndWifi); waitForIdle(); - expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, new String[]{MOBILE_IFNAME, WIFI_IFNAME}); - reset(mStatsService); + reset(mStatsManager); // If an underlying network disconnects, that interface should no longer be underlying. // This doesn't actually work because disconnectAndDestroyNetwork only notifies @@ -5637,17 +5638,17 @@ public class ConnectivityServiceTest { mCellNetworkAgent.disconnect(); waitForIdle(); assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork())); - expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, + expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME, new String[]{MOBILE_IFNAME, WIFI_IFNAME}); // Confirm that we never tell NetworkStatsService that cell is no longer the underlying // network for the VPN... - verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class), - any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */, - argThat(infos -> infos[0].underlyingIfaces.size() == 1 - && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0)))); - verifyNoMoreInteractions(mStatsService); - reset(mStatsService); + verify(mStatsManager, never()).notifyNetworkStatus(any(List.class), + any(List.class), any() /* anyString() doesn't match null */, + argThat(infos -> infos.get(0).underlyingIfaces.size() == 1 + && WIFI_IFNAME.equals(infos.get(0).underlyingIfaces.get(0)))); + verifyNoMoreInteractions(mStatsManager); + reset(mStatsManager); // ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be // called again, it does. For example, connect Ethernet, but with a low score, such that it @@ -5656,13 +5657,13 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.adjustScore(-40); mEthernetNetworkAgent.connect(false); waitForIdle(); - verify(mStatsService).forceUpdateIfaces(any(Network[].class), - any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */, - argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1 - && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0)))); + verify(mStatsManager).notifyNetworkStatus(any(List.class), + any(List.class), any() /* anyString() doesn't match null */, + argThat(vpnInfos -> vpnInfos.get(0).underlyingIfaces.size() == 1 + && WIFI_IFNAME.equals(vpnInfos.get(0).underlyingIfaces.get(0)))); mEthernetNetworkAgent.disconnect(); waitForIdle(); - reset(mStatsService); + reset(mStatsManager); // When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo // does not return the VPN, so CS does not pass it to NetworkStatsService. This causes @@ -5672,27 +5673,27 @@ public class ConnectivityServiceTest { // Also, for the same reason as above, the active interface passed in is null. mMockVpn.setUnderlyingNetworks(new Network[0]); waitForIdle(); - expectForceUpdateIfaces(wifiAndVpn, null); - reset(mStatsService); + expectNetworkStatus(wifiAndVpn, null); + reset(mStatsManager); // Specifying only a null underlying network is the same as no networks. mMockVpn.setUnderlyingNetworks(onlyNull); waitForIdle(); - expectForceUpdateIfaces(wifiAndVpn, null); - reset(mStatsService); + expectNetworkStatus(wifiAndVpn, null); + reset(mStatsManager); // Specifying networks that are all disconnected is the same as specifying no networks. mMockVpn.setUnderlyingNetworks(onlyCell); waitForIdle(); - expectForceUpdateIfaces(wifiAndVpn, null); - reset(mStatsService); + expectNetworkStatus(wifiAndVpn, null); + reset(mStatsManager); // Passing in null again means follow the default network again. mMockVpn.setUnderlyingNetworks(null); waitForIdle(); - expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, + expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME, new String[]{WIFI_IFNAME}); - reset(mStatsService); + reset(mStatsManager); } @Test