Merge changes I6eca0331,I346323cb am: c9af6cf307

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

Change-Id: I5f312536e73d6ed44e3feaca0e025dfda1543650
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Yan Yan
2022-12-16 19:27:02 +00:00
committed by Automerger Merge Worker
10 changed files with 690 additions and 194 deletions

View File

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

View File

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

View File

@@ -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);
@@ -356,7 +435,7 @@ public class UnderlyingNetworkController {
if (!allNetworkPriorities.isEmpty()) {
allNetworkPriorities += ", ";
}
allNetworkPriorities += record.network + ": " + record.getPriorityClass();
allNetworkPriorities += record.network + ": " + record.priorityClass;
}
logInfo(
"Selected network changed to "
@@ -393,19 +472,22 @@ public class UnderlyingNetworkController {
private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() {
TreeSet<UnderlyingNetworkRecord> sorted =
new TreeSet<>(
UnderlyingNetworkRecord.getComparator(
new TreeSet<>(UnderlyingNetworkRecord.getComparator());
for (UnderlyingNetworkRecord.Builder builder :
mUnderlyingNetworkRecordBuilders.values()) {
if (builder.isValid()) {
final UnderlyingNetworkRecord record =
builder.build(
mVcnContext,
mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
mSubscriptionGroup,
mLastSnapshot,
mCurrentRecord,
mCarrierConfig));
for (UnderlyingNetworkRecord.Builder builder :
mUnderlyingNetworkRecordBuilders.values()) {
if (builder.isValid()) {
sorted.add(builder.build());
mCarrierConfig);
if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) {
sorted.add(record);
}
}
}

View File

@@ -42,53 +42,58 @@ import java.util.Objects;
* @hide
*/
public class UnderlyingNetworkRecord {
private static final int PRIORITY_CLASS_INVALID = Integer.MAX_VALUE;
@NonNull public final Network network;
@NonNull public final NetworkCapabilities networkCapabilities;
@NonNull public final LinkProperties linkProperties;
public final boolean isBlocked;
private int mPriorityClass = PRIORITY_CLASS_INVALID;
public final boolean isSelected;
public final int priorityClass;
@VisibleForTesting(visibility = Visibility.PRIVATE)
public UnderlyingNetworkRecord(
@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull LinkProperties linkProperties,
boolean isBlocked) {
this.network = network;
this.networkCapabilities = networkCapabilities;
this.linkProperties = linkProperties;
this.isBlocked = isBlocked;
}
private int getOrCalculatePriorityClass(
boolean isBlocked,
VcnContext vcnContext,
List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
PersistableBundleWrapper carrierConfig) {
// Never changes after the underlying network record is created.
if (mPriorityClass == PRIORITY_CLASS_INVALID) {
mPriorityClass =
NetworkPriorityClassifier.calculatePriorityClass(
vcnContext,
this,
underlyingNetworkTemplates,
subscriptionGroup,
snapshot,
currentlySelected,
carrierConfig);
}
this.network = network;
this.networkCapabilities = networkCapabilities;
this.linkProperties = linkProperties;
this.isBlocked = isBlocked;
return mPriorityClass;
this.isSelected = isSelected(this.network, currentlySelected);
priorityClass =
NetworkPriorityClassifier.calculatePriorityClass(
vcnContext,
this,
underlyingNetworkTemplates,
subscriptionGroup,
snapshot,
currentlySelected,
carrierConfig);
}
// Used in UnderlyingNetworkController
int getPriorityClass() {
return mPriorityClass;
@VisibleForTesting(visibility = Visibility.PRIVATE)
public UnderlyingNetworkRecord(
@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull LinkProperties linkProperties,
boolean isBlocked,
boolean isSelected,
int priorityClass) {
this.network = network;
this.networkCapabilities = networkCapabilities;
this.linkProperties = linkProperties;
this.isBlocked = isBlocked;
this.isSelected = isSelected;
this.priorityClass = priorityClass;
}
@Override
@@ -108,40 +113,32 @@ public class UnderlyingNetworkRecord {
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
}
static Comparator<UnderlyingNetworkRecord> getComparator(
VcnContext vcnContext,
List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
PersistableBundleWrapper carrierConfig) {
/** Returns if two records are equal including their priority classes. */
public static boolean isEqualIncludingPriorities(
UnderlyingNetworkRecord left, UnderlyingNetworkRecord right) {
if (left != null && right != null) {
return left.equals(right)
&& left.isSelected == right.isSelected
&& left.priorityClass == right.priorityClass;
}
return left == right;
}
static Comparator<UnderlyingNetworkRecord> getComparator() {
return (left, right) -> {
final int leftIndex =
left.getOrCalculatePriorityClass(
vcnContext,
underlyingNetworkTemplates,
subscriptionGroup,
snapshot,
currentlySelected,
carrierConfig);
final int rightIndex =
right.getOrCalculatePriorityClass(
vcnContext,
underlyingNetworkTemplates,
subscriptionGroup,
snapshot,
currentlySelected,
carrierConfig);
final int leftIndex = left.priorityClass;
final int rightIndex = right.priorityClass;
// In the case of networks in the same priority class, prioritize based on other
// criteria (eg. actively selected network, link metrics, etc)
if (leftIndex == rightIndex) {
// TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord
// fall into the same priority class.
if (isSelected(left, currentlySelected)) {
if (left.isSelected) {
return -1;
}
if (isSelected(left, currentlySelected)) {
if (right.isSelected) {
return 1;
}
}
@@ -150,11 +147,11 @@ public class UnderlyingNetworkRecord {
}
private static boolean isSelected(
UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) {
Network networkToCheck, UnderlyingNetworkRecord currentlySelected) {
if (currentlySelected == null) {
return false;
}
if (currentlySelected.network == recordToCheck.network) {
if (currentlySelected.network.equals(networkToCheck)) {
return true;
}
return false;
@@ -172,16 +169,8 @@ public class UnderlyingNetworkRecord {
pw.println("UnderlyingNetworkRecord:");
pw.increaseIndent();
final int priorityIndex =
getOrCalculatePriorityClass(
vcnContext,
underlyingNetworkTemplates,
subscriptionGroup,
snapshot,
currentlySelected,
carrierConfig);
pw.println("Priority index: " + priorityIndex);
pw.println("priorityClass: " + priorityClass);
pw.println("isSelected: " + isSelected);
pw.println("mNetwork: " + network);
pw.println("mNetworkCapabilities: " + networkCapabilities);
pw.println("mLinkProperties: " + linkProperties);
@@ -198,8 +187,6 @@ public class UnderlyingNetworkRecord {
boolean mIsBlocked;
boolean mWasIsBlockedSet;
@Nullable private UnderlyingNetworkRecord mCached;
Builder(@NonNull Network network) {
mNetwork = network;
}
@@ -211,7 +198,6 @@ public class UnderlyingNetworkRecord {
void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
mNetworkCapabilities = networkCapabilities;
mCached = null;
}
@Nullable
@@ -221,32 +207,40 @@ public class UnderlyingNetworkRecord {
void setLinkProperties(@NonNull LinkProperties linkProperties) {
mLinkProperties = linkProperties;
mCached = null;
}
void setIsBlocked(boolean isBlocked) {
mIsBlocked = isBlocked;
mWasIsBlockedSet = true;
mCached = null;
}
boolean isValid() {
return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
}
UnderlyingNetworkRecord build() {
UnderlyingNetworkRecord build(
VcnContext vcnContext,
List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
PersistableBundleWrapper carrierConfig) {
if (!isValid()) {
throw new IllegalArgumentException(
"Called build before UnderlyingNetworkRecord was valid");
}
if (mCached == null) {
mCached =
new UnderlyingNetworkRecord(
mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
}
return mCached;
return new UnderlyingNetworkRecord(
mNetwork,
mNetworkCapabilities,
mLinkProperties,
mIsBlocked,
vcnContext,
underlyingNetworkTemplates,
subscriptionGroup,
snapshot,
currentlySelected,
carrierConfig);
}
}
}

View File

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

View File

@@ -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).

View File

@@ -143,9 +143,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
capBuilder.setAdministratorUids(new int[] {TEST_UID});
final Network underlyingNetwork = mock(Network.class, CALLS_REAL_METHODS);
UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
underlyingNetwork,
capBuilder.build(), new LinkProperties(), false);
UnderlyingNetworkRecord record =
getTestNetworkRecord(
underlyingNetwork, capBuilder.build(), new LinkProperties(), false);
final NetworkCapabilities vcnCaps =
VcnGatewayConnection.buildNetworkCapabilities(
VcnGatewayConnectionConfigTest.buildTestConfig(),
@@ -211,7 +211,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers();
UnderlyingNetworkRecord record =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
new NetworkCapabilities.Builder().build(),
underlyingLp,

View File

@@ -109,9 +109,23 @@ public class VcnGatewayConnectionTestBase {
protected static final long ELAPSED_REAL_TIME = 123456789L;
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
protected static UnderlyingNetworkRecord getTestNetworkRecord(
Network network,
NetworkCapabilities networkCapabilities,
LinkProperties linkProperties,
boolean isBlocked) {
return new UnderlyingNetworkRecord(
network,
networkCapabilities,
linkProperties,
isBlocked,
false /* isSelected */,
0 /* priorityClass */);
}
protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
new NetworkCapabilities(),
new LinkProperties(),
@@ -124,7 +138,7 @@ public class VcnGatewayConnectionTestBase {
protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
new NetworkCapabilities(),
new LinkProperties(),

View File

@@ -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,8 +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.calculatePriorityClass;
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;
@@ -48,6 +49,7 @@ import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnManager;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.net.vcn.VcnWifiUnderlyingNetworkTemplate;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
@@ -64,6 +66,8 @@ 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;
@@ -102,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)
@@ -135,25 +140,35 @@ public class NetworkPriorityClassifierTest {
false /* isInTestMode */));
doNothing().when(mVcnContext).ensureRunningOnLooperThread();
mWifiNetworkRecord =
new UnderlyingNetworkRecord(
mNetwork,
WIFI_NETWORK_CAPABILITIES,
LINK_PROPERTIES,
false /* isBlocked */);
mCellNetworkRecord =
new UnderlyingNetworkRecord(
mNetwork,
CELL_NETWORK_CAPABILITIES,
LINK_PROPERTIES,
false /* isBlocked */);
setupSystemService(
mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID);
when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID);
mWifiNetworkRecord =
getTestNetworkRecord(
WIFI_NETWORK_CAPABILITIES,
VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
mCellNetworkRecord =
getTestNetworkRecord(
CELL_NETWORK_CAPABILITIES,
VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
}
private UnderlyingNetworkRecord getTestNetworkRecord(
NetworkCapabilities nc, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates) {
return new UnderlyingNetworkRecord(
mNetwork,
nc,
LINK_PROPERTIES,
false /* isBlocked */,
mVcnContext,
underlyingNetworkTemplates,
SUB_GROUP,
mSubscriptionSnapshot,
null /* currentlySelected */,
null /* carrierConfig */);
}
@Test
@@ -490,37 +505,72 @@ public class NetworkPriorityClassifierTest {
mSubscriptionSnapshot));
}
private void verifyCalculatePriorityClass(
UnderlyingNetworkRecord networkRecord, int expectedIndex) {
final int priorityIndex =
calculatePriorityClass(
private void verifyMatchCellWithRequiredCapabilities(
VcnCellUnderlyingNetworkTemplate template, boolean expectMatch) {
assertEquals(
expectMatch,
checkMatchesCellPriorityRule(
mVcnContext,
networkRecord,
VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES,
template,
mCellNetworkRecord,
SUB_GROUP,
mSubscriptionSnapshot,
null /* currentlySelected */,
null /* carrierConfig */);
mSubscriptionSnapshot));
}
assertEquals(expectedIndex, priorityIndex);
@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 {
verifyCalculatePriorityClass(mCellNetworkRecord, 2);
assertEquals(2, mCellNetworkRecord.priorityClass);
}
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_CELLULAR);
if (hasInternet) {
ncBuilder.addCapability(NET_CAPABILITY_INTERNET);
}
final UnderlyingNetworkRecord nonDunNetworkRecord =
getTestNetworkRecord(ncBuilder.build(), templatesRequireDun);
assertEquals(expectedPriorityClass, nonDunNetworkRecord.priorityClass);
}
@Test
public void testCalculatePriorityClassFailToMatchAny() throws Exception {
final NetworkCapabilities nc =
new NetworkCapabilities.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setSignalStrength(WIFI_RSSI_LOW)
.setSsid(SSID)
.build();
final UnderlyingNetworkRecord wifiNetworkRecord =
new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */);
public void testCalculatePriorityClassFailToMatchAny_InternetNetwork() throws Exception {
checkCalculatePriorityClassFailToMatchAny(true /* hasInternet */, PRIORITY_FALLBACK);
}
verifyCalculatePriorityClass(wifiNetworkRecord, PRIORITY_ANY);
@Test
public void testCalculatePriorityClassFailToMatchAny_NonInternetNetwork() throws Exception {
checkCalculatePriorityClassFailToMatchAny(false /* hasInternet */, PRIORITY_INVALID);
}
}

View File

@@ -16,18 +16,29 @@
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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
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;
@@ -42,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;
@@ -64,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;
@@ -95,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;
@@ -201,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(
@@ -210,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)
@@ -253,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();
}
@@ -261,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();
@@ -270,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) {
@@ -301,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);
@@ -321,29 +484,55 @@ public class UnderlyingNetworkControllerTest {
.unregisterNetworkCallback(any(UnderlyingNetworkListener.class));
}
private static UnderlyingNetworkRecord getTestNetworkRecord(
Network network,
NetworkCapabilities networkCapabilities,
LinkProperties linkProperties,
boolean isBlocked) {
return new UnderlyingNetworkRecord(
network,
networkCapabilities,
linkProperties,
isBlocked,
false /* isSelected */,
0 /* priorityClass */);
}
@Test
public void testUnderlyingNetworkRecordEquals() {
UnderlyingNetworkRecord recordA =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mNetwork,
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
UnderlyingNetworkRecord recordB =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mNetwork,
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
UnderlyingNetworkRecord recordC =
new UnderlyingNetworkRecord(
mNetwork,
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */,
true /* isSelected */,
-1 /* priorityClass */);
UnderlyingNetworkRecord recordD =
getTestNetworkRecord(
mNetwork,
UPDATED_NETWORK_CAPABILITIES,
UPDATED_LINK_PROPERTIES,
false /* isBlocked */);
assertEquals(recordA, recordB);
assertNotEquals(recordA, recordC);
assertEquals(recordA, recordC);
assertNotEquals(recordA, recordD);
assertTrue(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordB));
assertFalse(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordC));
}
@Test
@@ -366,6 +555,10 @@ public class UnderlyingNetworkControllerTest {
.build();
}
private void verifyOnSelectedUnderlyingNetworkChanged(UnderlyingNetworkRecord expectedRecord) {
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback(
NetworkCapabilities networkCapabilities) {
verify(mConnectivityManager)
@@ -384,12 +577,12 @@ public class UnderlyingNetworkControllerTest {
cb.onBlockedStatusChanged(mNetwork, false /* isFalse */);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
return cb;
}
@@ -402,12 +595,12 @@ public class UnderlyingNetworkControllerTest {
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -417,12 +610,12 @@ public class UnderlyingNetworkControllerTest {
cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mNetwork,
buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
UPDATED_LINK_PROPERTIES,
false /* isBlocked */);
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -434,18 +627,16 @@ public class UnderlyingNetworkControllerTest {
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
verify(mNetworkControllerCb, times(1))
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
verify(mNetworkControllerCb, times(1))
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -458,18 +649,16 @@ public class UnderlyingNetworkControllerTest {
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
verify(mNetworkControllerCb, times(1))
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
verify(mNetworkControllerCb, times(1))
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -478,13 +667,7 @@ public class UnderlyingNetworkControllerTest {
cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
mNetwork,
buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
INITIAL_LINK_PROPERTIES,
true /* isBlocked */);
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
verifyOnSelectedUnderlyingNetworkChanged(null);
}
@Test
@@ -520,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));
}
}