Immediately create native networks when NetworkAgents register.

Currently, native networks for non-VPN networks are created only
when the NetworkAgent goes into the CONNECTED state. This is not
ideal, because until the network is connected:

- Nothing routes to the network, so no IP packets can be sent on
  it (except via packet sockets).
- Many network configuration changes (e.g., routes and DNS
  servers) fail to apply because the network does not exist yet.
  These cause ENONET errors in the logs.

Fix this starting in U by creating the native network as soon as
the agent registers. This should not impact apps because
NetworkCallbacks are not sent until networks are connected.

Bug: 143158421
Test: new coverage in NetworkAgentTest
Change-Id: I26bfa8630c085422175558645c47a6c64be96ae6
This commit is contained in:
Lorenzo Colitti
2022-07-25 13:20:37 +09:00
parent b95ca556db
commit 4f87aa3f13
3 changed files with 281 additions and 50 deletions

View File

@@ -2597,7 +2597,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final ArrayList<NetworkStateSnapshot> result = new ArrayList<>(); final ArrayList<NetworkStateSnapshot> result = new ArrayList<>();
for (Network network : getAllNetworks()) { for (Network network : getAllNetworks()) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); 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 // TODO (b/73321673) : NetworkStateSnapshot contains a copy of the
// NetworkCapabilities, which may contain UIDs of apps to which the // NetworkCapabilities, which may contain UIDs of apps to which the
// network applies. Should the UIDs be cleared so as not to leak or // network applies. Should the UIDs be cleared so as not to leak or
@@ -3799,9 +3800,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
break; break;
} }
case NetworkAgent.EVENT_UNREGISTER_AFTER_REPLACEMENT: { case NetworkAgent.EVENT_UNREGISTER_AFTER_REPLACEMENT: {
if (!nai.isCreated()) { if (!nai.everConnected()) {
Log.d(TAG, "unregisterAfterReplacement on uncreated " + nai.toShortString() Log.d(TAG, "unregisterAfterReplacement on never-connected "
+ ", tearing down instead"); + nai.toShortString() + ", tearing down instead");
teardownUnneededNetwork(nai); teardownUnneededNetwork(nai);
break; break;
} }
@@ -4386,6 +4387,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) { private static boolean shouldDestroyNativeNetwork(@NonNull NetworkAgentInfo nai) {
return nai.isCreated() && !nai.isDestroyed(); return nai.isCreated() && !nai.isDestroyed();
} }
@@ -7823,7 +7843,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (isDefaultNetwork(networkAgent)) { if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy()); handleApplyDefaultProxy(newLp.getHttpProxy());
} else { } else if (networkAgent.everConnected()) {
updateProxy(newLp, oldLp); updateProxy(newLp, oldLp);
} }
@@ -7857,6 +7877,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent); mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
} }
private void applyInitialLinkProperties(@NonNull NetworkAgentInfo nai) {
updateLinkProperties(nai, new LinkProperties(nai.linkProperties), null);
}
/** /**
* @param naData captive portal data from NetworkAgent * @param naData captive portal data from NetworkAgent
* @param apiData captive portal data from capport API * @param apiData captive portal data from capport API
@@ -9608,21 +9632,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
+ oldInfo.getState() + " to " + state); + oldInfo.getState() + " to " + state);
} }
if (!networkAgent.isCreated() if (shouldCreateNativeNetwork(networkAgent, state)) {
&& (state == NetworkInfo.State.CONNECTED
|| (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) {
// A network that has just connected has zero requests and is thus a foreground network. // A network that has just connected has zero requests and is thus a foreground network.
networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
if (!createNativeNetwork(networkAgent)) return; 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()) { if (networkAgent.propagateUnderlyingCapabilities()) {
// Initialize the network's capabilities to their starting values according to the // Initialize the network's capabilities to their starting values according to the
// underlying networks. This ensures that the capabilities are correct before // underlying networks. This ensures that the capabilities are correct before
// anything happens to the network. // anything happens to the network.
updateCapabilitiesForNetwork(networkAgent); updateCapabilitiesForNetwork(networkAgent);
} }
networkAgent.setCreated();
networkAgent.onNetworkCreated(); networkAgent.onNetworkCreated();
updateAllowedUids(networkAgent, null, networkAgent.networkCapabilities); updateAllowedUids(networkAgent, null, networkAgent.networkCapabilities);
updateProfileAllowedNetworks(); updateProfileAllowedNetworks();
@@ -9636,8 +9671,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities); networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig()); handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties), if (!shouldCreateNetworksImmediately()) {
null); 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 // 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 // provides internet connectivity), apply it. The tc police filter cannot be attached

View File

@@ -29,9 +29,9 @@ import android.net.LinkProperties
import android.net.NattKeepalivePacketData import android.net.NattKeepalivePacketData
import android.net.Network import android.net.Network
import android.net.NetworkAgent import android.net.NetworkAgent
import android.net.NetworkAgentConfig
import android.net.NetworkAgent.INVALID_NETWORK import android.net.NetworkAgent.INVALID_NETWORK
import android.net.NetworkAgent.VALID_NETWORK import android.net.NetworkAgent.VALID_NETWORK
import android.net.NetworkAgentConfig
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED 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.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_TEST import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkCapabilities.TRANSPORT_VPN import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkInfo import android.net.NetworkInfo
import android.net.NetworkProvider import android.net.NetworkProvider
import android.net.NetworkReleasedException import android.net.NetworkReleasedException
import android.net.NetworkRequest import android.net.NetworkRequest
import android.net.NetworkScore import android.net.NetworkScore
import android.net.RouteInfo
import android.net.QosCallback import android.net.QosCallback
import android.net.QosCallbackException
import android.net.QosCallback.QosCallbackRegistrationException import android.net.QosCallback.QosCallbackRegistrationException
import android.net.QosCallbackException
import android.net.QosSession import android.net.QosSession
import android.net.QosSessionAttributes import android.net.QosSessionAttributes
import android.net.QosSocketInfo import android.net.QosSocketInfo
import android.net.RouteInfo
import android.net.SocketKeepalive import android.net.SocketKeepalive
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
import android.net.Uri import android.net.Uri
import android.net.VpnManager import android.net.VpnManager
import android.net.VpnTransportInfo import android.net.VpnTransportInfo
@@ -71,6 +73,7 @@ import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.os.Message import android.os.Message
import android.os.Process
import android.os.SystemClock import android.os.SystemClock
import android.platform.test.annotations.AppModeFull import android.platform.test.annotations.AppModeFull
import android.system.OsConstants.IPPROTO_TCP 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.DevSdkIgnoreRunner
import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.Available
import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus 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.LinkPropertiesChanged
import com.android.testutils.RecorderCallback.CallbackEntry.Losing import com.android.testutils.RecorderCallback.CallbackEntry.Losing
import com.android.testutils.RecorderCallback.CallbackEntry.Lost import com.android.testutils.RecorderCallback.CallbackEntry.Lost
@@ -178,6 +182,7 @@ class NetworkAgentTest {
private val agentsToCleanUp = mutableListOf<NetworkAgent>() private val agentsToCleanUp = mutableListOf<NetworkAgent>()
private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>() private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>()
private var qosTestSocket: Closeable? = null // either Socket or DatagramSocket private var qosTestSocket: Closeable? = null // either Socket or DatagramSocket
private val ifacesToCleanUp = mutableListOf<TestNetworkInterface>()
@Before @Before
fun setUp() { fun setUp() {
@@ -189,6 +194,7 @@ class NetworkAgentTest {
fun tearDown() { fun tearDown() {
agentsToCleanUp.forEach { it.unregister() } agentsToCleanUp.forEach { it.unregister() }
callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) } callbacksToCleanUp.forEach { mCM.unregisterNetworkCallback(it) }
ifacesToCleanUp.forEach { it.fileDescriptor.close() }
qosTestSocket?.close() qosTestSocket?.close()
mHandlerThread.quitSafely() mHandlerThread.quitSafely()
mHandlerThread.join() mHandlerThread.join()
@@ -269,7 +275,7 @@ class NetworkAgentTest {
removeCapability(NET_CAPABILITY_INTERNET) removeCapability(NET_CAPABILITY_INTERNET)
addCapability(NET_CAPABILITY_NOT_SUSPENDED) addCapability(NET_CAPABILITY_NOT_SUSPENDED)
addCapability(NET_CAPABILITY_NOT_ROAMING) addCapability(NET_CAPABILITY_NOT_ROAMING)
addCapability(NET_CAPABILITY_NOT_VPN) if (!transports.contains(TRANSPORT_VPN)) addCapability(NET_CAPABILITY_NOT_VPN)
if (SdkLevel.isAtLeastS()) { if (SdkLevel.isAtLeastS()) {
addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
} }
@@ -304,7 +310,7 @@ class NetworkAgentTest {
context: Context = realContext, context: Context = realContext,
specifier: String? = UUID.randomUUID().toString(), specifier: String? = UUID.randomUUID().toString(),
initialConfig: NetworkAgentConfig? = null, initialConfig: NetworkAgentConfig? = null,
expectedInitSignalStrengthThresholds: IntArray? = intArrayOf(), expectedInitSignalStrengthThresholds: IntArray = intArrayOf(),
transports: IntArray = intArrayOf() transports: IntArray = intArrayOf()
): Pair<TestableNetworkAgent, TestableNetworkCallback> { ): Pair<TestableNetworkAgent, TestableNetworkCallback> {
val callback = TestableNetworkCallback() val callback = TestableNetworkCallback()
@@ -317,8 +323,7 @@ class NetworkAgentTest {
agent.register() agent.register()
agent.markConnected() agent.markConnected()
agent.expectCallback<OnNetworkCreated>() agent.expectCallback<OnNetworkCreated>()
agent.expectSignalStrengths(expectedInitSignalStrengthThresholds) agent.expectPostConnectionCallbacks(expectedInitSignalStrengthThresholds)
agent.expectValidationBypassedStatus()
callback.expectAvailableThenValidatedCallbacks(agent.network!!) callback.expectAvailableThenValidatedCallbacks(agent.network!!)
return agent to callback return agent to callback
} }
@@ -336,6 +341,19 @@ class NetworkAgentTest {
mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) 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( fun assertLinkPropertiesEventually(
n: Network, n: Network,
description: String, description: String,
@@ -1291,8 +1309,12 @@ class NetworkAgentTest {
requestNetwork(makeTestNetworkRequest(specifier = specifier6), callback) requestNetwork(makeTestNetworkRequest(specifier = specifier6), callback)
val agent6 = createNetworkAgent(specifier = specifier6) val agent6 = createNetworkAgent(specifier = specifier6)
val network6 = agent6.register() val network6 = agent6.register()
// No callbacks are sent, so check the LinkProperties to see if the network has connected. if (SdkLevel.isAtLeastU()) {
agent6.expectCallback<OnNetworkCreated>()
} else {
// No callbacks are sent, so check LinkProperties to wait for the network to be created.
assertLinkPropertiesEventuallyNotNull(agent6.network!!) assertLinkPropertiesEventuallyNotNull(agent6.network!!)
}
// unregisterAfterReplacement tears down the network immediately. // unregisterAfterReplacement tears down the network immediately.
// Approximately check that this is the case by picking an unregister timeout that's longer // 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 val timeoutMs = agent6.DEFAULT_TIMEOUT_MS.toInt() + 1_000
agent6.unregisterAfterReplacement(timeoutMs) agent6.unregisterAfterReplacement(timeoutMs)
agent6.expectCallback<OnNetworkUnwanted>() agent6.expectCallback<OnNetworkUnwanted>()
if (!SdkLevel.isAtLeastT()) { if (!SdkLevel.isAtLeastT() || SdkLevel.isAtLeastU()) {
// Before T, onNetworkDestroyed is called even if the network was never created. // 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<OnNetworkDestroyed>() agent6.expectCallback<OnNetworkDestroyed>()
} }
// Poll for LinkProperties becoming null, because when onNetworkUnwanted is called, the // Poll for LinkProperties becoming null, because when onNetworkUnwanted is called, the
@@ -1375,4 +1398,101 @@ class NetworkAgentTest {
callback.expect<Available>(agent.network!!) callback.expect<Available>(agent.network!!)
callback.eventuallyExpect<Lost> { it.network == agent.network } callback.eventuallyExpect<Lost> { 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<OnNetworkCreated>()
} else {
agent.expectCallback<OnNetworkCreated>()
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<Available>(network)
listenCallback.expect<Available>(network)
requestCallback.expect<CapabilitiesChanged>(network) { it.caps.hasCapability(
NET_CAPABILITY_TEMPORARILY_NOT_METERED) }
listenCallback.expect<CapabilitiesChanged>(network) { it.caps.hasCapability(
NET_CAPABILITY_TEMPORARILY_NOT_METERED) }
requestCallback.expect<LinkPropertiesChanged>(network) { it.lp.equals(lp) }
listenCallback.expect<LinkPropertiesChanged>(network) { it.lp.equals(lp) }
requestCallback.expect<BlockedStatus>()
listenCallback.expect<BlockedStatus>()
// 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<Lost>(network)
listenCallback.expect<Lost>(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))
}
} }

View File

@@ -3783,6 +3783,12 @@ public class ConnectivityServiceTest {
mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, callbacks); 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 // 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 // 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 // network has come up is necessary because ConnectivityService does not appear to clear the
@@ -3790,7 +3796,12 @@ public class ConnectivityServiceTest {
// connected. // connected.
// TODO: fix this bug, file the request before connecting, and remove the waitForIdle. // TODO: fix this bug, file the request before connecting, and remove the waitForIdle.
mWiFiAgent.connectWithoutInternet(); mWiFiAgent.connectWithoutInternet();
if (!mService.shouldCreateNetworksImmediately()) {
assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
} else {
waitForIdle(); waitForIdle();
assertNull(eventOrder.poll());
}
mCm.requestNetwork(request, callback); mCm.requestNetwork(request, callback);
callback.expectAvailableCallbacksUnvalidated(mWiFiAgent); callback.expectAvailableCallbacksUnvalidated(mWiFiAgent);
@@ -3807,7 +3818,6 @@ public class ConnectivityServiceTest {
// Disconnect the network and check that events happened in the right order. // Disconnect the network and check that events happened in the right order.
mCm.unregisterNetworkCallback(callback); mCm.unregisterNetworkCallback(callback);
assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
@@ -7593,7 +7603,9 @@ public class ConnectivityServiceTest {
// Simple connection with initial LP should have updated ifaces. // Simple connection with initial LP should have updated ifaces.
mCellAgent.connect(false); mCellAgent.connect(false);
waitForIdle(); waitForIdle();
expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME); List<Network> allNetworks = mService.shouldCreateNetworksImmediately()
? cellAndWifi() : onlyCell();
expectNotifyNetworkStatus(allNetworks, onlyCell(), MOBILE_IFNAME);
reset(mStatsManager); reset(mStatsManager);
// Verify change fields other than interfaces does not trigger a notification to NSS. // Verify change fields other than interfaces does not trigger a notification to NSS.
@@ -7902,9 +7914,13 @@ public class ConnectivityServiceTest {
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
final int netId = mCellAgent.getNetwork().netId;
waitForIdle(); waitForIdle();
if (mService.shouldCreateNetworksImmediately()) {
verify(mMockDnsResolver, times(1)).createNetworkCache(netId);
} else {
verify(mMockDnsResolver, never()).setResolverConfiguration(any()); verify(mMockDnsResolver, never()).setResolverConfiguration(any());
verifyNoMoreInteractions(mMockDnsResolver); }
final LinkProperties cellLp = new LinkProperties(); final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME); cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -7920,10 +7936,13 @@ public class ConnectivityServiceTest {
mCellAgent.sendLinkProperties(cellLp); mCellAgent.sendLinkProperties(cellLp);
mCellAgent.connect(false); mCellAgent.connect(false);
waitForIdle(); waitForIdle();
if (!mService.shouldCreateNetworksImmediately()) {
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(mCellAgent.getNetwork().netId));
// CS tells dnsresolver about the empty DNS config for this network. // CS tells dnsresolver about the empty DNS config for this network.
verify(mMockDnsResolver, times(1)).createNetworkCache(netId);
}
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
verifyNoMoreInteractions(mMockDnsResolver);
reset(mMockDnsResolver); reset(mMockDnsResolver);
cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
@@ -8038,10 +8057,13 @@ public class ConnectivityServiceTest {
mCm.requestNetwork(cellRequest, cellNetworkCallback); mCm.requestNetwork(cellRequest, cellNetworkCallback);
mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
final int netId = mCellAgent.getNetwork().netId;
waitForIdle(); waitForIdle();
// CS tells netd about the empty DNS config for this network. if (mService.shouldCreateNetworksImmediately()) {
verify(mMockDnsResolver, times(1)).createNetworkCache(netId);
} else {
verify(mMockDnsResolver, never()).setResolverConfiguration(any()); verify(mMockDnsResolver, never()).setResolverConfiguration(any());
verifyNoMoreInteractions(mMockDnsResolver); }
final LinkProperties cellLp = new LinkProperties(); final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME); cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -8060,7 +8082,9 @@ public class ConnectivityServiceTest {
mCellAgent.sendLinkProperties(cellLp); mCellAgent.sendLinkProperties(cellLp);
mCellAgent.connect(false); mCellAgent.connect(false);
waitForIdle(); waitForIdle();
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(mCellAgent.getNetwork().netId)); if (!mService.shouldCreateNetworksImmediately()) {
verify(mMockDnsResolver, times(1)).createNetworkCache(netId);
}
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
mResolverParamsParcelCaptor.capture()); mResolverParamsParcelCaptor.capture());
ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
@@ -8071,6 +8095,7 @@ public class ConnectivityServiceTest {
assertEquals(2, resolvrParams.tlsServers.length); assertEquals(2, resolvrParams.tlsServers.length);
assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll( assertTrue(new ArraySet<>(resolvrParams.tlsServers).containsAll(
asList("2001:db8::1", "192.0.2.1"))); asList("2001:db8::1", "192.0.2.1")));
verifyNoMoreInteractions(mMockDnsResolver);
reset(mMockDnsResolver); reset(mMockDnsResolver);
cellNetworkCallback.expect(AVAILABLE, mCellAgent); cellNetworkCallback.expect(AVAILABLE, mCellAgent);
cellNetworkCallback.expect(NETWORK_CAPS_UPDATED, mCellAgent); cellNetworkCallback.expect(NETWORK_CAPS_UPDATED, mCellAgent);
@@ -10388,7 +10413,8 @@ public class ConnectivityServiceTest {
if (inOrder != null) { if (inOrder != null) {
return inOrder.verify(t); return inOrder.verify(t);
} else { } else {
return verify(t); // times(1) for consistency with the above. InOrder#verify always implies times(1).
return verify(t, times(1));
} }
} }
@@ -10437,6 +10463,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 @Test
public void testStackedLinkProperties() throws Exception { public void testStackedLinkProperties() throws Exception {
final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24"); final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
@@ -10474,11 +10515,8 @@ public class ConnectivityServiceTest {
int cellNetId = mCellAgent.getNetwork().netId; int cellNetId = mCellAgent.getNetwork().netId;
waitForIdle(); waitForIdle();
verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId, expectNativeNetworkCreated(cellNetId, INetd.PERMISSION_NONE, MOBILE_IFNAME);
INetd.PERMISSION_NONE));
assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default); assertRoutesAdded(cellNetId, ipv6Subnet, ipv6Default);
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
final ArrayTrackRecord<ReportedInterfaces>.ReadHead readHead = final ArrayTrackRecord<ReportedInterfaces>.ReadHead readHead =
mDeps.mReportedInterfaceHistory.newReadHead(); mDeps.mReportedInterfaceHistory.newReadHead();
assertNotNull(readHead.poll(TIMEOUT_MS, ri -> ri.contentEquals(mServiceContext, assertNotNull(readHead.poll(TIMEOUT_MS, ri -> ri.contentEquals(mServiceContext,
@@ -14993,7 +15031,7 @@ public class ConnectivityServiceTest {
UserHandle testHandle, UserHandle testHandle,
TestNetworkCallback profileDefaultNetworkCallback, TestNetworkCallback profileDefaultNetworkCallback,
TestNetworkCallback disAllowProfileDefaultNetworkCallback) throws Exception { TestNetworkCallback disAllowProfileDefaultNetworkCallback) throws Exception {
final InOrder inOrder = inOrder(mMockNetd); final InOrder inOrder = inOrder(mMockNetd, mMockDnsResolver);
mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellAgent.connect(true); mCellAgent.connect(true);
@@ -15009,8 +15047,16 @@ public class ConnectivityServiceTest {
final TestNetworkAgentWrapper workAgent = final TestNetworkAgentWrapper workAgent =
makeEnterpriseNetworkAgent(profileNetworkPreference.getPreferenceEnterpriseId()); makeEnterpriseNetworkAgent(profileNetworkPreference.getPreferenceEnterpriseId());
if (mService.shouldCreateNetworksImmediately()) {
expectNativeNetworkCreated(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM,
null /* iface */, inOrder);
}
if (connectWorkProfileAgentAhead) { if (connectWorkProfileAgentAhead) {
workAgent.connect(false); workAgent.connect(false);
if (!mService.shouldCreateNetworksImmediately()) {
expectNativeNetworkCreated(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM,
null /* iface */, inOrder);
}
} }
final TestOnCompleteListener listener = new TestOnCompleteListener(); final TestOnCompleteListener listener = new TestOnCompleteListener();
@@ -15050,6 +15096,11 @@ public class ConnectivityServiceTest {
if (!connectWorkProfileAgentAhead) { if (!connectWorkProfileAgentAhead) {
workAgent.connect(false); workAgent.connect(false);
if (!mService.shouldCreateNetworksImmediately()) {
inOrder.verify(mMockNetd).networkCreate(
nativeNetworkConfigPhysical(workAgent.getNetwork().netId,
INetd.PERMISSION_SYSTEM));
}
} }
profileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent); profileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
@@ -15058,8 +15109,6 @@ public class ConnectivityServiceTest {
} }
mSystemDefaultNetworkCallback.assertNoCallback(); mSystemDefaultNetworkCallback.assertNoCallback();
mDefaultNetworkCallback.assertNoCallback(); mDefaultNetworkCallback.assertNoCallback();
inOrder.verify(mMockNetd).networkCreate(
nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig( inOrder.verify(mMockNetd).networkAddUidRangesParcel(new NativeUidRangeConfig(
workAgent.getNetwork().netId, workAgent.getNetwork().netId,
uidRangeFor(testHandle, profileNetworkPreference), uidRangeFor(testHandle, profileNetworkPreference),
@@ -17578,6 +17627,22 @@ public class ConnectivityServiceTest {
verify(mMockNetd, never()).interfaceSetMtu(eq(WIFI_IFNAME), anyInt()); 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 @Test
public void testSendLinkPropertiesSetInterfaceMtuBeforeConnect() throws Exception { public void testSendLinkPropertiesSetInterfaceMtuBeforeConnect() throws Exception {
final int mtu = 1281; final int mtu = 1281;
@@ -17592,8 +17657,8 @@ public class ConnectivityServiceTest {
reset(mMockNetd); reset(mMockNetd);
mWiFiAgent.connect(false /* validated */); mWiFiAgent.connect(false /* validated */);
// The MTU is always (re-)applied when the network connects. // Before U, the MTU is always (re-)applied when the network connects.
verifyMtuSetOnWifiInterface(mtu); verifyMtuSetOnWifiInterfaceOnlyUpToT(mtu);
} }
@Test @Test
@@ -17603,13 +17668,13 @@ public class ConnectivityServiceTest {
lp.setInterfaceName(WIFI_IFNAME); lp.setInterfaceName(WIFI_IFNAME);
lp.setMtu(mtu); 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); mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
waitForIdle(); waitForIdle();
verifyMtuNeverSetOnWifiInterface(); verifyMtuSetOnWifiInterfaceOnlyStartingFromU(mtu);
reset(mMockNetd); 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); mWiFiAgent.sendLinkProperties(lp);
waitForIdle(); waitForIdle();
verifyMtuNeverSetOnWifiInterface(); verifyMtuNeverSetOnWifiInterface();
@@ -17622,8 +17687,8 @@ public class ConnectivityServiceTest {
reset(mMockNetd); reset(mMockNetd);
mWiFiAgent.connect(false /* validated */); mWiFiAgent.connect(false /* validated */);
// The MTU is always (re-)applied when the network connects. // Before U, the MTU is always (re-)applied when the network connects.
verifyMtuSetOnWifiInterface(mtu + 1); verifyMtuSetOnWifiInterfaceOnlyUpToT(mtu + 1);
} }
@Test @Test