Support selecting non-INTERNET networks as underlying networks
This commit allows VCN to select underlying Cell networks according to caller configured network capabilities instead of always only selecting INTERNET networks as underlying networks. This commit also makes sure that if all of the network candidates fail to match caller configured network templates, VCN can still select an INTERNET network as a fallback but will never select a non-INTERNET network. Bug: 245618320 Test: FrameworksVcnTests(new tests), CtsVcnTestCases Change-Id: I6eca0331e4bc6804a500fbed9909bb91b1e80d2d
This commit is contained in:
@@ -353,6 +353,11 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork
|
||||
return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_RCS);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public Map<Integer, Integer> getCapabilitiesMatchCriteria() {
|
||||
return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.server.vcn.routeselection;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||
@@ -45,6 +46,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription
|
||||
import com.android.server.vcn.VcnContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -69,9 +71,23 @@ class NetworkPriorityClassifier {
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;
|
||||
|
||||
/** Priority for any other networks (including unvalidated, etc) */
|
||||
/**
|
||||
* Priority for networks that VCN can fall back to.
|
||||
*
|
||||
* <p>If none of the network candidates are validated or match any template, VCN will fall back
|
||||
* to any INTERNET network.
|
||||
*/
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int PRIORITY_ANY = Integer.MAX_VALUE;
|
||||
static final int PRIORITY_FALLBACK = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Priority for networks that cannot be selected as VCN's underlying networks.
|
||||
*
|
||||
* <p>VCN MUST never select a non-INTERNET network that are unvalidated or fail to match any
|
||||
* template as the underlying network.
|
||||
*/
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int PRIORITY_INVALID = -1;
|
||||
|
||||
/** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */
|
||||
public static int calculatePriorityClass(
|
||||
@@ -86,12 +102,12 @@ class NetworkPriorityClassifier {
|
||||
|
||||
if (networkRecord.isBlocked) {
|
||||
logWtf("Network blocked for System Server: " + networkRecord.network);
|
||||
return PRIORITY_ANY;
|
||||
return PRIORITY_INVALID;
|
||||
}
|
||||
|
||||
if (snapshot == null) {
|
||||
logWtf("Got null snapshot");
|
||||
return PRIORITY_ANY;
|
||||
return PRIORITY_INVALID;
|
||||
}
|
||||
|
||||
int priorityIndex = 0;
|
||||
@@ -108,7 +124,13 @@ class NetworkPriorityClassifier {
|
||||
}
|
||||
priorityIndex++;
|
||||
}
|
||||
return PRIORITY_ANY;
|
||||
|
||||
final NetworkCapabilities caps = networkRecord.networkCapabilities;
|
||||
if (caps.hasCapability(NET_CAPABILITY_INTERNET)
|
||||
|| (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST))) {
|
||||
return PRIORITY_FALLBACK;
|
||||
}
|
||||
return PRIORITY_INVALID;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
@@ -297,6 +319,18 @@ class NetworkPriorityClassifier {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, Integer> entry :
|
||||
networkPriority.getCapabilitiesMatchCriteria().entrySet()) {
|
||||
final int cap = entry.getKey();
|
||||
final int matchCriteria = entry.getValue();
|
||||
|
||||
if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) {
|
||||
return false;
|
||||
} else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.server.vcn.routeselection;
|
||||
|
||||
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
|
||||
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
|
||||
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
|
||||
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
|
||||
|
||||
import static com.android.server.VcnManagementService.LOCAL_LOG;
|
||||
@@ -32,6 +35,7 @@ import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
|
||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
||||
import android.net.vcn.VcnUnderlyingNetworkTemplate;
|
||||
import android.os.Handler;
|
||||
@@ -40,6 +44,7 @@ import android.os.ParcelUuid;
|
||||
import android.telephony.TelephonyCallback;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -49,6 +54,7 @@ import com.android.server.vcn.VcnContext;
|
||||
import com.android.server.vcn.util.LogUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -126,6 +132,63 @@ public class UnderlyingNetworkController {
|
||||
registerOrUpdateNetworkRequests();
|
||||
}
|
||||
|
||||
private static class CapabilityMatchCriteria {
|
||||
public final int capability;
|
||||
public final int matchCriteria;
|
||||
|
||||
CapabilityMatchCriteria(int capability, int matchCriteria) {
|
||||
this.capability = capability;
|
||||
this.matchCriteria = matchCriteria;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(capability, matchCriteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (!(other instanceof CapabilityMatchCriteria)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final CapabilityMatchCriteria rhs = (CapabilityMatchCriteria) other;
|
||||
return capability == rhs.capability && matchCriteria == rhs.matchCriteria;
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<Set<CapabilityMatchCriteria>> dedupAndGetCapRequirementsForCell(
|
||||
VcnGatewayConnectionConfig connectionConfig) {
|
||||
final Set<Set<CapabilityMatchCriteria>> dedupedCapsMatchSets = new ArraySet<>();
|
||||
|
||||
for (VcnUnderlyingNetworkTemplate template :
|
||||
connectionConfig.getVcnUnderlyingNetworkPriorities()) {
|
||||
if (template instanceof VcnCellUnderlyingNetworkTemplate) {
|
||||
final Set<CapabilityMatchCriteria> capsMatchSet = new ArraySet<>();
|
||||
|
||||
for (Map.Entry<Integer, Integer> entry :
|
||||
((VcnCellUnderlyingNetworkTemplate) template)
|
||||
.getCapabilitiesMatchCriteria()
|
||||
.entrySet()) {
|
||||
|
||||
final int capability = entry.getKey();
|
||||
final int matchCriteria = entry.getValue();
|
||||
if (matchCriteria != MATCH_ANY) {
|
||||
capsMatchSet.add(new CapabilityMatchCriteria(capability, matchCriteria));
|
||||
}
|
||||
}
|
||||
|
||||
dedupedCapsMatchSets.add(capsMatchSet);
|
||||
}
|
||||
}
|
||||
|
||||
dedupedCapsMatchSets.add(
|
||||
Collections.singleton(
|
||||
new CapabilityMatchCriteria(
|
||||
NetworkCapabilities.NET_CAPABILITY_INTERNET, MATCH_REQUIRED)));
|
||||
return dedupedCapsMatchSets;
|
||||
}
|
||||
|
||||
private void registerOrUpdateNetworkRequests() {
|
||||
NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback;
|
||||
NetworkCallback oldWifiCallback = mWifiBringupCallback;
|
||||
@@ -158,11 +221,14 @@ public class UnderlyingNetworkController {
|
||||
getWifiNetworkRequest(), mWifiBringupCallback, mHandler);
|
||||
|
||||
for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
|
||||
final NetworkBringupCallback cb = new NetworkBringupCallback();
|
||||
mCellBringupCallbacks.add(cb);
|
||||
for (Set<CapabilityMatchCriteria> capsMatchCriteria :
|
||||
dedupAndGetCapRequirementsForCell(mConnectionConfig)) {
|
||||
final NetworkBringupCallback cb = new NetworkBringupCallback();
|
||||
mCellBringupCallbacks.add(cb);
|
||||
|
||||
mConnectivityManager.requestBackgroundNetwork(
|
||||
getCellNetworkRequestForSubId(subId), cb, mHandler);
|
||||
mConnectivityManager.requestBackgroundNetwork(
|
||||
getCellNetworkRequestForSubId(subId, capsMatchCriteria), cb, mHandler);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mRouteSelectionCallback = null;
|
||||
@@ -214,6 +280,13 @@ public class UnderlyingNetworkController {
|
||||
.build();
|
||||
}
|
||||
|
||||
private NetworkRequest.Builder getBaseWifiNetworkRequestBuilder() {
|
||||
return getBaseNetworkRequestBuilder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the WiFi bringup request
|
||||
*
|
||||
@@ -224,10 +297,7 @@ public class UnderlyingNetworkController {
|
||||
* but will NEVER bring up a Carrier WiFi network itself.
|
||||
*/
|
||||
private NetworkRequest getWifiNetworkRequest() {
|
||||
return getBaseNetworkRequestBuilder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
|
||||
.build();
|
||||
return getBaseWifiNetworkRequestBuilder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,9 +308,7 @@ public class UnderlyingNetworkController {
|
||||
* pace to effectively select a short-lived WiFi offload network.
|
||||
*/
|
||||
private NetworkRequest getWifiEntryRssiThresholdNetworkRequest() {
|
||||
return getBaseNetworkRequestBuilder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
|
||||
return getBaseWifiNetworkRequestBuilder()
|
||||
// Ensure wifi updates signal strengths when crossing this threshold.
|
||||
.setSignalStrength(getWifiEntryRssiThreshold(mCarrierConfig))
|
||||
.build();
|
||||
@@ -254,9 +322,7 @@ public class UnderlyingNetworkController {
|
||||
* pace to effectively select away from a failing WiFi network.
|
||||
*/
|
||||
private NetworkRequest getWifiExitRssiThresholdNetworkRequest() {
|
||||
return getBaseNetworkRequestBuilder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
|
||||
return getBaseWifiNetworkRequestBuilder()
|
||||
// Ensure wifi updates signal strengths when crossing this threshold.
|
||||
.setSignalStrength(getWifiExitRssiThreshold(mCarrierConfig))
|
||||
.build();
|
||||
@@ -273,11 +339,25 @@ public class UnderlyingNetworkController {
|
||||
* <p>Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified
|
||||
* in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier.
|
||||
*/
|
||||
private NetworkRequest getCellNetworkRequestForSubId(int subId) {
|
||||
return getBaseNetworkRequestBuilder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
|
||||
.build();
|
||||
private NetworkRequest getCellNetworkRequestForSubId(
|
||||
int subId, Set<CapabilityMatchCriteria> capsMatchCriteria) {
|
||||
final NetworkRequest.Builder nrBuilder =
|
||||
getBaseNetworkRequestBuilder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
|
||||
|
||||
for (CapabilityMatchCriteria capMatchCriteria : capsMatchCriteria) {
|
||||
final int cap = capMatchCriteria.capability;
|
||||
final int matchCriteria = capMatchCriteria.matchCriteria;
|
||||
|
||||
if (matchCriteria == MATCH_REQUIRED) {
|
||||
nrBuilder.addCapability(cap);
|
||||
} else if (matchCriteria == MATCH_FORBIDDEN) {
|
||||
nrBuilder.addForbiddenCapability(cap);
|
||||
}
|
||||
}
|
||||
|
||||
return nrBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +365,6 @@ public class UnderlyingNetworkController {
|
||||
*/
|
||||
private NetworkRequest.Builder getBaseNetworkRequestBuilder() {
|
||||
return new NetworkRequest.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
@@ -406,7 +485,9 @@ public class UnderlyingNetworkController {
|
||||
mLastSnapshot,
|
||||
mCurrentRecord,
|
||||
mCarrierConfig);
|
||||
sorted.add(record);
|
||||
if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) {
|
||||
sorted.add(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTe
|
||||
private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>();
|
||||
private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>();
|
||||
|
||||
private static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() {
|
||||
// Public for use in UnderlyingNetworkControllerTest
|
||||
public static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() {
|
||||
return new VcnCellUnderlyingNetworkTemplate.Builder()
|
||||
.setMetered(MATCH_FORBIDDEN)
|
||||
.setMinUpstreamBandwidthKbps(
|
||||
|
||||
@@ -100,14 +100,20 @@ public class VcnGatewayConnectionConfigTest {
|
||||
EXPOSED_CAPS);
|
||||
}
|
||||
|
||||
// Public for use in VcnGatewayConnectionTest
|
||||
public static VcnGatewayConnectionConfig buildTestConfig() {
|
||||
// Public for use in UnderlyingNetworkControllerTest
|
||||
public static VcnGatewayConnectionConfig buildTestConfig(
|
||||
List<VcnUnderlyingNetworkTemplate> nwTemplates) {
|
||||
final VcnGatewayConnectionConfig.Builder builder =
|
||||
newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_TEMPLATES);
|
||||
newBuilder().setVcnUnderlyingNetworkPriorities(nwTemplates);
|
||||
|
||||
return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS);
|
||||
}
|
||||
|
||||
// Public for use in VcnGatewayConnectionTest
|
||||
public static VcnGatewayConnectionConfig buildTestConfig() {
|
||||
return buildTestConfig(UNDERLYING_NETWORK_TEMPLATES);
|
||||
}
|
||||
|
||||
private static VcnGatewayConnectionConfig.Builder newBuilder() {
|
||||
// Append a unique identifier to the name prefix to guarantee that all created
|
||||
// VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.vcn.routeselection;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
|
||||
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
|
||||
import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS;
|
||||
@@ -24,7 +25,8 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT
|
||||
import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS;
|
||||
|
||||
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_FALLBACK;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule;
|
||||
@@ -64,6 +66,7 @@ import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -103,6 +106,7 @@ public class NetworkPriorityClassifierTest {
|
||||
private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setSubscriptionIds(Set.of(SUB_ID))
|
||||
.setNetworkSpecifier(TEL_NETWORK_SPECIFIER)
|
||||
@@ -501,24 +505,72 @@ public class NetworkPriorityClassifierTest {
|
||||
mSubscriptionSnapshot));
|
||||
}
|
||||
|
||||
private void verifyMatchCellWithRequiredCapabilities(
|
||||
VcnCellUnderlyingNetworkTemplate template, boolean expectMatch) {
|
||||
assertEquals(
|
||||
expectMatch,
|
||||
checkMatchesCellPriorityRule(
|
||||
mVcnContext,
|
||||
template,
|
||||
mCellNetworkRecord,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchCell() {
|
||||
final VcnCellUnderlyingNetworkTemplate template =
|
||||
getCellNetworkPriorityBuilder().setInternet(MATCH_REQUIRED).build();
|
||||
verifyMatchCellWithRequiredCapabilities(template, true /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchCellFail_RequiredCapabilitiesMissing() {
|
||||
final VcnCellUnderlyingNetworkTemplate template =
|
||||
getCellNetworkPriorityBuilder().setCbs(MATCH_REQUIRED).build();
|
||||
verifyMatchCellWithRequiredCapabilities(template, false /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchCellFail_ForbiddenCapabilitiesFound() {
|
||||
final VcnCellUnderlyingNetworkTemplate template =
|
||||
getCellNetworkPriorityBuilder().setDun(MATCH_FORBIDDEN).build();
|
||||
verifyMatchCellWithRequiredCapabilities(template, false /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePriorityClass() throws Exception {
|
||||
assertEquals(2, mCellNetworkRecord.priorityClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePriorityClassFailToMatchAny() throws Exception {
|
||||
final NetworkCapabilities nc =
|
||||
private void checkCalculatePriorityClassFailToMatchAny(
|
||||
boolean hasInternet, int expectedPriorityClass) throws Exception {
|
||||
final List<VcnUnderlyingNetworkTemplate> templatesRequireDun =
|
||||
Collections.singletonList(
|
||||
new VcnCellUnderlyingNetworkTemplate.Builder()
|
||||
.setDun(MATCH_REQUIRED)
|
||||
.build());
|
||||
|
||||
final NetworkCapabilities.Builder ncBuilder =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.setSignalStrength(WIFI_RSSI_LOW)
|
||||
.setSsid(SSID)
|
||||
.build();
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
|
||||
if (hasInternet) {
|
||||
ncBuilder.addCapability(NET_CAPABILITY_INTERNET);
|
||||
}
|
||||
|
||||
final UnderlyingNetworkRecord wifiNetworkRecord =
|
||||
getTestNetworkRecord(
|
||||
nc, VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
|
||||
final UnderlyingNetworkRecord nonDunNetworkRecord =
|
||||
getTestNetworkRecord(ncBuilder.build(), templatesRequireDun);
|
||||
|
||||
assertEquals(PRIORITY_ANY, wifiNetworkRecord.priorityClass);
|
||||
assertEquals(expectedPriorityClass, nonDunNetworkRecord.priorityClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePriorityClassFailToMatchAny_InternetNetwork() throws Exception {
|
||||
checkCalculatePriorityClassFailToMatchAny(true /* hasInternet */, PRIORITY_FALLBACK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePriorityClassFailToMatchAny_NonInternetNetwork() throws Exception {
|
||||
checkCalculatePriorityClassFailToMatchAny(false /* hasInternet */, PRIORITY_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
|
||||
package com.android.server.vcn.routeselection;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
|
||||
import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_ANY;
|
||||
import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
|
||||
import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_REQUIRED;
|
||||
|
||||
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
|
||||
@@ -30,6 +38,7 @@ import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -44,7 +53,10 @@ import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
|
||||
import android.net.vcn.VcnCellUnderlyingNetworkTemplateTest;
|
||||
import android.net.vcn.VcnGatewayConnectionConfigTest;
|
||||
import android.net.vcn.VcnUnderlyingNetworkTemplate;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
@@ -66,7 +78,10 @@ import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -97,11 +112,39 @@ public class UnderlyingNetworkControllerTest {
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.build();
|
||||
|
||||
private static final NetworkCapabilities DUN_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
.build();
|
||||
|
||||
private static final NetworkCapabilities CBS_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
.build();
|
||||
|
||||
private static final LinkProperties INITIAL_LINK_PROPERTIES =
|
||||
getLinkPropertiesWithName("initial_iface");
|
||||
private static final LinkProperties UPDATED_LINK_PROPERTIES =
|
||||
getLinkPropertiesWithName("updated_iface");
|
||||
|
||||
private static final VcnCellUnderlyingNetworkTemplate CELL_TEMPLATE_DUN =
|
||||
new VcnCellUnderlyingNetworkTemplate.Builder()
|
||||
.setInternet(MATCH_ANY)
|
||||
.setDun(MATCH_REQUIRED)
|
||||
.build();
|
||||
|
||||
private static final VcnCellUnderlyingNetworkTemplate CELL_TEMPLATE_CBS =
|
||||
new VcnCellUnderlyingNetworkTemplate.Builder()
|
||||
.setInternet(MATCH_ANY)
|
||||
.setCbs(MATCH_REQUIRED)
|
||||
.build();
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private VcnNetworkProvider mVcnNetworkProvider;
|
||||
@Mock private ConnectivityManager mConnectivityManager;
|
||||
@@ -203,6 +246,107 @@ public class UnderlyingNetworkControllerTest {
|
||||
any());
|
||||
}
|
||||
|
||||
private void verifyRequestBackgroundNetwork(
|
||||
ConnectivityManager cm,
|
||||
int expectedSubId,
|
||||
Set<Integer> expectedRequiredCaps,
|
||||
Set<Integer> expectedForbiddenCaps) {
|
||||
verify(cm)
|
||||
.requestBackgroundNetwork(
|
||||
eq(
|
||||
getCellRequestForSubId(
|
||||
expectedSubId,
|
||||
expectedRequiredCaps,
|
||||
expectedForbiddenCaps)),
|
||||
any(NetworkBringupCallback.class),
|
||||
any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkCallbacksRegisteredOnStartupForNonInternetCapabilities() {
|
||||
final ConnectivityManager cm = mock(ConnectivityManager.class);
|
||||
setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
|
||||
|
||||
// Build network templates
|
||||
final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
|
||||
|
||||
networkTemplates.add(
|
||||
VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplateBuilder()
|
||||
.setDun(MATCH_REQUIRED)
|
||||
.setInternet(MATCH_ANY)
|
||||
.build());
|
||||
|
||||
networkTemplates.add(
|
||||
VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplateBuilder()
|
||||
.setMms(MATCH_REQUIRED)
|
||||
.setCbs(MATCH_FORBIDDEN)
|
||||
.setInternet(MATCH_ANY)
|
||||
.build());
|
||||
|
||||
// Start UnderlyingNetworkController
|
||||
new UnderlyingNetworkController(
|
||||
mVcnContext,
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates),
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
mNetworkControllerCb);
|
||||
|
||||
// Verifications
|
||||
for (final int subId : INITIAL_SUB_IDS) {
|
||||
verifyRequestBackgroundNetwork(
|
||||
cm,
|
||||
subId,
|
||||
Collections.singleton(NET_CAPABILITY_INTERNET),
|
||||
Collections.emptySet());
|
||||
verifyRequestBackgroundNetwork(
|
||||
cm, subId, Collections.singleton(NET_CAPABILITY_DUN), Collections.emptySet());
|
||||
verifyRequestBackgroundNetwork(
|
||||
cm,
|
||||
subId,
|
||||
Collections.singleton(NET_CAPABILITY_MMS),
|
||||
Collections.singleton(NET_CAPABILITY_CBS));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkCallbacksRegisteredOnStartupWithDedupedtCapabilities() {
|
||||
final ConnectivityManager cm = mock(ConnectivityManager.class);
|
||||
setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
|
||||
|
||||
// Build network templates
|
||||
final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
|
||||
final VcnCellUnderlyingNetworkTemplate.Builder builder =
|
||||
new VcnCellUnderlyingNetworkTemplate.Builder()
|
||||
.setMms(MATCH_REQUIRED)
|
||||
.setCbs(MATCH_FORBIDDEN)
|
||||
.setInternet(MATCH_ANY);
|
||||
|
||||
networkTemplates.add(builder.setMetered(MATCH_REQUIRED).build());
|
||||
networkTemplates.add(builder.setMetered(MATCH_FORBIDDEN).build());
|
||||
|
||||
// Start UnderlyingNetworkController
|
||||
new UnderlyingNetworkController(
|
||||
mVcnContext,
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates),
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
mNetworkControllerCb);
|
||||
|
||||
// Verifications
|
||||
for (final int subId : INITIAL_SUB_IDS) {
|
||||
verifyRequestBackgroundNetwork(
|
||||
cm,
|
||||
subId,
|
||||
Collections.singleton(NET_CAPABILITY_INTERNET),
|
||||
Collections.emptySet());
|
||||
verifyRequestBackgroundNetwork(
|
||||
cm,
|
||||
subId,
|
||||
Collections.singleton(NET_CAPABILITY_MMS),
|
||||
Collections.singleton(NET_CAPABILITY_CBS));
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) {
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
@@ -212,8 +356,13 @@ public class UnderlyingNetworkControllerTest {
|
||||
for (final int subId : expectedSubIds) {
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getCellRequestForSubId(subId)),
|
||||
any(NetworkBringupCallback.class), any());
|
||||
eq(
|
||||
getCellRequestForSubId(
|
||||
subId,
|
||||
Collections.singleton(NET_CAPABILITY_INTERNET),
|
||||
Collections.emptySet())),
|
||||
any(NetworkBringupCallback.class),
|
||||
any());
|
||||
}
|
||||
|
||||
verify(mConnectivityManager)
|
||||
@@ -255,6 +404,7 @@ public class UnderlyingNetworkControllerTest {
|
||||
private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) {
|
||||
return getExpectedRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.setSubscriptionIds(netCapsSubIds)
|
||||
.build();
|
||||
}
|
||||
@@ -263,6 +413,7 @@ public class UnderlyingNetworkControllerTest {
|
||||
// TODO (b/187991063): Add tests for carrier-config based thresholds
|
||||
return getExpectedRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.setSubscriptionIds(netCapsSubIds)
|
||||
.setSignalStrength(WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT)
|
||||
.build();
|
||||
@@ -272,16 +423,27 @@ public class UnderlyingNetworkControllerTest {
|
||||
// TODO (b/187991063): Add tests for carrier-config based thresholds
|
||||
return getExpectedRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.setSubscriptionIds(netCapsSubIds)
|
||||
.setSignalStrength(WIFI_EXIT_RSSI_THRESHOLD_DEFAULT)
|
||||
.build();
|
||||
}
|
||||
|
||||
private NetworkRequest getCellRequestForSubId(int subId) {
|
||||
return getExpectedRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
|
||||
.build();
|
||||
private NetworkRequest getCellRequestForSubId(
|
||||
int subId, Set<Integer> requiredCaps, Set<Integer> forbiddenCaps) {
|
||||
final NetworkRequest.Builder nqBuilder =
|
||||
getExpectedRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
|
||||
|
||||
for (int cap : requiredCaps) {
|
||||
nqBuilder.addCapability(cap);
|
||||
}
|
||||
for (int cap : forbiddenCaps) {
|
||||
nqBuilder.addForbiddenCapability(cap);
|
||||
}
|
||||
|
||||
return nqBuilder.build();
|
||||
}
|
||||
|
||||
private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
|
||||
@@ -303,7 +465,6 @@ public class UnderlyingNetworkControllerTest {
|
||||
private NetworkRequest.Builder getExpectedRequestBase() {
|
||||
final NetworkRequest.Builder builder =
|
||||
new NetworkRequest.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
@@ -506,13 +667,7 @@ public class UnderlyingNetworkControllerTest {
|
||||
|
||||
cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
getTestNetworkRecord(
|
||||
mNetwork,
|
||||
buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
true /* isBlocked */);
|
||||
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
|
||||
verifyOnSelectedUnderlyingNetworkChanged(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -548,5 +703,132 @@ public class UnderlyingNetworkControllerTest {
|
||||
verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
|
||||
}
|
||||
|
||||
// TODO (b/187991063): Add tests for network prioritization
|
||||
private UnderlyingNetworkListener setupControllerAndGetNetworkListener(
|
||||
List<VcnUnderlyingNetworkTemplate> networkTemplates) {
|
||||
final ConnectivityManager cm = mock(ConnectivityManager.class);
|
||||
setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
|
||||
|
||||
new UnderlyingNetworkController(
|
||||
mVcnContext,
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates),
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
mNetworkControllerCb);
|
||||
|
||||
verify(cm)
|
||||
.registerNetworkCallback(
|
||||
eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
|
||||
mUnderlyingNetworkListenerCaptor.capture(),
|
||||
any());
|
||||
|
||||
return mUnderlyingNetworkListenerCaptor.getValue();
|
||||
}
|
||||
|
||||
private UnderlyingNetworkRecord bringupNetworkAndGetRecord(
|
||||
UnderlyingNetworkListener cb,
|
||||
NetworkCapabilities requestNetworkCaps,
|
||||
List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
|
||||
UnderlyingNetworkRecord currentlySelected) {
|
||||
final Network network = mock(Network.class);
|
||||
final NetworkCapabilities responseNetworkCaps =
|
||||
buildResponseNwCaps(requestNetworkCaps, INITIAL_SUB_IDS);
|
||||
|
||||
cb.onAvailable(network);
|
||||
cb.onCapabilitiesChanged(network, responseNetworkCaps);
|
||||
cb.onLinkPropertiesChanged(network, INITIAL_LINK_PROPERTIES);
|
||||
cb.onBlockedStatusChanged(network, false /* isFalse */);
|
||||
return new UnderlyingNetworkRecord(
|
||||
network,
|
||||
responseNetworkCaps,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */,
|
||||
mVcnContext,
|
||||
underlyingNetworkTemplates,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
currentlySelected,
|
||||
null /* carrierConfig */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectMorePreferredNetwork() {
|
||||
final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
|
||||
networkTemplates.add(CELL_TEMPLATE_DUN);
|
||||
networkTemplates.add(CELL_TEMPLATE_CBS);
|
||||
|
||||
UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
|
||||
|
||||
// Bring up CBS network
|
||||
final UnderlyingNetworkRecord cbsNetworkRecord =
|
||||
bringupNetworkAndGetRecord(
|
||||
cb,
|
||||
CBS_NETWORK_CAPABILITIES,
|
||||
networkTemplates,
|
||||
null /* currentlySelected */);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord));
|
||||
|
||||
// Bring up DUN network
|
||||
final UnderlyingNetworkRecord dunNetworkRecord =
|
||||
bringupNetworkAndGetRecord(
|
||||
cb, DUN_NETWORK_CAPABILITIES, networkTemplates, cbsNetworkRecord);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeverSelectLessPreferredNetwork() {
|
||||
final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
|
||||
networkTemplates.add(CELL_TEMPLATE_DUN);
|
||||
networkTemplates.add(CELL_TEMPLATE_CBS);
|
||||
|
||||
UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
|
||||
|
||||
// Bring up DUN network
|
||||
final UnderlyingNetworkRecord dunNetworkRecord =
|
||||
bringupNetworkAndGetRecord(
|
||||
cb,
|
||||
DUN_NETWORK_CAPABILITIES,
|
||||
networkTemplates,
|
||||
null /* currentlySelected */);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord));
|
||||
|
||||
// Bring up CBS network
|
||||
final UnderlyingNetworkRecord cbsNetworkRecord =
|
||||
bringupNetworkAndGetRecord(
|
||||
cb, CBS_NETWORK_CAPABILITIES, networkTemplates, dunNetworkRecord);
|
||||
verify(mNetworkControllerCb, never())
|
||||
.onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailtoMatchTemplateAndFallBackToInternetNetwork() {
|
||||
final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
|
||||
|
||||
networkTemplates.add(
|
||||
new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build());
|
||||
UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
|
||||
|
||||
// Bring up an Internet network without DUN capability
|
||||
final UnderlyingNetworkRecord networkRecord =
|
||||
bringupNetworkAndGetRecord(
|
||||
cb,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
networkTemplates,
|
||||
null /* currentlySelected */);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(networkRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailtoMatchTemplateAndNeverFallBackToNonInternetNetwork() {
|
||||
final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
|
||||
|
||||
networkTemplates.add(
|
||||
new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build());
|
||||
UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
|
||||
|
||||
bringupNetworkAndGetRecord(
|
||||
cb, CBS_NETWORK_CAPABILITIES, networkTemplates, null /* currentlySelected */);
|
||||
|
||||
verify(mNetworkControllerCb, never())
|
||||
.onSelectedUnderlyingNetworkChanged(any(UnderlyingNetworkRecord.class));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user