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

@@ -3783,6 +3783,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
@@ -3790,7 +3796,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);
@@ -3807,7 +3818,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));
@@ -7593,7 +7603,9 @@ public class ConnectivityServiceTest {
// Simple connection with initial LP should have updated ifaces.
mCellAgent.connect(false);
waitForIdle();
expectNotifyNetworkStatus(onlyCell(), onlyCell(), MOBILE_IFNAME);
List<Network> 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.
@@ -7902,9 +7914,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);
@@ -7920,10 +7936,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"));
@@ -8038,10 +8057,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);
@@ -8060,7 +8082,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();
@@ -8071,6 +8095,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);
@@ -10388,7 +10413,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));
}
}
@@ -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
public void testStackedLinkProperties() throws Exception {
final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
@@ -10474,11 +10515,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<ReportedInterfaces>.ReadHead readHead =
mDeps.mReportedInterfaceHistory.newReadHead();
assertNotNull(readHead.poll(TIMEOUT_MS, ri -> ri.contentEquals(mServiceContext,
@@ -14993,7 +15031,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);
@@ -15009,8 +15047,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();
@@ -15050,6 +15096,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);
@@ -15058,8 +15109,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),
@@ -17578,6 +17627,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;
@@ -17592,8 +17657,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
@@ -17603,13 +17668,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();
@@ -17622,8 +17687,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