Merge "[VCN13] Implement tracking best matching network" am: f98037abb3 am: 4377c5d40c

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1633519

Change-Id: I49f94fb997e770874e851afaa5266c6fd2ba1396
This commit is contained in:
Junyu Lai
2021-03-16 17:17:08 +00:00
committed by Automerger Merge Worker
5 changed files with 128 additions and 15 deletions

View File

@@ -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;
@@ -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);
}
/**

View File

@@ -140,7 +140,7 @@ public class NetworkRequest implements Parcelable {
REQUEST,
BACKGROUND_REQUEST,
TRACK_SYSTEM_DEFAULT,
TRACK_BEST,
LISTEN_FOR_BEST,
};
/**
@@ -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:
*

View File

@@ -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;
@@ -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()
@@ -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
@@ -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);
}
@@ -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);

View File

@@ -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;

View File

@@ -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) {
@@ -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);
}
}