diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 5bab8e358d..b5c9b0a256 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -2653,7 +2653,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final ArrayList result = new ArrayList<>(); for (Network network : getAllNetworks()) { final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - if (nai != null && nai.everConnected()) { + final boolean includeNetwork = (nai != null) && nai.isCreated(); + if (includeNetwork) { // TODO (b/73321673) : NetworkStateSnapshot contains a copy of the // NetworkCapabilities, which may contain UIDs of apps to which the // network applies. Should the UIDs be cleared so as not to leak or @@ -3879,9 +3880,9 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_UNREGISTER_AFTER_REPLACEMENT: { - if (!nai.isCreated()) { - Log.d(TAG, "unregisterAfterReplacement on uncreated " + nai.toShortString() - + ", tearing down instead"); + if (!nai.everConnected()) { + Log.d(TAG, "unregisterAfterReplacement on never-connected " + + nai.toShortString() + ", tearing down instead"); teardownUnneededNetwork(nai); break; } @@ -4466,6 +4467,25 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @VisibleForTesting + protected static boolean shouldCreateNetworksImmediately() { + // Before U, physical networks are only created when the agent advances to CONNECTED. + // In U and above, all networks are immediately created when the agent is registered. + return SdkLevel.isAtLeastU(); + } + + private static boolean shouldCreateNativeNetwork(@NonNull NetworkAgentInfo nai, + @NonNull NetworkInfo.State state) { + if (nai.isCreated()) return false; + if (state == NetworkInfo.State.CONNECTED) return true; + if (state != NetworkInfo.State.CONNECTING) { + // TODO: throw if no WTFs are observed in the field. + Log.wtf(TAG, "Uncreated network in invalid state: " + state); + return false; + } + return nai.isVPN() || shouldCreateNetworksImmediately(); + } + private static boolean shouldDestroyNativeNetwork(@NonNull NetworkAgentInfo nai) { return nai.isCreated() && !nai.isDestroyed(); } @@ -7908,7 +7928,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (isDefaultNetwork(networkAgent)) { handleApplyDefaultProxy(newLp.getHttpProxy()); - } else { + } else if (networkAgent.everConnected()) { updateProxy(newLp, oldLp); } @@ -7942,6 +7962,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent); } + private void applyInitialLinkProperties(@NonNull NetworkAgentInfo nai) { + updateLinkProperties(nai, new LinkProperties(nai.linkProperties), null); + } + /** * @param naData captive portal data from NetworkAgent * @param apiData captive portal data from capport API @@ -9704,21 +9728,32 @@ public class ConnectivityService extends IConnectivityManager.Stub + oldInfo.getState() + " to " + state); } - if (!networkAgent.isCreated() - && (state == NetworkInfo.State.CONNECTED - || (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) { - + if (shouldCreateNativeNetwork(networkAgent, state)) { // A network that has just connected has zero requests and is thus a foreground network. networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); if (!createNativeNetwork(networkAgent)) return; + + networkAgent.setCreated(); + + // If the network is created immediately on register, then apply the LinkProperties now. + // Otherwise, this is done further down when the network goes into connected state. + // Applying the LinkProperties means that the network is ready to carry traffic - + // interfaces and routing rules have been added, DNS servers programmed, etc. + // For VPNs, this must be done before the capabilities are updated, because as soon as + // that happens, UIDs are routed to the network. + if (shouldCreateNetworksImmediately()) { + applyInitialLinkProperties(networkAgent); + } + + // TODO: should this move earlier? It doesn't seem to have anything to do with whether + // a network is created or not. if (networkAgent.propagateUnderlyingCapabilities()) { // Initialize the network's capabilities to their starting values according to the // underlying networks. This ensures that the capabilities are correct before // anything happens to the network. updateCapabilitiesForNetwork(networkAgent); } - networkAgent.setCreated(); networkAgent.onNetworkCreated(); updateAllowedUids(networkAgent, null, networkAgent.networkCapabilities); updateProfileAllowedNetworks(); @@ -9732,8 +9767,19 @@ public class ConnectivityService extends IConnectivityManager.Stub networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities); handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig()); - updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties), - null); + if (!shouldCreateNetworksImmediately()) { + applyInitialLinkProperties(networkAgent); + } else { + // The network was created when the agent registered, and the LinkProperties are + // already up-to-date. However, updateLinkProperties also makes some changes only + // when the network connects. Apply those changes here. On T and below these are + // handled by the applyInitialLinkProperties call just above. + // TODO: stop relying on updateLinkProperties(..., null) to do this. + // If something depends on both LinkProperties and connected state, it should be in + // this method as well. + networkAgent.clatd.update(); + updateProxy(networkAgent.linkProperties, null); + } // If a rate limit has been configured and is applicable to this network (network // provides internet connectivity), apply it. The tc police filter cannot be attached diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 869562b5ec..af8938a1a7 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -29,9 +29,9 @@ import android.net.LinkProperties import android.net.NattKeepalivePacketData import android.net.Network import android.net.NetworkAgent -import android.net.NetworkAgentConfig import android.net.NetworkAgent.INVALID_NETWORK import android.net.NetworkAgent.VALID_NETWORK +import android.net.NetworkAgentConfig import android.net.NetworkCapabilities import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED @@ -46,21 +46,23 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkCapabilities.TRANSPORT_TEST -import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkCapabilities.TRANSPORT_VPN +import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkInfo import android.net.NetworkProvider import android.net.NetworkReleasedException import android.net.NetworkRequest import android.net.NetworkScore -import android.net.RouteInfo import android.net.QosCallback -import android.net.QosCallbackException import android.net.QosCallback.QosCallbackRegistrationException +import android.net.QosCallbackException import android.net.QosSession import android.net.QosSessionAttributes import android.net.QosSocketInfo +import android.net.RouteInfo import android.net.SocketKeepalive +import android.net.TestNetworkInterface +import android.net.TestNetworkManager import android.net.Uri import android.net.VpnManager import android.net.VpnTransportInfo @@ -71,6 +73,7 @@ import android.os.Build import android.os.Handler import android.os.HandlerThread import android.os.Message +import android.os.Process import android.os.SystemClock import android.platform.test.annotations.AppModeFull import android.system.OsConstants.IPPROTO_TCP @@ -89,6 +92,7 @@ import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged import com.android.testutils.RecorderCallback.CallbackEntry.Losing import com.android.testutils.RecorderCallback.CallbackEntry.Lost @@ -178,6 +182,7 @@ class NetworkAgentTest { private val agentsToCleanUp = mutableListOf() private val callbacksToCleanUp = mutableListOf() private var qosTestSocket: Closeable? = null // either Socket or DatagramSocket + private val ifacesToCleanUp = mutableListOf() @Before fun setUp() { @@ -189,6 +194,7 @@ class NetworkAgentTest { fun tearDown() { agentsToCleanUp.forEach { it.unregister() } callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) } + ifacesToCleanUp.forEach { it.fileDescriptor.close() } qosTestSocket?.close() mHandlerThread.quitSafely() mHandlerThread.join() @@ -269,7 +275,7 @@ class NetworkAgentTest { removeCapability(NET_CAPABILITY_INTERNET) addCapability(NET_CAPABILITY_NOT_SUSPENDED) addCapability(NET_CAPABILITY_NOT_ROAMING) - addCapability(NET_CAPABILITY_NOT_VPN) + if (!transports.contains(TRANSPORT_VPN)) addCapability(NET_CAPABILITY_NOT_VPN) if (SdkLevel.isAtLeastS()) { addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) } @@ -304,7 +310,7 @@ class NetworkAgentTest { context: Context = realContext, specifier: String? = UUID.randomUUID().toString(), initialConfig: NetworkAgentConfig? = null, - expectedInitSignalStrengthThresholds: IntArray? = intArrayOf(), + expectedInitSignalStrengthThresholds: IntArray = intArrayOf(), transports: IntArray = intArrayOf() ): Pair { val callback = TestableNetworkCallback() @@ -317,8 +323,7 @@ class NetworkAgentTest { agent.register() agent.markConnected() agent.expectCallback() - agent.expectSignalStrengths(expectedInitSignalStrengthThresholds) - agent.expectValidationBypassedStatus() + agent.expectPostConnectionCallbacks(expectedInitSignalStrengthThresholds) callback.expectAvailableThenValidatedCallbacks(agent.network!!) return agent to callback } @@ -336,6 +341,19 @@ class NetworkAgentTest { mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) } + private fun TestableNetworkAgent.expectPostConnectionCallbacks( + thresholds: IntArray = intArrayOf() + ) { + expectSignalStrengths(thresholds) + expectValidationBypassedStatus() + assertNoCallback() + } + + private fun createTunInterface(): TestNetworkInterface = realContext.getSystemService( + TestNetworkManager::class.java)!!.createTunInterface(emptyList()).also { + ifacesToCleanUp.add(it) + } + fun assertLinkPropertiesEventually( n: Network, description: String, @@ -1291,8 +1309,12 @@ class NetworkAgentTest { requestNetwork(makeTestNetworkRequest(specifier = specifier6), callback) val agent6 = createNetworkAgent(specifier = specifier6) val network6 = agent6.register() - // No callbacks are sent, so check the LinkProperties to see if the network has connected. - assertLinkPropertiesEventuallyNotNull(agent6.network!!) + if (SdkLevel.isAtLeastU()) { + agent6.expectCallback() + } else { + // No callbacks are sent, so check LinkProperties to wait for the network to be created. + assertLinkPropertiesEventuallyNotNull(agent6.network!!) + } // unregisterAfterReplacement tears down the network immediately. // Approximately check that this is the case by picking an unregister timeout that's longer @@ -1301,8 +1323,9 @@ class NetworkAgentTest { val timeoutMs = agent6.DEFAULT_TIMEOUT_MS.toInt() + 1_000 agent6.unregisterAfterReplacement(timeoutMs) agent6.expectCallback() - if (!SdkLevel.isAtLeastT()) { + if (!SdkLevel.isAtLeastT() || SdkLevel.isAtLeastU()) { // Before T, onNetworkDestroyed is called even if the network was never created. + // On U+, the network was created by register(). Destroying it sends onNetworkDestroyed. agent6.expectCallback() } // Poll for LinkProperties becoming null, because when onNetworkUnwanted is called, the @@ -1375,4 +1398,101 @@ class NetworkAgentTest { callback.expect(agent.network!!) callback.eventuallyExpect { it.network == agent.network } } + + fun doTestNativeNetworkCreation(expectCreatedImmediately: Boolean, transports: IntArray) { + val iface = createTunInterface() + val ifName = iface.interfaceName + val nc = makeTestNetworkCapabilities(ifName, transports).also { + if (transports.contains(TRANSPORT_VPN)) { + val sessionId = "NetworkAgentTest-${Process.myPid()}" + it.transportInfo = VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, sessionId, + /*bypassable=*/ false, /*longLivedTcpConnectionsExpensive=*/ false) + it.underlyingNetworks = listOf() + } + } + val lp = LinkProperties().apply { + interfaceName = ifName + addLinkAddress(LinkAddress("2001:db8::1/64")) + addRoute(RouteInfo(IpPrefix("2001:db8::/64"), null /* nextHop */, ifName)) + addRoute(RouteInfo(IpPrefix("::/0"), + InetAddresses.parseNumericAddress("fe80::abcd"), + ifName)) + } + + // File a request containing the agent's specifier to receive callbacks and to ensure that + // the agent is not torn down due to being unneeded. + val request = makeTestNetworkRequest(specifier = ifName) + val requestCallback = TestableNetworkCallback() + requestNetwork(request, requestCallback) + + val listenCallback = TestableNetworkCallback() + registerNetworkCallback(request, listenCallback) + + // Register the NetworkAgent... + val agent = createNetworkAgent(realContext, initialNc = nc, initialLp = lp) + val network = agent.register() + + // ... and then change the NetworkCapabilities and LinkProperties. + nc.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED) + agent.sendNetworkCapabilities(nc) + lp.addLinkAddress(LinkAddress("192.0.2.2/25")) + lp.addRoute(RouteInfo(IpPrefix("192.0.2.0/25"), null /* nextHop */, ifName)) + agent.sendLinkProperties(lp) + + requestCallback.assertNoCallback() + listenCallback.assertNoCallback() + if (!expectCreatedImmediately) { + agent.assertNoCallback() + agent.markConnected() + agent.expectCallback() + } else { + agent.expectCallback() + agent.markConnected() + } + agent.expectPostConnectionCallbacks() + + // onAvailable must be called only when the network connects, and no other callbacks may be + // called before that happens. The callbacks report the state of the network as it was when + // it connected, so they reflect the NC and LP changes made after registration. + requestCallback.expect(network) + listenCallback.expect(network) + + requestCallback.expect(network) { it.caps.hasCapability( + NET_CAPABILITY_TEMPORARILY_NOT_METERED) } + listenCallback.expect(network) { it.caps.hasCapability( + NET_CAPABILITY_TEMPORARILY_NOT_METERED) } + + requestCallback.expect(network) { it.lp.equals(lp) } + listenCallback.expect(network) { it.lp.equals(lp) } + + requestCallback.expect() + listenCallback.expect() + + // Except for network validation, ensure no more callbacks are sent. + requestCallback.expectCaps(network) { + it.hasCapability(NET_CAPABILITY_VALIDATED) + } + listenCallback.expectCaps(network) { + it.hasCapability(NET_CAPABILITY_VALIDATED) + } + unregister(agent) + // Lost implicitly checks that no further callbacks happened after connect. + requestCallback.expect(network) + listenCallback.expect(network) + assertNull(mCM.getLinkProperties(network)) + } + + @Test + fun testNativeNetworkCreation_PhysicalNetwork() { + // On T and below, the native network is only created when the agent connects. + // Starting in U, the native network is created as soon as the agent is registered. + doTestNativeNetworkCreation(expectCreatedImmediately = SdkLevel.isAtLeastU(), + intArrayOf(TRANSPORT_CELLULAR)) + } + + @Test + fun testNativeNetworkCreation_Vpn() { + // VPN networks are always created as soon as the agent is registered. + doTestNativeNetworkCreation(expectCreatedImmediately = true, intArrayOf(TRANSPORT_VPN)) + } } diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index a90aa0d4d3..9d7b21f559 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -3810,6 +3810,12 @@ public class ConnectivityServiceTest { mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, callbacks); + if (mService.shouldCreateNetworksImmediately()) { + assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } else { + assertNull(eventOrder.poll()); + } + // Connect a network, and file a request for it after it has come up, to ensure the nascent // timer is cleared and the test does not have to wait for it. Filing the request after the // network has come up is necessary because ConnectivityService does not appear to clear the @@ -3817,7 +3823,12 @@ public class ConnectivityServiceTest { // connected. // TODO: fix this bug, file the request before connecting, and remove the waitForIdle. mWiFiAgent.connectWithoutInternet(); - waitForIdle(); + if (!mService.shouldCreateNetworksImmediately()) { + assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } else { + waitForIdle(); + assertNull(eventOrder.poll()); + } mCm.requestNetwork(request, callback); callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); @@ -3834,7 +3845,6 @@ public class ConnectivityServiceTest { // Disconnect the network and check that events happened in the right order. mCm.unregisterNetworkCallback(callback); - assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -7620,7 +7630,9 @@ public class ConnectivityServiceTest { // Simple connection with initial LP should have updated ifaces. mCellAgent.connect(false); waitForIdle(); - expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME); + List allNetworks = mService.shouldCreateNetworksImmediately() + ? cellAndWifi() : onlyCell(); + expectNotifyNetworkStatus(allNetworks, onlyCell(), MOBILE_IFNAME); reset(mStatsManager); // Verify change fields other than interfaces does not trigger a notification to NSS. @@ -7929,9 +7941,13 @@ public class ConnectivityServiceTest { setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + final int netId = mCellAgent.getNetwork().netId; waitForIdle(); - verify(mMockDnsResolver, never()).setResolverConfiguration(any()); - verifyNoMoreInteractions(mMockDnsResolver); + if (mService.shouldCreateNetworksImmediately()) { + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } else { + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); + } final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -7947,10 +7963,13 @@ public class ConnectivityServiceTest { mCellAgent.sendLinkProperties(cellLp); mCellAgent.connect(false); waitForIdle(); - - verify(mMockDnsResolver, times(1)).createNetworkCache(eq(mCellAgent.getNetwork().netId)); - // CS tells dnsresolver about the empty DNS config for this network. + if (!mService.shouldCreateNetworksImmediately()) { + // CS tells dnsresolver about the empty DNS config for this network. + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); + + verifyNoMoreInteractions(mMockDnsResolver); reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); @@ -8065,10 +8084,13 @@ public class ConnectivityServiceTest { mCm.requestNetwork(cellRequest, cellNetworkCallback); mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + final int netId = mCellAgent.getNetwork().netId; waitForIdle(); - // CS tells netd about the empty DNS config for this network. - verify(mMockDnsResolver, never()).setResolverConfiguration(any()); - verifyNoMoreInteractions(mMockDnsResolver); + if (mService.shouldCreateNetworksImmediately()) { + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } else { + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); + } final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -8087,7 +8109,9 @@ public class ConnectivityServiceTest { mCellAgent.sendLinkProperties(cellLp); mCellAgent.connect(false); waitForIdle(); - verify(mMockDnsResolver, times(1)).createNetworkCache(eq(mCellAgent.getNetwork().netId)); + if (!mService.shouldCreateNetworksImmediately()) { + verify(mMockDnsResolver, times(1)).createNetworkCache(netId); + } verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( mResolverParamsParcelCaptor.capture()); ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); @@ -8098,6 +8122,7 @@ public class ConnectivityServiceTest { assertEquals(2, resolvrParams.tlsServers.length); assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll( asList("2001:db8::1", "192.0.2.1"))); + verifyNoMoreInteractions(mMockDnsResolver); reset(mMockDnsResolver); cellNetworkCallback.expect(AVAILABLE, mCellAgent); cellNetworkCallback.expect(NETWORK_CAPS_UPDATED, mCellAgent); @@ -10425,7 +10450,8 @@ public class ConnectivityServiceTest { if (inOrder != null) { return inOrder.verify(t); } else { - return verify(t); + // times(1) for consistency with the above. InOrder#verify always implies times(1). + return verify(t, times(1)); } } @@ -10474,6 +10500,21 @@ public class ConnectivityServiceTest { } } + private void expectNativeNetworkCreated(int netId, int permission, String iface, + InOrder inOrder) throws Exception { + verifyWithOrder(inOrder, mMockNetd).networkCreate(nativeNetworkConfigPhysical(netId, + permission)); + verifyWithOrder(inOrder, mMockDnsResolver).createNetworkCache(eq(netId)); + if (iface != null) { + verifyWithOrder(inOrder, mMockNetd).networkAddInterface(netId, iface); + } + } + + private void expectNativeNetworkCreated(int netId, int permission, String iface) + throws Exception { + expectNativeNetworkCreated(netId, permission, iface, null /* inOrder */); + } + @Test public void testStackedLinkProperties() throws Exception { final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24"); @@ -10511,11 +10552,8 @@ public class ConnectivityServiceTest { int cellNetId = mCellAgent.getNetwork().netId; waitForIdle(); - verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId, - INetd.PERMISSION_NONE)); + expectNativeNetworkCreated(cellNetId, INetd.PERMISSION_NONE, MOBILE_IFNAME); assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default); - verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId)); - verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME); final ArrayTrackRecord.ReadHead readHead = mDeps.mReportedInterfaceHistory.newReadHead(); assertNotNull(readHead.poll(TIMEOUT_MS, ri -> ri.contentEquals(mServiceContext, @@ -15062,7 +15100,7 @@ public class ConnectivityServiceTest { UserHandle testHandle, TestNetworkCallback profileDefaultNetworkCallback, TestNetworkCallback disAllowProfileDefaultNetworkCallback) throws Exception { - final InOrder inOrder = inOrder(mMockNetd); + final InOrder inOrder = inOrder(mMockNetd, mMockDnsResolver); mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellAgent.connect(true); @@ -15078,8 +15116,16 @@ public class ConnectivityServiceTest { final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent(profileNetworkPreference.getPreferenceEnterpriseId()); + if (mService.shouldCreateNetworksImmediately()) { + expectNativeNetworkCreated(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM, + null /* iface */, inOrder); + } if (connectWorkProfileAgentAhead) { workAgent.connect(false); + if (!mService.shouldCreateNetworksImmediately()) { + expectNativeNetworkCreated(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM, + null /* iface */, inOrder); + } } final TestOnCompleteListener listener = new TestOnCompleteListener(); @@ -15119,6 +15165,11 @@ public class ConnectivityServiceTest { if (!connectWorkProfileAgentAhead) { workAgent.connect(false); + if (!mService.shouldCreateNetworksImmediately()) { + inOrder.verify(mMockNetd).networkCreate( + nativeNetworkConfigPhysical(workAgent.getNetwork().netId, + INetd.PERMISSION_SYSTEM)); + } } profileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent); @@ -15127,8 +15178,6 @@ public class ConnectivityServiceTest { } mSystemDefaultNetworkCallback.assertNoCallback(); mDefaultNetworkCallback.assertNoCallback(); - inOrder.verify(mMockNetd).networkCreate( - nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM)); inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( workAgent.getNetwork().netId, uidRangeFor(testHandle, profileNetworkPreference), @@ -17647,6 +17696,22 @@ public class ConnectivityServiceTest { verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); } + private void verifyMtuSetOnWifiInterfaceOnlyUpToT(int mtu) throws Exception { + if (!mService.shouldCreateNetworksImmediately()) { + verify(mMockNetd, times(1)).interfaceSetMtu(WIFI_IFNAME, mtu); + } else { + verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); + } + } + + private void verifyMtuSetOnWifiInterfaceOnlyStartingFromU(int mtu) throws Exception { + if (mService.shouldCreateNetworksImmediately()) { + verify(mMockNetd, times(1)).interfaceSetMtu(WIFI_IFNAME, mtu); + } else { + verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); + } + } + @Test public void testSendLinkPropertiesSetInterfaceMtuBeforeConnect() throws Exception { final int mtu = 1281; @@ -17661,8 +17726,8 @@ public class ConnectivityServiceTest { reset(mMockNetd); mWiFiAgent.connect(false /* validated */); - // The MTU is always (re-)applied when the network connects. - verifyMtuSetOnWifiInterface(mtu); + // Before U, the MTU is always (re-)applied when the network connects. + verifyMtuSetOnWifiInterfaceOnlyUpToT(mtu); } @Test @@ -17672,13 +17737,13 @@ public class ConnectivityServiceTest { lp.setInterfaceName(WIFI_IFNAME); lp.setMtu(mtu); - // Registering an agent with an MTU doesn't set the MTU... + // Registering an agent with an MTU only sets the MTU on U+. mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp); waitForIdle(); - verifyMtuNeverSetOnWifiInterface(); + verifyMtuSetOnWifiInterfaceOnlyStartingFromU(mtu); reset(mMockNetd); - // ... but prevents future updates with the same MTU from setting the MTU. + // Future updates with the same MTU don't set the MTU even on T when it's not set initially. mWiFiAgent.sendLinkProperties(lp); waitForIdle(); verifyMtuNeverSetOnWifiInterface(); @@ -17691,8 +17756,8 @@ public class ConnectivityServiceTest { reset(mMockNetd); mWiFiAgent.connect(false /* validated */); - // The MTU is always (re-)applied when the network connects. - verifyMtuSetOnWifiInterface(mtu + 1); + // Before U, the MTU is always (re-)applied when the network connects. + verifyMtuSetOnWifiInterfaceOnlyUpToT(mtu + 1); } @Test