diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 184f1bfaa0..d70a5e00f7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1380,8 +1380,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } final String action = blocked ? "BLOCKED" : "UNBLOCKED"; + final NetworkRequest satisfiedRequest = nri.getSatisfiedRequest(); + final int requestId = satisfiedRequest != null + ? satisfiedRequest.requestId : nri.mRequests.get(0).requestId; mNetworkInfoBlockingLogs.log(String.format( - "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.getNetId())); + "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId())); } /** @@ -2705,7 +2708,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * Return an array of all current NetworkRequest sorted by request id. */ @VisibleForTesting - protected NetworkRequestInfo[] requestsSortedById() { + NetworkRequestInfo[] requestsSortedById() { NetworkRequestInfo[] requests = new NetworkRequestInfo[0]; requests = mNetworkRequests.values().toArray(requests); // Sort the array based off the NRI containing the min requestId in its requests. @@ -3555,30 +3558,58 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } for (NetworkRequestInfo nri : mNetworkRequests.values()) { - if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) { + if (reason == UnneededFor.LINGER + && !nri.isMultilayerRequest() + && nri.mRequests.get(0).isBackgroundRequest()) { // Background requests don't affect lingering. continue; } - // If this Network is already the highest scoring Network for a request, or if - // there is hope for it to become one if it validated, then it is needed. - if (nri.request.isRequest() && nai.satisfies(nri.request) && - (nai.isSatisfyingRequest(nri.request.requestId) || - // Note that this catches two important cases: - // 1. Unvalidated cellular will not be reaped when unvalidated WiFi - // is currently satisfying the request. This is desirable when - // cellular ends up validating but WiFi does not. - // 2. Unvalidated WiFi will not be reaped when validated cellular - // is currently satisfying the request. This is desirable when - // WiFi ends up validating and out scoring cellular. - nri.mSatisfier.getCurrentScore() - < nai.getCurrentScoreAsValidated())) { + if (isNetworkPotentialSatisfier(nai, nri)) { return false; } } return true; } + private boolean isNetworkPotentialSatisfier( + @NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) { + // listen requests won't keep up a network satisfying it. If this is not a multilayer + // request, we can return immediately. For multilayer requests, we have to check to see if + // any of the multilayer requests may have a potential satisfier. + if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) { + return false; + } + for (final NetworkRequest req : nri.mRequests) { + // As non-multilayer listen requests have already returned, the below would only happen + // for a multilayer request therefore continue to the next request if available. + if (req.isListen()) { + continue; + } + // If this Network is already the highest scoring Network for a request, or if + // there is hope for it to become one if it validated, then it is needed. + if (candidate.satisfies(req)) { + // As soon as a network is found that satisfies a request, return. Specifically for + // multilayer requests, returning as soon as a NetworkAgentInfo satisfies a request + // is important so as to not evaluate lower priority requests further in + // nri.mRequests. + final boolean isNetworkNeeded = candidate.isSatisfyingRequest(req.requestId) + // Note that this catches two important cases: + // 1. Unvalidated cellular will not be reaped when unvalidated WiFi + // is currently satisfying the request. This is desirable when + // cellular ends up validating but WiFi does not. + // 2. Unvalidated WiFi will not be reaped when validated cellular + // is currently satisfying the request. This is desirable when + // WiFi ends up validating and out scoring cellular. + || nri.mSatisfier.getCurrentScore() + < candidate.getCurrentScoreAsValidated(); + return isNetworkNeeded; + } + } + + return false; + } + private NetworkRequestInfo getNriForAppRequest( NetworkRequest request, int callingUid, String requestedOperation) { final NetworkRequestInfo nri = mNetworkRequests.get(request); @@ -5464,6 +5495,10 @@ public class ConnectivityService extends IConnectivityManager.Stub this(r, null); } + boolean isMultilayerRequest() { + return mRequests.size() > 1; + } + private List initializeRequests(NetworkRequest r) { final ArrayList tempRequests = new ArrayList<>(); tempRequests.add(new NetworkRequest(r)); @@ -5505,7 +5540,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public void binderDied() { log("ConnectivityService NetworkRequestInfo binderDied(" + mRequests + ", " + mBinder + ")"); - releaseNetworkRequest(mRequests); + releaseNetworkRequests(mRequests); } @Override @@ -5538,13 +5573,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mAppOpsManager.checkPackage(callerUid, callerPackageName); } - private ArrayList getSignalStrengthThresholds(NetworkAgentInfo nai) { + private ArrayList getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) { final SortedSet thresholds = new TreeSet<>(); synchronized (nai) { - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - if (nri.request.networkCapabilities.hasSignalStrength() && - nai.satisfiesImmutableCapabilitiesOf(nri.request)) { - thresholds.add(nri.request.networkCapabilities.getSignalStrength()); + for (final NetworkRequestInfo nri : mNetworkRequests.values()) { + for (final NetworkRequest req : nri.mRequests) { + if (req.networkCapabilities.hasSignalStrength() + && nai.satisfiesImmutableCapabilitiesOf(req)) { + thresholds.add(req.networkCapabilities.getSignalStrength()); + } } } } @@ -5831,7 +5868,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return mNextNetworkProviderId.getAndIncrement(); } - private void releaseNetworkRequest(List networkRequests) { + private void releaseNetworkRequests(List networkRequests) { for (int i = 0; i < networkRequests.size(); i++) { releaseNetworkRequest(networkRequests.get(i)); } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 21dbbc6fed..a68044a985 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -8109,7 +8109,16 @@ public class ConnectivityServiceTest { @Test public void testDumpDoesNotCrash() { - StringWriter stringWriter = new StringWriter(); + // Filing a couple requests prior to testing the dump. + final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback(); + final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback(); + final NetworkRequest genericRequest = new NetworkRequest.Builder() + .clearCapabilities().build(); + final NetworkRequest wifiRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI).build(); + mCm.registerNetworkCallback(genericRequest, genericNetworkCallback); + mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); + final StringWriter stringWriter = new StringWriter(); mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]); @@ -8131,11 +8140,11 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); mCm.registerNetworkCallback(cellRequest, cellNetworkCallback); - ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById(); + final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById(); assertTrue(nriOutput.length > 1); for (int i = 0; i < nriOutput.length - 1; i++) { - boolean isRequestIdInOrder = + final boolean isRequestIdInOrder = nriOutput[i].mRequests.get(0).requestId < nriOutput[i + 1].mRequests.get(0).requestId; assertTrue(isRequestIdInOrder);