Loading packages/Connectivity/framework/src/android/net/ConnectivityManager.java +2 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,8 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; import static android.net.NetworkRequest.Type.LISTEN; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; import static android.net.NetworkRequest.Type.REQUEST; import static android.net.NetworkRequest.Type.TRACK_BEST; import static android.net.NetworkRequest.Type.TRACK_DEFAULT; import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT; import static android.net.QosCallback.QosCallbackRegistrationException; Loading Loading @@ -4249,7 +4249,7 @@ public class ConnectivityManager { @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { final NetworkCapabilities nc = request.networkCapabilities; final CallbackHandler cbHandler = new CallbackHandler(handler); sendRequestForNetwork(nc, networkCallback, 0, TRACK_BEST, TYPE_NONE, cbHandler); sendRequestForNetwork(nc, networkCallback, 0, LISTEN_FOR_BEST, TYPE_NONE, cbHandler); } /** Loading packages/Connectivity/framework/src/android/net/NetworkRequest.java +10 −1 Original line number Diff line number Diff line Loading @@ -140,7 +140,7 @@ public class NetworkRequest implements Parcelable { REQUEST, BACKGROUND_REQUEST, TRACK_SYSTEM_DEFAULT, TRACK_BEST, LISTEN_FOR_BEST, }; /** Loading Loading @@ -513,6 +513,15 @@ public class NetworkRequest implements Parcelable { return type == Type.LISTEN; } /** * Returns true iff. this NetworkRequest is of type LISTEN_FOR_BEST. * * @hide */ public boolean isListenForBest() { return type == Type.LISTEN_FOR_BEST; } /** * Returns true iff. the contained NetworkRequest is one that: * Loading services/core/java/com/android/server/ConnectivityService.java +18 −7 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.uidRulesToString; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired; import static android.os.Process.INVALID_UID; import static android.os.Process.VPN_UID; Loading Loading @@ -3663,6 +3664,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkRequestInfoLogs.log("REGISTER " + nri); for (final NetworkRequest req : nri.mRequests) { mNetworkRequests.put(req, nri); // TODO: Consider update signal strength for other types. if (req.isListen()) { for (final NetworkAgentInfo network : mNetworkAgentInfos) { if (req.networkCapabilities.hasSignalStrength() Loading Loading @@ -3755,18 +3757,19 @@ public class ConnectivityService extends IConnectivityManager.Stub // listen requests won't keep up a network satisfying it. If this is not a multilayer // request, return immediately. For multilayer requests, check to see if any of the // multilayer requests may have a potential satisfier. if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) { if (!nri.isMultilayerRequest() && (nri.mRequests.get(0).isListen() || nri.mRequests.get(0).isListenForBest())) { return false; } for (final NetworkRequest req : nri.mRequests) { // This multilayer listen request is satisfied therefore no further requests need to be // evaluated deeming this network not a potential satisfier. if (req.isListen() && nri.getActiveRequest() == req) { if ((req.isListen() || req.isListenForBest()) && nri.getActiveRequest() == req) { return false; } // 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()) { if (req.isListen() || req.isListenForBest()) { continue; } // If this Network is already the highest scoring Network for a request, or if Loading Loading @@ -5549,8 +5552,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // request if the app changes network state. http://b/29964605 enforceMeteredApnPolicy(networkCapabilities); break; case TRACK_BEST: throw new UnsupportedOperationException("Not implemented yet"); case LISTEN_FOR_BEST: enforceAccessPermission(); networkCapabilities = new NetworkCapabilities(networkCapabilities); break; default: throw new IllegalArgumentException("Unsupported request type " + reqType); } Loading @@ -5558,11 +5563,17 @@ public class ConnectivityService extends IConnectivityManager.Stub ensureSufficientPermissionsForRequest(networkCapabilities, Binder.getCallingPid(), callingUid, callingPackageName); // Set the UID range for this request to the single UID of the requester, or to an empty // set of UIDs if the caller has the appropriate permission and UIDs have not been set. // Enforce FOREGROUND if the caller does not have permission to use background network. if (reqType == LISTEN_FOR_BEST) { restrictBackgroundRequestForCaller(networkCapabilities); } // Set the UID range for this request to the single UID of the requester, unless the // requester has the permission to specify other UIDs. // This will overwrite any allowed UIDs in the requested capabilities. Though there // are no visible methods to set the UIDs, an app could use reflection to try and get // networks for other apps so it's essential that the UIDs are overwritten. // Also set the requester UID and package name in the request. restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities, callingUid, callingPackageName); Loading services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +1 −0 Original line number Diff line number Diff line Loading @@ -719,6 +719,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { break; case LISTEN: case LISTEN_FOR_BEST: case TRACK_DEFAULT: case TRACK_SYSTEM_DEFAULT: break; Loading tests/net/java/com/android/server/ConnectivityServiceTest.java +97 −5 Original line number Diff line number Diff line Loading @@ -1079,6 +1079,10 @@ public class ConnectivityServiceTest { public void triggerUnfulfillable(NetworkRequest r) { super.releaseRequestAsUnfulfillableByAnyFactory(r); } public void assertNoRequestChanged() { assertNull(mRequestHistory.poll(0, r -> true)); } } private Set<UidRange> uidRangesForUids(int... uids) { Loading Loading @@ -11121,11 +11125,99 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(cellCb); } // Cannot be part of MockNetworkFactory since it requires method of the test. private void expectNoRequestChanged(@NonNull MockNetworkFactory factory) { waitForIdle(); factory.assertNoRequestChanged(); } @Test public void testRegisterBestMatchingNetworkCallback() throws Exception { final NetworkRequest request = new NetworkRequest.Builder().build(); assertThrows(UnsupportedOperationException.class, () -> mCm.registerBestMatchingNetworkCallback(request, new NetworkCallback(), mCsHandlerThread.getThreadHandler())); public void testRegisterBestMatchingNetworkCallback_noIssueToFactory() throws Exception { // Prepare mock mms factory. final HandlerThread handlerThread = new HandlerThread("MockCellularFactory"); handlerThread.start(); NetworkCapabilities filter = new NetworkCapabilities() .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_MMS); final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), mServiceContext, "testFactory", filter, mCsHandlerThread); testFactory.setScoreFilter(40); try { // Register the factory and expect it will see default request, because all requests // are sent to all factories. testFactory.register(); testFactory.expectRequestAdd(); testFactory.assertRequestCountEquals(1); // The factory won't try to start the network since the default request doesn't // match the filter (no INTERNET capability). assertFalse(testFactory.getMyStartRequested()); // Register callback for listening best matching network. Verify that the request won't // be sent to factory. final TestNetworkCallback bestMatchingCb = new TestNetworkCallback(); mCm.registerBestMatchingNetworkCallback( new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(), bestMatchingCb, mCsHandlerThread.getThreadHandler()); bestMatchingCb.assertNoCallback(); expectNoRequestChanged(testFactory); testFactory.assertRequestCountEquals(1); assertFalse(testFactory.getMyStartRequested()); // Fire a normal mms request, verify the factory will only see the request. final TestNetworkCallback mmsNetworkCallback = new TestNetworkCallback(); final NetworkRequest mmsRequest = new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_MMS).build(); mCm.requestNetwork(mmsRequest, mmsNetworkCallback); testFactory.expectRequestAdd(); testFactory.assertRequestCountEquals(2); assertTrue(testFactory.getMyStartRequested()); // Unregister best matching callback, verify factory see no change. mCm.unregisterNetworkCallback(bestMatchingCb); expectNoRequestChanged(testFactory); testFactory.assertRequestCountEquals(2); assertTrue(testFactory.getMyStartRequested()); } finally { testFactory.terminate(); } } @Test public void testRegisterBestMatchingNetworkCallback_trackBestNetwork() throws Exception { final TestNetworkCallback bestMatchingCb = new TestNetworkCallback(); mCm.registerBestMatchingNetworkCallback( new NetworkRequest.Builder().addCapability(NET_CAPABILITY_TRUSTED).build(), bestMatchingCb, mCsHandlerThread.getThreadHandler()); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); // Change something on cellular to trigger capabilities changed, since the callback // only cares about the best network, verify it received nothing from cellular. mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); bestMatchingCb.assertNoCallback(); // Make cellular the best network again, verify the callback now tracks cellular. mWiFiNetworkAgent.adjustScore(-50); bestMatchingCb.expectAvailableCallbacksValidated(mCellNetworkAgent); // Make cellular temporary non-trusted, which will not satisfying the request. // Verify the callback switch from/to the other network accordingly. mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED); bestMatchingCb.expectAvailableCallbacksValidated(mWiFiNetworkAgent); mCellNetworkAgent.addCapability(NET_CAPABILITY_TRUSTED); bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellNetworkAgent); // Verify the callback doesn't care about wifi disconnect. mWiFiNetworkAgent.disconnect(); bestMatchingCb.assertNoCallback(); mCellNetworkAgent.disconnect(); bestMatchingCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); } } Loading
packages/Connectivity/framework/src/android/net/ConnectivityManager.java +2 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,8 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; import static android.net.NetworkRequest.Type.LISTEN; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; import static android.net.NetworkRequest.Type.REQUEST; import static android.net.NetworkRequest.Type.TRACK_BEST; import static android.net.NetworkRequest.Type.TRACK_DEFAULT; import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT; import static android.net.QosCallback.QosCallbackRegistrationException; Loading Loading @@ -4249,7 +4249,7 @@ public class ConnectivityManager { @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { final NetworkCapabilities nc = request.networkCapabilities; final CallbackHandler cbHandler = new CallbackHandler(handler); sendRequestForNetwork(nc, networkCallback, 0, TRACK_BEST, TYPE_NONE, cbHandler); sendRequestForNetwork(nc, networkCallback, 0, LISTEN_FOR_BEST, TYPE_NONE, cbHandler); } /** Loading
packages/Connectivity/framework/src/android/net/NetworkRequest.java +10 −1 Original line number Diff line number Diff line Loading @@ -140,7 +140,7 @@ public class NetworkRequest implements Parcelable { REQUEST, BACKGROUND_REQUEST, TRACK_SYSTEM_DEFAULT, TRACK_BEST, LISTEN_FOR_BEST, }; /** Loading Loading @@ -513,6 +513,15 @@ public class NetworkRequest implements Parcelable { return type == Type.LISTEN; } /** * Returns true iff. this NetworkRequest is of type LISTEN_FOR_BEST. * * @hide */ public boolean isListenForBest() { return type == Type.LISTEN_FOR_BEST; } /** * Returns true iff. the contained NetworkRequest is one that: * Loading
services/core/java/com/android/server/ConnectivityService.java +18 −7 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.uidRulesToString; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired; import static android.os.Process.INVALID_UID; import static android.os.Process.VPN_UID; Loading Loading @@ -3663,6 +3664,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkRequestInfoLogs.log("REGISTER " + nri); for (final NetworkRequest req : nri.mRequests) { mNetworkRequests.put(req, nri); // TODO: Consider update signal strength for other types. if (req.isListen()) { for (final NetworkAgentInfo network : mNetworkAgentInfos) { if (req.networkCapabilities.hasSignalStrength() Loading Loading @@ -3755,18 +3757,19 @@ public class ConnectivityService extends IConnectivityManager.Stub // listen requests won't keep up a network satisfying it. If this is not a multilayer // request, return immediately. For multilayer requests, check to see if any of the // multilayer requests may have a potential satisfier. if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) { if (!nri.isMultilayerRequest() && (nri.mRequests.get(0).isListen() || nri.mRequests.get(0).isListenForBest())) { return false; } for (final NetworkRequest req : nri.mRequests) { // This multilayer listen request is satisfied therefore no further requests need to be // evaluated deeming this network not a potential satisfier. if (req.isListen() && nri.getActiveRequest() == req) { if ((req.isListen() || req.isListenForBest()) && nri.getActiveRequest() == req) { return false; } // 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()) { if (req.isListen() || req.isListenForBest()) { continue; } // If this Network is already the highest scoring Network for a request, or if Loading Loading @@ -5549,8 +5552,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // request if the app changes network state. http://b/29964605 enforceMeteredApnPolicy(networkCapabilities); break; case TRACK_BEST: throw new UnsupportedOperationException("Not implemented yet"); case LISTEN_FOR_BEST: enforceAccessPermission(); networkCapabilities = new NetworkCapabilities(networkCapabilities); break; default: throw new IllegalArgumentException("Unsupported request type " + reqType); } Loading @@ -5558,11 +5563,17 @@ public class ConnectivityService extends IConnectivityManager.Stub ensureSufficientPermissionsForRequest(networkCapabilities, Binder.getCallingPid(), callingUid, callingPackageName); // Set the UID range for this request to the single UID of the requester, or to an empty // set of UIDs if the caller has the appropriate permission and UIDs have not been set. // Enforce FOREGROUND if the caller does not have permission to use background network. if (reqType == LISTEN_FOR_BEST) { restrictBackgroundRequestForCaller(networkCapabilities); } // Set the UID range for this request to the single UID of the requester, unless the // requester has the permission to specify other UIDs. // This will overwrite any allowed UIDs in the requested capabilities. Though there // are no visible methods to set the UIDs, an app could use reflection to try and get // networks for other apps so it's essential that the UIDs are overwritten. // Also set the requester UID and package name in the request. restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities, callingUid, callingPackageName); Loading
services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +1 −0 Original line number Diff line number Diff line Loading @@ -719,6 +719,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { break; case LISTEN: case LISTEN_FOR_BEST: case TRACK_DEFAULT: case TRACK_SYSTEM_DEFAULT: break; Loading
tests/net/java/com/android/server/ConnectivityServiceTest.java +97 −5 Original line number Diff line number Diff line Loading @@ -1079,6 +1079,10 @@ public class ConnectivityServiceTest { public void triggerUnfulfillable(NetworkRequest r) { super.releaseRequestAsUnfulfillableByAnyFactory(r); } public void assertNoRequestChanged() { assertNull(mRequestHistory.poll(0, r -> true)); } } private Set<UidRange> uidRangesForUids(int... uids) { Loading Loading @@ -11121,11 +11125,99 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(cellCb); } // Cannot be part of MockNetworkFactory since it requires method of the test. private void expectNoRequestChanged(@NonNull MockNetworkFactory factory) { waitForIdle(); factory.assertNoRequestChanged(); } @Test public void testRegisterBestMatchingNetworkCallback() throws Exception { final NetworkRequest request = new NetworkRequest.Builder().build(); assertThrows(UnsupportedOperationException.class, () -> mCm.registerBestMatchingNetworkCallback(request, new NetworkCallback(), mCsHandlerThread.getThreadHandler())); public void testRegisterBestMatchingNetworkCallback_noIssueToFactory() throws Exception { // Prepare mock mms factory. final HandlerThread handlerThread = new HandlerThread("MockCellularFactory"); handlerThread.start(); NetworkCapabilities filter = new NetworkCapabilities() .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_MMS); final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), mServiceContext, "testFactory", filter, mCsHandlerThread); testFactory.setScoreFilter(40); try { // Register the factory and expect it will see default request, because all requests // are sent to all factories. testFactory.register(); testFactory.expectRequestAdd(); testFactory.assertRequestCountEquals(1); // The factory won't try to start the network since the default request doesn't // match the filter (no INTERNET capability). assertFalse(testFactory.getMyStartRequested()); // Register callback for listening best matching network. Verify that the request won't // be sent to factory. final TestNetworkCallback bestMatchingCb = new TestNetworkCallback(); mCm.registerBestMatchingNetworkCallback( new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(), bestMatchingCb, mCsHandlerThread.getThreadHandler()); bestMatchingCb.assertNoCallback(); expectNoRequestChanged(testFactory); testFactory.assertRequestCountEquals(1); assertFalse(testFactory.getMyStartRequested()); // Fire a normal mms request, verify the factory will only see the request. final TestNetworkCallback mmsNetworkCallback = new TestNetworkCallback(); final NetworkRequest mmsRequest = new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_MMS).build(); mCm.requestNetwork(mmsRequest, mmsNetworkCallback); testFactory.expectRequestAdd(); testFactory.assertRequestCountEquals(2); assertTrue(testFactory.getMyStartRequested()); // Unregister best matching callback, verify factory see no change. mCm.unregisterNetworkCallback(bestMatchingCb); expectNoRequestChanged(testFactory); testFactory.assertRequestCountEquals(2); assertTrue(testFactory.getMyStartRequested()); } finally { testFactory.terminate(); } } @Test public void testRegisterBestMatchingNetworkCallback_trackBestNetwork() throws Exception { final TestNetworkCallback bestMatchingCb = new TestNetworkCallback(); mCm.registerBestMatchingNetworkCallback( new NetworkRequest.Builder().addCapability(NET_CAPABILITY_TRUSTED).build(), bestMatchingCb, mCsHandlerThread.getThreadHandler()); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); // Change something on cellular to trigger capabilities changed, since the callback // only cares about the best network, verify it received nothing from cellular. mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED); bestMatchingCb.assertNoCallback(); // Make cellular the best network again, verify the callback now tracks cellular. mWiFiNetworkAgent.adjustScore(-50); bestMatchingCb.expectAvailableCallbacksValidated(mCellNetworkAgent); // Make cellular temporary non-trusted, which will not satisfying the request. // Verify the callback switch from/to the other network accordingly. mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED); bestMatchingCb.expectAvailableCallbacksValidated(mWiFiNetworkAgent); mCellNetworkAgent.addCapability(NET_CAPABILITY_TRUSTED); bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellNetworkAgent); // Verify the callback doesn't care about wifi disconnect. mWiFiNetworkAgent.disconnect(); bestMatchingCb.assertNoCallback(); mCellNetworkAgent.disconnect(); bestMatchingCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); } }