Calculate priority based on caller configurations
Update NetworkPriorityClassifier to calculate priority according to the VcnUnderlyingNetworkPriority list configured in VcnGatewayConnectionConfig Bug: 206044122 Test: atest FrameworksVcnTests(new) Test: atest CtsVcnTestCses Change-Id: I55afa916af44db655a568aae2488877f2c177d59
This commit is contained in:
@@ -29,6 +29,7 @@ import android.telephony.TelephonyManager;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.vcn.util.PersistableBundleUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -200,6 +201,15 @@ public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetwork
|
||||
&& mRequireOpportunistic == rhs.mRequireOpportunistic;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
void dumpTransportSpecificFields(IndentingPrintWriter pw) {
|
||||
pw.println("mAllowedNetworkPlmnIds: " + mAllowedNetworkPlmnIds.toString());
|
||||
pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds.toString());
|
||||
pw.println("mAllowRoaming: " + mAllowRoaming);
|
||||
pw.println("mRequireOpportunistic: " + mRequireOpportunistic);
|
||||
}
|
||||
|
||||
/** This class is used to incrementally build WifiNetworkPriority objects. */
|
||||
public static class Builder extends VcnUnderlyingNetworkPriority.Builder<Builder> {
|
||||
@NonNull private final Set<String> mAllowedNetworkPlmnIds = new ArraySet<>();
|
||||
|
||||
@@ -160,7 +160,9 @@ public final class VcnGatewayConnectionConfig {
|
||||
TimeUnit.MINUTES.toMillis(15)
|
||||
};
|
||||
|
||||
private static final LinkedHashSet<VcnUnderlyingNetworkPriority>
|
||||
/** @hide */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static final LinkedHashSet<VcnUnderlyingNetworkPriority>
|
||||
DEFAULT_UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet<>();
|
||||
|
||||
static {
|
||||
|
||||
@@ -21,8 +21,10 @@ import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.PersistableBundle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -37,10 +39,17 @@ public abstract class VcnUnderlyingNetworkPriority {
|
||||
/** @hide */
|
||||
protected static final int NETWORK_PRIORITY_TYPE_CELL = 2;
|
||||
|
||||
/** Denotes that network quality needs to be OK */
|
||||
public static final int NETWORK_QUALITY_OK = 10000;
|
||||
/** Denotes that any network quality is acceptable */
|
||||
public static final int NETWORK_QUALITY_ANY = Integer.MAX_VALUE;
|
||||
public static final int NETWORK_QUALITY_ANY = 0;
|
||||
/** Denotes that network quality needs to be OK */
|
||||
public static final int NETWORK_QUALITY_OK = 100000;
|
||||
|
||||
private static final SparseArray<String> NETWORK_QUALITY_TO_STRING_MAP = new SparseArray<>();
|
||||
|
||||
static {
|
||||
NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_ANY, "NETWORK_QUALITY_ANY");
|
||||
NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_OK, "NETWORK_QUALITY_OK");
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -125,6 +134,28 @@ public abstract class VcnUnderlyingNetworkPriority {
|
||||
&& mAllowMetered == rhs.mAllowMetered;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
abstract void dumpTransportSpecificFields(IndentingPrintWriter pw);
|
||||
|
||||
/**
|
||||
* Dumps the state of this record for logging and debugging purposes.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void dump(IndentingPrintWriter pw) {
|
||||
pw.println(this.getClass().getSimpleName() + ":");
|
||||
pw.increaseIndent();
|
||||
|
||||
pw.println(
|
||||
"mNetworkQuality: "
|
||||
+ NETWORK_QUALITY_TO_STRING_MAP.get(
|
||||
mNetworkQuality, "Invalid value " + mNetworkQuality));
|
||||
pw.println("mAllowMetered: " + mAllowMetered);
|
||||
dumpTransportSpecificFields(pw);
|
||||
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
/** Retrieve the required network quality. */
|
||||
@NetworkQuality
|
||||
public int getNetworkQuality() {
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -81,6 +82,12 @@ public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetwork
|
||||
return mSsid == rhs.mSsid;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
void dumpTransportSpecificFields(IndentingPrintWriter pw) {
|
||||
pw.println("mSsid: " + mSsid);
|
||||
}
|
||||
|
||||
/** Retrieve the required SSID, or {@code null} if there is no requirement on SSID. */
|
||||
@Nullable
|
||||
public String getSsid() {
|
||||
|
||||
@@ -686,6 +686,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
mUnderlyingNetworkController =
|
||||
mDeps.newUnderlyingNetworkController(
|
||||
mVcnContext,
|
||||
mConnectionConfig,
|
||||
subscriptionGroup,
|
||||
mLastSnapshot,
|
||||
mUnderlyingNetworkControllerCallback);
|
||||
@@ -2364,11 +2365,12 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
/** Builds a new UnderlyingNetworkController. */
|
||||
public UnderlyingNetworkController newUnderlyingNetworkController(
|
||||
VcnContext vcnContext,
|
||||
VcnGatewayConnectionConfig connectionConfig,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
UnderlyingNetworkControllerCallback callback) {
|
||||
return new UnderlyingNetworkController(
|
||||
vcnContext, subscriptionGroup, snapshot, callback);
|
||||
vcnContext, connectionConfig, subscriptionGroup, snapshot, callback);
|
||||
}
|
||||
|
||||
/** Builds a new IkeSession. */
|
||||
|
||||
@@ -15,25 +15,36 @@
|
||||
*/
|
||||
package com.android.server.vcn.routeselection;
|
||||
|
||||
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;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||
import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY;
|
||||
import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
|
||||
|
||||
import static com.android.server.VcnManagementService.LOCAL_LOG;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.VcnCellUnderlyingNetworkPriority;
|
||||
import android.net.vcn.VcnManager;
|
||||
import android.net.vcn.VcnUnderlyingNetworkPriority;
|
||||
import android.net.vcn.VcnWifiUnderlyingNetworkPriority;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.PersistableBundle;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.VcnContext;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** @hide */
|
||||
@@ -56,52 +67,20 @@ class NetworkPriorityClassifier {
|
||||
*/
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;
|
||||
/** Priority for any cellular network for which the subscription is listed as opportunistic */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0;
|
||||
/** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int PRIORITY_WIFI_IN_USE = 1;
|
||||
/** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int PRIORITY_WIFI_PROSPECTIVE = 2;
|
||||
/** Priority for any standard macro cellular network */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int PRIORITY_MACRO_CELLULAR = 3;
|
||||
|
||||
/** Priority for any other networks (including unvalidated, etc) */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int PRIORITY_ANY = Integer.MAX_VALUE;
|
||||
|
||||
private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
|
||||
|
||||
static {
|
||||
PRIORITY_TO_STRING_MAP.put(
|
||||
PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
|
||||
PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
|
||||
PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
|
||||
PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
|
||||
PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives networks a priority class, based on the following priorities:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Opportunistic cellular
|
||||
* <li>Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT
|
||||
* <li>Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT
|
||||
* <li>Macro cellular
|
||||
* <li>Any others
|
||||
* </ol>
|
||||
*/
|
||||
static int calculatePriorityClass(
|
||||
/** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */
|
||||
public static int calculatePriorityClass(
|
||||
VcnContext vcnContext,
|
||||
UnderlyingNetworkRecord networkRecord,
|
||||
LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
UnderlyingNetworkRecord currentlySelected,
|
||||
PersistableBundle carrierConfig) {
|
||||
final NetworkCapabilities caps = networkRecord.networkCapabilities;
|
||||
|
||||
// mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
|
||||
|
||||
if (networkRecord.isBlocked) {
|
||||
@@ -109,8 +88,167 @@ class NetworkPriorityClassifier {
|
||||
return PRIORITY_ANY;
|
||||
}
|
||||
|
||||
if (caps.hasTransport(TRANSPORT_CELLULAR)
|
||||
&& isOpportunistic(snapshot, caps.getSubscriptionIds())) {
|
||||
if (snapshot == null) {
|
||||
logWtf("Got null snapshot");
|
||||
return PRIORITY_ANY;
|
||||
}
|
||||
|
||||
int priorityIndex = 0;
|
||||
for (VcnUnderlyingNetworkPriority nwPriority : underlyingNetworkPriorities) {
|
||||
if (checkMatchesPriorityRule(
|
||||
vcnContext,
|
||||
nwPriority,
|
||||
networkRecord,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
currentlySelected,
|
||||
carrierConfig)) {
|
||||
return priorityIndex;
|
||||
}
|
||||
priorityIndex++;
|
||||
}
|
||||
return PRIORITY_ANY;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static boolean checkMatchesPriorityRule(
|
||||
VcnContext vcnContext,
|
||||
VcnUnderlyingNetworkPriority networkPriority,
|
||||
UnderlyingNetworkRecord networkRecord,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
UnderlyingNetworkRecord currentlySelected,
|
||||
PersistableBundle carrierConfig) {
|
||||
// TODO: Check Network Quality reported by metric monitors/probers.
|
||||
|
||||
final NetworkCapabilities caps = networkRecord.networkCapabilities;
|
||||
if (!networkPriority.allowMetered() && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (networkPriority instanceof VcnWifiUnderlyingNetworkPriority) {
|
||||
return checkMatchesWifiPriorityRule(
|
||||
(VcnWifiUnderlyingNetworkPriority) networkPriority,
|
||||
networkRecord,
|
||||
currentlySelected,
|
||||
carrierConfig);
|
||||
}
|
||||
|
||||
if (networkPriority instanceof VcnCellUnderlyingNetworkPriority) {
|
||||
return checkMatchesCellPriorityRule(
|
||||
vcnContext,
|
||||
(VcnCellUnderlyingNetworkPriority) networkPriority,
|
||||
networkRecord,
|
||||
subscriptionGroup,
|
||||
snapshot);
|
||||
}
|
||||
|
||||
logWtf(
|
||||
"Got unknown VcnUnderlyingNetworkPriority class: "
|
||||
+ networkPriority.getClass().getSimpleName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static boolean checkMatchesWifiPriorityRule(
|
||||
VcnWifiUnderlyingNetworkPriority networkPriority,
|
||||
UnderlyingNetworkRecord networkRecord,
|
||||
UnderlyingNetworkRecord currentlySelected,
|
||||
PersistableBundle carrierConfig) {
|
||||
final NetworkCapabilities caps = networkRecord.networkCapabilities;
|
||||
|
||||
if (!caps.hasTransport(TRANSPORT_WIFI)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Move the Network Quality check to the network metric monitor framework.
|
||||
if (networkPriority.getNetworkQuality()
|
||||
> getWifiQuality(networkRecord, currentlySelected, carrierConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (networkPriority.getSsid() != null && networkPriority.getSsid() != caps.getSsid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int getWifiQuality(
|
||||
UnderlyingNetworkRecord networkRecord,
|
||||
UnderlyingNetworkRecord currentlySelected,
|
||||
PersistableBundle carrierConfig) {
|
||||
final NetworkCapabilities caps = networkRecord.networkCapabilities;
|
||||
final boolean isSelectedNetwork =
|
||||
currentlySelected != null
|
||||
&& networkRecord.network.equals(currentlySelected.network);
|
||||
|
||||
if (isSelectedNetwork
|
||||
&& caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) {
|
||||
return NETWORK_QUALITY_OK;
|
||||
}
|
||||
|
||||
if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) {
|
||||
return NETWORK_QUALITY_OK;
|
||||
}
|
||||
|
||||
return NETWORK_QUALITY_ANY;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static boolean checkMatchesCellPriorityRule(
|
||||
VcnContext vcnContext,
|
||||
VcnCellUnderlyingNetworkPriority networkPriority,
|
||||
UnderlyingNetworkRecord networkRecord,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot) {
|
||||
final NetworkCapabilities caps = networkRecord.networkCapabilities;
|
||||
|
||||
if (!caps.hasTransport(TRANSPORT_CELLULAR)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
|
||||
((TelephonyNetworkSpecifier) caps.getNetworkSpecifier());
|
||||
if (telephonyNetworkSpecifier == null) {
|
||||
logWtf("Got null NetworkSpecifier");
|
||||
return false;
|
||||
}
|
||||
|
||||
final int subId = telephonyNetworkSpecifier.getSubscriptionId();
|
||||
final TelephonyManager subIdSpecificTelephonyMgr =
|
||||
vcnContext
|
||||
.getContext()
|
||||
.getSystemService(TelephonyManager.class)
|
||||
.createForSubscriptionId(subId);
|
||||
|
||||
if (!networkPriority.getAllowedPlmnIds().isEmpty()) {
|
||||
final String plmnId = subIdSpecificTelephonyMgr.getNetworkOperator();
|
||||
if (!networkPriority.getAllowedPlmnIds().contains(plmnId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!networkPriority.getAllowedSpecificCarrierIds().isEmpty()) {
|
||||
final int carrierId = subIdSpecificTelephonyMgr.getSimSpecificCarrierId();
|
||||
if (!networkPriority.getAllowedSpecificCarrierIds().contains(carrierId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!networkPriority.allowRoaming() && !caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (networkPriority.requireOpportunistic()) {
|
||||
if (!isOpportunistic(snapshot, caps.getSubscriptionIds())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this carrier is the active data provider, ensure that opportunistic is only
|
||||
// ever prioritized if it is also the active data subscription. This ensures that
|
||||
// if an opportunistic subscription is still in the process of being switched to,
|
||||
@@ -121,36 +259,15 @@ class NetworkPriorityClassifier {
|
||||
// Allow the following two cases:
|
||||
// 1. Active subId is NOT in the group that this VCN is supporting
|
||||
// 2. This opportunistic subscription is for the active subId
|
||||
if (!snapshot.getAllSubIdsInGroup(subscriptionGroup)
|
||||
if (snapshot.getAllSubIdsInGroup(subscriptionGroup)
|
||||
.contains(SubscriptionManager.getActiveDataSubscriptionId())
|
||||
|| caps.getSubscriptionIds()
|
||||
&& !caps.getSubscriptionIds()
|
||||
.contains(SubscriptionManager.getActiveDataSubscriptionId())) {
|
||||
return PRIORITY_OPPORTUNISTIC_CELLULAR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (caps.hasTransport(TRANSPORT_WIFI)) {
|
||||
if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)
|
||||
&& currentlySelected != null
|
||||
&& networkRecord.network.equals(currentlySelected.network)) {
|
||||
return PRIORITY_WIFI_IN_USE;
|
||||
}
|
||||
|
||||
if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) {
|
||||
return PRIORITY_WIFI_PROSPECTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might
|
||||
// be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be
|
||||
// the case if the Default Data SubId does not support certain services (eg voice
|
||||
// calling)
|
||||
if (caps.hasTransport(TRANSPORT_CELLULAR)
|
||||
&& !isOpportunistic(snapshot, caps.getSubscriptionIds())) {
|
||||
return PRIORITY_MACRO_CELLULAR;
|
||||
}
|
||||
|
||||
return PRIORITY_ANY;
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean isOpportunistic(
|
||||
@@ -185,10 +302,6 @@ class NetworkPriorityClassifier {
|
||||
return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
|
||||
}
|
||||
|
||||
static String priorityClassToString(int priorityClass) {
|
||||
return PRIORITY_TO_STRING_MAP.get(priorityClass, "unknown");
|
||||
}
|
||||
|
||||
private static void logWtf(String msg) {
|
||||
Slog.wtf(TAG, msg);
|
||||
LOCAL_LOG.log(TAG + " WTF: " + msg);
|
||||
|
||||
@@ -32,6 +32,8 @@ import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
||||
import android.net.vcn.VcnUnderlyingNetworkPriority;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.ParcelUuid;
|
||||
@@ -68,6 +70,7 @@ public class UnderlyingNetworkController {
|
||||
@NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName();
|
||||
|
||||
@NonNull private final VcnContext mVcnContext;
|
||||
@NonNull private final VcnGatewayConnectionConfig mConnectionConfig;
|
||||
@NonNull private final ParcelUuid mSubscriptionGroup;
|
||||
@NonNull private final UnderlyingNetworkControllerCallback mCb;
|
||||
@NonNull private final Dependencies mDeps;
|
||||
@@ -91,24 +94,22 @@ public class UnderlyingNetworkController {
|
||||
|
||||
public UnderlyingNetworkController(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull UnderlyingNetworkControllerCallback cb) {
|
||||
this(
|
||||
vcnContext,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
cb,
|
||||
new Dependencies());
|
||||
this(vcnContext, connectionConfig, subscriptionGroup, snapshot, cb, new Dependencies());
|
||||
}
|
||||
|
||||
private UnderlyingNetworkController(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull UnderlyingNetworkControllerCallback cb,
|
||||
@NonNull Dependencies deps) {
|
||||
mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
|
||||
mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
|
||||
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
|
||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
mCb = Objects.requireNonNull(cb, "Missing cb");
|
||||
@@ -399,6 +400,8 @@ public class UnderlyingNetworkController {
|
||||
TreeSet<UnderlyingNetworkRecord> sorted =
|
||||
new TreeSet<>(
|
||||
UnderlyingNetworkRecord.getComparator(
|
||||
mVcnContext,
|
||||
mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
|
||||
mSubscriptionGroup,
|
||||
mLastSnapshot,
|
||||
mCurrentRecord,
|
||||
@@ -495,12 +498,31 @@ public class UnderlyingNetworkController {
|
||||
pw.println(
|
||||
"Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network));
|
||||
|
||||
pw.println("VcnUnderlyingNetworkPriority list:");
|
||||
pw.increaseIndent();
|
||||
int index = 0;
|
||||
for (VcnUnderlyingNetworkPriority priority :
|
||||
mConnectionConfig.getVcnUnderlyingNetworkPriorities()) {
|
||||
pw.println("Priority index: " + index);
|
||||
priority.dump(pw);
|
||||
index++;
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
pw.println();
|
||||
|
||||
pw.println("Underlying networks:");
|
||||
pw.increaseIndent();
|
||||
if (mRouteSelectionCallback != null) {
|
||||
for (UnderlyingNetworkRecord record :
|
||||
mRouteSelectionCallback.getSortedUnderlyingNetworks()) {
|
||||
record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig);
|
||||
record.dump(
|
||||
mVcnContext,
|
||||
pw,
|
||||
mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
|
||||
mSubscriptionGroup,
|
||||
mLastSnapshot,
|
||||
mCurrentRecord,
|
||||
mCarrierConfig);
|
||||
}
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.vcn.VcnUnderlyingNetworkPriority;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
@@ -28,8 +29,10 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.VcnContext;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -73,22 +76,64 @@ public class UnderlyingNetworkRecord {
|
||||
}
|
||||
|
||||
static Comparator<UnderlyingNetworkRecord> getComparator(
|
||||
VcnContext vcnContext,
|
||||
LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
UnderlyingNetworkRecord currentlySelected,
|
||||
PersistableBundle carrierConfig) {
|
||||
return (left, right) -> {
|
||||
return Integer.compare(
|
||||
final int leftIndex =
|
||||
NetworkPriorityClassifier.calculatePriorityClass(
|
||||
left, subscriptionGroup, snapshot, currentlySelected, carrierConfig),
|
||||
vcnContext,
|
||||
left,
|
||||
underlyingNetworkPriorities,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
currentlySelected,
|
||||
carrierConfig);
|
||||
final int rightIndex =
|
||||
NetworkPriorityClassifier.calculatePriorityClass(
|
||||
right, subscriptionGroup, snapshot, currentlySelected, carrierConfig));
|
||||
vcnContext,
|
||||
right,
|
||||
underlyingNetworkPriorities,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
currentlySelected,
|
||||
carrierConfig);
|
||||
|
||||
// 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)) {
|
||||
return -1;
|
||||
}
|
||||
if (isSelected(left, currentlySelected)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return Integer.compare(leftIndex, rightIndex);
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isSelected(
|
||||
UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) {
|
||||
if (currentlySelected == null) {
|
||||
return false;
|
||||
}
|
||||
if (currentlySelected.network == recordToCheck.network) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Dumps the state of this record for logging and debugging purposes. */
|
||||
void dump(
|
||||
VcnContext vcnContext,
|
||||
IndentingPrintWriter pw,
|
||||
LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
UnderlyingNetworkRecord currentlySelected,
|
||||
@@ -96,15 +141,17 @@ public class UnderlyingNetworkRecord {
|
||||
pw.println("UnderlyingNetworkRecord:");
|
||||
pw.increaseIndent();
|
||||
|
||||
final int priorityClass =
|
||||
final int priorityIndex =
|
||||
NetworkPriorityClassifier.calculatePriorityClass(
|
||||
this, subscriptionGroup, snapshot, currentlySelected, carrierConfig);
|
||||
pw.println(
|
||||
"Priority class: "
|
||||
+ NetworkPriorityClassifier.priorityClassToString(priorityClass)
|
||||
+ " ("
|
||||
+ priorityClass
|
||||
+ ")");
|
||||
vcnContext,
|
||||
this,
|
||||
underlyingNetworkPriorities,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
currentlySelected,
|
||||
carrierConfig);
|
||||
|
||||
pw.println("Priority index:" + priorityIndex);
|
||||
pw.println("mNetwork: " + network);
|
||||
pw.println("mNetworkCapabilities: " + networkCapabilities);
|
||||
pw.println("mLinkProperties: " + linkProperties);
|
||||
|
||||
@@ -179,7 +179,7 @@ public class VcnGatewayConnectionTestBase {
|
||||
|
||||
doReturn(mUnderlyingNetworkController)
|
||||
.when(mDeps)
|
||||
.newUnderlyingNetworkController(any(), any(), any(), any());
|
||||
.newUnderlyingNetworkController(any(), any(), any(), any(), any());
|
||||
doReturn(mWakeLock)
|
||||
.when(mDeps)
|
||||
.newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vcn.routeselection;
|
||||
|
||||
import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
|
||||
|
||||
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.checkMatchesCellPriorityRule;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule;
|
||||
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule;
|
||||
import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.VcnCellUnderlyingNetworkPriority;
|
||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
||||
import android.net.vcn.VcnManager;
|
||||
import android.net.vcn.VcnWifiUnderlyingNetworkPriority;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.test.TestLooper;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.VcnContext;
|
||||
import com.android.server.vcn.VcnNetworkProvider;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class NetworkPriorityClassifierTest {
|
||||
private static final String SSID = "TestWifi";
|
||||
private static final String SSID_OTHER = "TestWifiOther";
|
||||
private static final String PLMN_ID = "123456";
|
||||
private static final String PLMN_ID_OTHER = "234567";
|
||||
|
||||
private static final int SUB_ID = 1;
|
||||
private static final int WIFI_RSSI = -60;
|
||||
private static final int WIFI_RSSI_HIGH = -50;
|
||||
private static final int WIFI_RSSI_LOW = -80;
|
||||
private static final int CARRIER_ID = 1;
|
||||
private static final int CARRIER_ID_OTHER = 2;
|
||||
|
||||
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
|
||||
|
||||
private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.setSignalStrength(WIFI_RSSI)
|
||||
.setSsid(SSID)
|
||||
.build();
|
||||
|
||||
private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER =
|
||||
new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build();
|
||||
private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setSubscriptionIds(Set.of(SUB_ID))
|
||||
.setNetworkSpecifier(TEL_NETWORK_SPECIFIER)
|
||||
.build();
|
||||
|
||||
private static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface");
|
||||
|
||||
@Mock private Network mNetwork;
|
||||
@Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
||||
@Mock private TelephonyManager mTelephonyManager;
|
||||
|
||||
private TestLooper mTestLooper;
|
||||
private VcnContext mVcnContext;
|
||||
private UnderlyingNetworkRecord mWifiNetworkRecord;
|
||||
private UnderlyingNetworkRecord mCellNetworkRecord;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
final Context mockContext = mock(Context.class);
|
||||
mTestLooper = new TestLooper();
|
||||
mVcnContext =
|
||||
spy(
|
||||
new VcnContext(
|
||||
mockContext,
|
||||
mTestLooper.getLooper(),
|
||||
mock(VcnNetworkProvider.class),
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchWithoutNotMeteredBit() {
|
||||
final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority =
|
||||
new VcnWifiUnderlyingNetworkPriority.Builder()
|
||||
.setNetworkQuality(NETWORK_QUALITY_OK)
|
||||
.setAllowMetered(false /* allowMetered */)
|
||||
.build();
|
||||
|
||||
assertFalse(
|
||||
checkMatchesPriorityRule(
|
||||
mVcnContext,
|
||||
wifiNetworkPriority,
|
||||
mWifiNetworkRecord,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
null /* currentlySelecetd */,
|
||||
null /* carrierConfig */));
|
||||
}
|
||||
|
||||
private void verifyMatchWifi(
|
||||
boolean isSelectedNetwork, PersistableBundle carrierConfig, boolean expectMatch) {
|
||||
final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority =
|
||||
new VcnWifiUnderlyingNetworkPriority.Builder()
|
||||
.setNetworkQuality(NETWORK_QUALITY_OK)
|
||||
.setAllowMetered(true /* allowMetered */)
|
||||
.build();
|
||||
final UnderlyingNetworkRecord selectedNetworkRecord =
|
||||
isSelectedNetwork ? mWifiNetworkRecord : null;
|
||||
assertEquals(
|
||||
expectMatch,
|
||||
checkMatchesWifiPriorityRule(
|
||||
wifiNetworkPriority,
|
||||
mWifiNetworkRecord,
|
||||
selectedNetworkRecord,
|
||||
carrierConfig));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchSelectedWifi() {
|
||||
verifyMatchWifi(
|
||||
true /* isSelectedNetwork */, null /* carrierConfig */, true /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchSelectedWifiBelowRssiThreshold() {
|
||||
final PersistableBundle carrierConfig = new PersistableBundle();
|
||||
carrierConfig.putInt(
|
||||
VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH);
|
||||
carrierConfig.putInt(
|
||||
VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH);
|
||||
|
||||
verifyMatchWifi(true /* isSelectedNetwork */, carrierConfig, false /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchUnselectedWifi() {
|
||||
verifyMatchWifi(
|
||||
false /* isSelectedNetwork */, null /* carrierConfig */, true /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchUnselectedWifiBelowRssiThreshold() {
|
||||
final PersistableBundle carrierConfig = new PersistableBundle();
|
||||
carrierConfig.putInt(
|
||||
VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, WIFI_RSSI_HIGH);
|
||||
|
||||
verifyMatchWifi(false /* isSelectedNetwork */, carrierConfig, false /* expectMatch */);
|
||||
}
|
||||
|
||||
private void verifyMatchWifiWithSsid(boolean useMatchedSsid, boolean expectMatch) {
|
||||
final String nwPrioritySsid = useMatchedSsid ? SSID : SSID_OTHER;
|
||||
final VcnWifiUnderlyingNetworkPriority wifiNetworkPriority =
|
||||
new VcnWifiUnderlyingNetworkPriority.Builder()
|
||||
.setNetworkQuality(NETWORK_QUALITY_OK)
|
||||
.setAllowMetered(true /* allowMetered */)
|
||||
.setSsid(nwPrioritySsid)
|
||||
.build();
|
||||
|
||||
assertEquals(
|
||||
expectMatch,
|
||||
checkMatchesWifiPriorityRule(
|
||||
wifiNetworkPriority,
|
||||
mWifiNetworkRecord,
|
||||
null /* currentlySelecetd */,
|
||||
null /* carrierConfig */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchWifiWithSsid() {
|
||||
verifyMatchWifiWithSsid(true /* useMatchedSsid */, true /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchWifiFailWithWrongSsid() {
|
||||
verifyMatchWifiWithSsid(false /* useMatchedSsid */, false /* expectMatch */);
|
||||
}
|
||||
|
||||
private static VcnCellUnderlyingNetworkPriority.Builder getCellNetworkPriorityBuilder() {
|
||||
return new VcnCellUnderlyingNetworkPriority.Builder()
|
||||
.setNetworkQuality(NETWORK_QUALITY_OK)
|
||||
.setAllowMetered(true /* allowMetered */)
|
||||
.setAllowRoaming(true /* allowRoaming */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchMacroCell() {
|
||||
assertTrue(
|
||||
checkMatchesCellPriorityRule(
|
||||
mVcnContext,
|
||||
getCellNetworkPriorityBuilder().build(),
|
||||
mCellNetworkRecord,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchOpportunisticCell() {
|
||||
final VcnCellUnderlyingNetworkPriority opportunisticCellNetworkPriority =
|
||||
getCellNetworkPriorityBuilder()
|
||||
.setRequireOpportunistic(true /* requireOpportunistic */)
|
||||
.build();
|
||||
|
||||
when(mSubscriptionSnapshot.isOpportunistic(SUB_ID)).thenReturn(true);
|
||||
when(mSubscriptionSnapshot.getAllSubIdsInGroup(SUB_GROUP)).thenReturn(new ArraySet<>());
|
||||
|
||||
assertTrue(
|
||||
checkMatchesCellPriorityRule(
|
||||
mVcnContext,
|
||||
opportunisticCellNetworkPriority,
|
||||
mCellNetworkRecord,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot));
|
||||
}
|
||||
|
||||
private void verifyMatchMacroCellWithAllowedPlmnIds(
|
||||
boolean useMatchedPlmnId, boolean expectMatch) {
|
||||
final String networkPriorityPlmnId = useMatchedPlmnId ? PLMN_ID : PLMN_ID_OTHER;
|
||||
final VcnCellUnderlyingNetworkPriority networkPriority =
|
||||
getCellNetworkPriorityBuilder()
|
||||
.setAllowedPlmnIds(Set.of(networkPriorityPlmnId))
|
||||
.build();
|
||||
|
||||
assertEquals(
|
||||
expectMatch,
|
||||
checkMatchesCellPriorityRule(
|
||||
mVcnContext,
|
||||
networkPriority,
|
||||
mCellNetworkRecord,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchMacroCellWithAllowedPlmnIds() {
|
||||
verifyMatchMacroCellWithAllowedPlmnIds(true /* useMatchedPlmnId */, true /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchMacroCellFailWithDisallowedPlmnIds() {
|
||||
verifyMatchMacroCellWithAllowedPlmnIds(
|
||||
false /* useMatchedPlmnId */, false /* expectMatch */);
|
||||
}
|
||||
|
||||
private void verifyMatchMacroCellWithAllowedSpecificCarrierIds(
|
||||
boolean useMatchedCarrierId, boolean expectMatch) {
|
||||
final int networkPriorityCarrierId = useMatchedCarrierId ? CARRIER_ID : CARRIER_ID_OTHER;
|
||||
final VcnCellUnderlyingNetworkPriority networkPriority =
|
||||
getCellNetworkPriorityBuilder()
|
||||
.setAllowedSpecificCarrierIds(Set.of(networkPriorityCarrierId))
|
||||
.build();
|
||||
|
||||
assertEquals(
|
||||
expectMatch,
|
||||
checkMatchesCellPriorityRule(
|
||||
mVcnContext,
|
||||
networkPriority,
|
||||
mCellNetworkRecord,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchMacroCellWithAllowedSpecificCarrierIds() {
|
||||
verifyMatchMacroCellWithAllowedSpecificCarrierIds(
|
||||
true /* useMatchedCarrierId */, true /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchMacroCellFailWithDisallowedSpecificCarrierIds() {
|
||||
verifyMatchMacroCellWithAllowedSpecificCarrierIds(
|
||||
false /* useMatchedCarrierId */, false /* expectMatch */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchWifiFailWithoutNotRoamingBit() {
|
||||
final VcnCellUnderlyingNetworkPriority networkPriority =
|
||||
getCellNetworkPriorityBuilder().setAllowRoaming(false /* allowRoaming */).build();
|
||||
|
||||
assertFalse(
|
||||
checkMatchesCellPriorityRule(
|
||||
mVcnContext,
|
||||
networkPriority,
|
||||
mCellNetworkRecord,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot));
|
||||
}
|
||||
|
||||
private void verifyCalculatePriorityClass(
|
||||
UnderlyingNetworkRecord networkRecord, int expectedIndex) {
|
||||
final int priorityIndex =
|
||||
calculatePriorityClass(
|
||||
mVcnContext,
|
||||
networkRecord,
|
||||
VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_PRIORITIES,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
null /* currentlySelected */,
|
||||
null /* carrierConfig */);
|
||||
|
||||
assertEquals(expectedIndex, priorityIndex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculatePriorityClass() throws Exception {
|
||||
verifyCalculatePriorityClass(mCellNetworkRecord, 2);
|
||||
}
|
||||
|
||||
@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 */);
|
||||
|
||||
verifyCalculatePriorityClass(wifiNetworkRecord, PRIORITY_ANY);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.VcnGatewayConnectionConfigTest;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
@@ -145,7 +146,11 @@ public class UnderlyingNetworkControllerTest {
|
||||
|
||||
mUnderlyingNetworkController =
|
||||
new UnderlyingNetworkController(
|
||||
mVcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb);
|
||||
mVcnContext,
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig(),
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
mNetworkControllerCb);
|
||||
}
|
||||
|
||||
private void resetVcnContext() {
|
||||
@@ -153,7 +158,8 @@ public class UnderlyingNetworkControllerTest {
|
||||
doNothing().when(mVcnContext).ensureRunningOnLooperThread();
|
||||
}
|
||||
|
||||
private static LinkProperties getLinkPropertiesWithName(String iface) {
|
||||
// Package private for use in NetworkPriorityClassifierTest
|
||||
static LinkProperties getLinkPropertiesWithName(String iface) {
|
||||
LinkProperties linkProperties = new LinkProperties();
|
||||
linkProperties.setInterfaceName(iface);
|
||||
return linkProperties;
|
||||
@@ -182,7 +188,11 @@ public class UnderlyingNetworkControllerTest {
|
||||
true /* isInTestMode */);
|
||||
|
||||
new UnderlyingNetworkController(
|
||||
vcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb);
|
||||
vcnContext,
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig(),
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
mNetworkControllerCb);
|
||||
|
||||
verify(cm)
|
||||
.registerNetworkCallback(
|
||||
@@ -345,6 +355,17 @@ public class UnderlyingNetworkControllerTest {
|
||||
return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES);
|
||||
}
|
||||
|
||||
private static NetworkCapabilities buildResponseNwCaps(
|
||||
NetworkCapabilities requestNetworkCaps, Set<Integer> netCapsSubIds) {
|
||||
final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
|
||||
new TelephonyNetworkSpecifier.Builder()
|
||||
.setSubscriptionId(netCapsSubIds.iterator().next())
|
||||
.build();
|
||||
return new NetworkCapabilities.Builder(requestNetworkCaps)
|
||||
.setNetworkSpecifier(telephonyNetworkSpecifier)
|
||||
.build();
|
||||
}
|
||||
|
||||
private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback(
|
||||
NetworkCapabilities networkCapabilities) {
|
||||
verify(mConnectivityManager)
|
||||
@@ -355,14 +376,17 @@ public class UnderlyingNetworkControllerTest {
|
||||
|
||||
UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue();
|
||||
cb.onAvailable(mNetwork);
|
||||
cb.onCapabilitiesChanged(mNetwork, networkCapabilities);
|
||||
|
||||
final NetworkCapabilities responseNetworkCaps =
|
||||
buildResponseNwCaps(networkCapabilities, INITIAL_SUB_IDS);
|
||||
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
|
||||
cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES);
|
||||
cb.onBlockedStatusChanged(mNetwork, false /* isFalse */);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
networkCapabilities,
|
||||
responseNetworkCaps,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
@@ -373,12 +397,14 @@ public class UnderlyingNetworkControllerTest {
|
||||
public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() {
|
||||
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
|
||||
final NetworkCapabilities responseNetworkCaps =
|
||||
buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS);
|
||||
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
UPDATED_NETWORK_CAPABILITIES,
|
||||
responseNetworkCaps,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
@@ -393,7 +419,7 @@ public class UnderlyingNetworkControllerTest {
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
|
||||
UPDATED_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
@@ -403,19 +429,21 @@ public class UnderlyingNetworkControllerTest {
|
||||
public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
|
||||
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
|
||||
final NetworkCapabilities responseNetworkCaps =
|
||||
buildResponseNwCaps(SUSPENDED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS);
|
||||
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
SUSPENDED_NETWORK_CAPABILITIES,
|
||||
responseNetworkCaps,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkControllerCb, times(1))
|
||||
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
|
||||
// change.
|
||||
cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
|
||||
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
|
||||
verify(mNetworkControllerCb, times(1))
|
||||
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
}
|
||||
@@ -425,19 +453,21 @@ public class UnderlyingNetworkControllerTest {
|
||||
UnderlyingNetworkListener cb =
|
||||
verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
|
||||
|
||||
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
||||
final NetworkCapabilities responseNetworkCaps =
|
||||
buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS);
|
||||
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
responseNetworkCaps,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkControllerCb, times(1))
|
||||
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
|
||||
// change.
|
||||
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
||||
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
|
||||
verify(mNetworkControllerCb, times(1))
|
||||
.onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
}
|
||||
@@ -451,7 +481,7 @@ public class UnderlyingNetworkControllerTest {
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
true /* isBlocked */);
|
||||
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
@@ -470,7 +500,8 @@ public class UnderlyingNetworkControllerTest {
|
||||
public void testRecordTrackerCallbackIgnoresDuplicateRecord() {
|
||||
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
||||
cb.onCapabilitiesChanged(
|
||||
mNetwork, buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS));
|
||||
|
||||
// Verify no more calls to the UnderlyingNetworkControllerCallback when the
|
||||
// UnderlyingNetworkRecord does not actually change
|
||||
@@ -482,7 +513,8 @@ public class UnderlyingNetworkControllerTest {
|
||||
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
mUnderlyingNetworkController.teardown();
|
||||
|
||||
cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
|
||||
cb.onCapabilitiesChanged(
|
||||
mNetwork, buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, INITIAL_SUB_IDS));
|
||||
|
||||
// Verify that the only call was during onAvailable()
|
||||
verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
|
||||
|
||||
Reference in New Issue
Block a user