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
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 08390b4..e7301cc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1227,6 +1227,14 @@
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 @@
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 @@
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 @@
}
}
+ // 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 @@
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 @@
final int mUid;
final Messenger messenger;
+ /**
+ * Get the list of UIDs this nri applies to.
+ */
+ @NonNull
+ private Set<UidRange> getUids() {
+ // networkCapabilities.getUids() returns a defensive copy.
+ // multilayer requests will all have the same uids so return the first one.
+ final Set<UidRange> 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 @@
@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 @@
@NonNull
private final ArraySet<NetworkRequestInfo> 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
@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 @@
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 @@
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));