From d31bdfaa0c9b38e4210aae849681a1a46f3d677f Mon Sep 17 00:00:00 2001 From: James Mattis Date: Wed, 23 Dec 2020 16:37:26 -0800 Subject: [PATCH] Transmitting multiple default networks to netd Updating ConnectivityService to transmit network information to netd as part of supporting multiple default networks. Bug: 176191930 Bug: 172347841 Test: atest FrameworksNetTests atest NetworkStackTests atest FrameworksNetIntegrationTests atest NetworkStackIntegrationTests atest CtsNetTestCasesLatestSdk Change-Id: I5851a36e3c3ccb45f4cb3ff85e0fc1352f64dc70 --- .../android/server/ConnectivityService.java | 156 ++++++++++++++---- 1 file changed, 126 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 08390b4e52..e7301ccb6f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1227,6 +1227,14 @@ public class ConnectivityService extends IConnectivityManager.Stub mDnsManager = new DnsManager(mContext, mDnsResolver); registerPrivateDnsSettingsCallbacks(); + + mNoServiceNetwork = new NetworkAgentInfo(null, + new Network(NO_SERVICE_NET_ID), + new NetworkInfo(TYPE_NONE, 0, "", ""), + new LinkProperties(), new NetworkCapabilities(), 0, mContext, + null, new NetworkAgentConfig(), this, null, + null, null, 0, INVALID_UID, + mQosCallbackTracker); } private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { @@ -3446,13 +3454,16 @@ public class ConnectivityService extends IConnectivityManager.Stub propagateUnderlyingNetworkCapabilities(nai.network); // Remove all previously satisfied requests. for (int i = 0; i < nai.numNetworkRequests(); i++) { - NetworkRequest request = nai.requestAt(i); + final NetworkRequest request = nai.requestAt(i); final NetworkRequestInfo nri = mNetworkRequests.get(request); final NetworkAgentInfo currentNetwork = nri.getSatisfier(); if (currentNetwork != null && currentNetwork.network.getNetId() == nai.network.getNetId()) { + // uid rules for this network will be removed in destroyNativeNetwork(nai). nri.setSatisfier(null, null); - sendUpdatedScoreToFactories(request, null); + if (request.isRequest()) { + sendUpdatedScoreToFactories(request, null); + } if (mDefaultRequest == nri) { // TODO : make battery stats aware that since 2013 multiple interfaces may be @@ -3709,7 +3720,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (mNetworkRequests.get(nri.mRequests.get(0)) == null) { return; } - if (nri.getSatisfier() != null) { + if (nri.getActiveRequest() != null) { return; } if (VDBG || (DBG && nri.mRequests.get(0).isRequest())) { @@ -4951,6 +4962,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + // TODO This needs to be the default network that applies to the NAI. private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) { final Network defaultNetwork = getNetwork(getDefaultNetwork()); if (underlyingNetworks == null && defaultNetwork != null) { @@ -5521,9 +5533,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mActiveRequest = activeRequest; } - // The network currently satisfying this request, or null if none. Must only be touched - // on the handler thread. This only makes sense for network requests and not for listens, - // as defined by NetworkRequest#isRequest(). For listens, this is always null. + // The network currently satisfying this NRI. Only one request in an NRI can have a + // satisfier. For non-multilayer requests, only REQUEST-type requests can have a satisfier. @Nullable private NetworkAgentInfo mSatisfier; NetworkAgentInfo getSatisfier() { @@ -5546,6 +5557,18 @@ public class ConnectivityService extends IConnectivityManager.Stub final int mUid; final Messenger messenger; + /** + * Get the list of UIDs this nri applies to. + */ + @NonNull + private Set getUids() { + // networkCapabilities.getUids() returns a defensive copy. + // multilayer requests will all have the same uids so return the first one. + final Set uids = null == mRequests.get(0).networkCapabilities.getUids() + ? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids(); + return uids; + } + NetworkRequestInfo(NetworkRequest r, PendingIntent pi) { mRequests = initializeRequests(r); ensureAllNetworkRequestsHaveType(mRequests); @@ -5604,7 +5627,9 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String toString() { - return "uid/pid:" + mUid + "/" + mPid + " " + mRequests + return "uid/pid:" + mUid + "/" + mPid + " active request Id: " + + (mActiveRequest == null ? null : mActiveRequest.requestId) + + " " + mRequests + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent); } } @@ -6064,6 +6089,26 @@ public class ConnectivityService extends IConnectivityManager.Stub @NonNull private final ArraySet mDefaultNetworkRequests = new ArraySet<>(); + private boolean isPerAppDefaultRequest(@NonNull final NetworkRequestInfo nri) { + return (mDefaultNetworkRequests.contains(nri) && mDefaultRequest != nri); + } + + /** + * Determine if an nri is a managed default request that disallows default networking. + * @param nri the request to evaluate + * @return true if device-default networking is disallowed + */ + private boolean isDefaultBlocked(@NonNull final NetworkRequestInfo nri) { + // Check if this nri is a managed default that supports the default network at its + // lowest priority request. + final NetworkRequest defaultNetworkRequest = mDefaultRequest.mRequests.get(0); + final NetworkCapabilities lowestPriorityNetCap = + nri.mRequests.get(nri.mRequests.size() - 1).networkCapabilities; + return isPerAppDefaultRequest(nri) + && !(defaultNetworkRequest.networkCapabilities.equalRequestableCapabilities( + lowestPriorityNetCap)); + } + // Request used to optionally keep mobile data active even when higher // priority networks like Wi-Fi are active. private final NetworkRequest mDefaultMobileDataRequest; @@ -6075,6 +6120,17 @@ public class ConnectivityService extends IConnectivityManager.Stub // Request used to optionally keep vehicle internal network always active private final NetworkRequest mDefaultVehicleRequest; + // TODO replace with INetd.DUMMY_NET_ID when available. + private static final int NO_SERVICE_NET_ID = 51; + // Sentinel NAI used to direct apps with default networks that should have no connectivity to a + // network with no service. This NAI should never be matched against, nor should any public API + // ever return the associated network. For this reason, this NAI is not in the list of available + // NAIs. It is used in computeNetworkReassignment() to be set as the satisfier for non-device + // default requests that don't support using the device default network which will ultimately + // allow ConnectivityService to use this no-service network when calling makeDefaultForApps(). + @VisibleForTesting + final NetworkAgentInfo mNoServiceNetwork; + // TODO: b/178729499 update this in favor of a method taking in a UID. // The NetworkAgentInfo currently satisfying the default request, if any. private NetworkAgentInfo getDefaultNetwork() { @@ -6165,8 +6221,6 @@ public class ConnectivityService extends IConnectivityManager.Stub LinkProperties lp = new LinkProperties(linkProperties); - // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network - // satisfies mDefaultRequest. final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); final NetworkAgentInfo nai = new NetworkAgentInfo(na, new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, @@ -7233,21 +7287,20 @@ public class ConnectivityService extends IConnectivityManager.Stub log("Switching to new default network for: " + nri + " using " + newDefaultNetwork); } - try { - // TODO http://b/176191930 update netd calls in follow-up CL for multinetwork changes. - if (mDefaultRequest != nri) { - return; - } - - if (null != newDefaultNetwork) { - mNetd.networkSetDefault(newDefaultNetwork.network.getNetId()); - } else { - mNetd.networkClearDefault(); - } - } catch (RemoteException | ServiceSpecificException e) { - loge("Exception setting default network :" + e); + // Fix up the NetworkCapabilities of any networks that have this network as underlying. + if (newDefaultNetwork != null) { + propagateUnderlyingNetworkCapabilities(newDefaultNetwork.network); } + // Set an app level managed default and return since further processing only applies to the + // default network. + if (mDefaultRequest != nri) { + makeDefaultForApps(nri, oldDefaultNetwork, newDefaultNetwork); + return; + } + + makeDefaultNetwork(newDefaultNetwork); + if (oldDefaultNetwork != null) { mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork); } @@ -7258,10 +7311,6 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(null != newDefaultNetwork ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null); notifyIfacesChangedForNetworkStats(); - // Fix up the NetworkCapabilities of any networks that have this network as underlying. - if (newDefaultNetwork != null) { - propagateUnderlyingNetworkCapabilities(newDefaultNetwork.network); - } // Log 0 -> X and Y -> X default network transitions, where X is the new default. final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null; @@ -7285,6 +7334,49 @@ public class ConnectivityService extends IConnectivityManager.Stub prevNetwork, prevScore, prevLp, prevNc); } + private void makeDefaultForApps(@NonNull final NetworkRequestInfo nri, + @Nullable final NetworkAgentInfo oldDefaultNetwork, + @Nullable final NetworkAgentInfo newDefaultNetwork) { + try { + if (VDBG) { + log("Setting default network for " + nri + + " using UIDs " + nri.getUids() + + " with old network " + (oldDefaultNetwork != null + ? oldDefaultNetwork.network().getNetId() : "null") + + " and new network " + (newDefaultNetwork != null + ? newDefaultNetwork.network().getNetId() : "null")); + } + if (nri.getUids().isEmpty()) { + throw new IllegalStateException("makeDefaultForApps called without specifying" + + " any applications to set as the default." + nri); + } + if (null != newDefaultNetwork) { + mNetd.networkAddUidRanges( + newDefaultNetwork.network.getNetId(), + toUidRangeStableParcels(nri.getUids())); + } + if (null != oldDefaultNetwork) { + mNetd.networkRemoveUidRanges( + oldDefaultNetwork.network.getNetId(), + toUidRangeStableParcels(nri.getUids())); + } + } catch (RemoteException | ServiceSpecificException e) { + loge("Exception setting OEM network preference default network :" + e); + } + } + + private void makeDefaultNetwork(@Nullable final NetworkAgentInfo newDefaultNetwork) { + try { + if (null != newDefaultNetwork) { + mNetd.networkSetDefault(newDefaultNetwork.network.getNetId()); + } else { + mNetd.networkClearDefault(); + } + } catch (RemoteException | ServiceSpecificException e) { + loge("Exception setting default network :" + e); + } + } + private void processListenRequests(@NonNull final NetworkAgentInfo nai) { // For consistency with previous behaviour, send onLost callbacks before onAvailable. processNewlyLostListenRequests(nai); @@ -7406,9 +7498,9 @@ public class ConnectivityService extends IConnectivityManager.Stub @Nullable final NetworkAgentInfo previousSatisfier, @Nullable final NetworkAgentInfo newSatisfier, final long now) { - if (newSatisfier != null) { + if (null != newSatisfier && mNoServiceNetwork != newSatisfier) { if (VDBG) log("rematch for " + newSatisfier.toShortString()); - if (previousSatisfier != null) { + if (null != previousSatisfier && mNoServiceNetwork != previousSatisfier) { if (VDBG || DDBG) { log(" accepting network in place of " + previousSatisfier.toShortString()); } @@ -7422,7 +7514,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has " + newRequest); } - } else { + } else if (null != previousSatisfier) { if (DBG) { log("Network " + previousSatisfier.toShortString() + " stopped satisfying" + " request " + previousRequest.requestId); @@ -7473,7 +7565,11 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } } - if (bestNetwork != nri.mSatisfier) { + if (null == bestNetwork && isDefaultBlocked(nri)) { + // Remove default networking if disallowed for managed default requests. + bestNetwork = mNoServiceNetwork; + } + if (nri.getSatisfier() != bestNetwork) { // bestNetwork may be null if no network can satisfy this request. changes.addRequestReassignment(new NetworkReassignment.RequestReassignment( nri, nri.mActiveRequest, bestRequest, nri.getSatisfier(), bestNetwork));