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<>();
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
@@ -3799,9 +3800,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;
}
@@ -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) {
return nai.isCreated() && !nai.isDestroyed();
}
@@ -7823,7 +7843,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
} else if (networkAgent.everConnected()) {
updateProxy(newLp, oldLp);
}
@@ -7857,6 +7877,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
@@ -9608,21 +9632,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();
@@ -9636,8 +9671,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