Merge "Calculate priority based on caller configurations" am: 36a25527b4
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1906130
Change-Id: I3817a344247104eb4056e949d09a123662fb6b65
diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java
index 6b33e4f..50a6bfc 100644
--- a/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java
+++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java
@@ -29,6 +29,7 @@
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 @@
&& 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<>();
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index de4ada2..31e38c0 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -160,7 +160,9 @@
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 {
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java
index 82f6ae7..551f757 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java
@@ -21,8 +21,10 @@
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 @@
/** @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 @@
&& 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() {
diff --git a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java
index fc7e7e2..2ba9169 100644
--- a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java
+++ b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java
@@ -22,6 +22,7 @@
import android.os.PersistableBundle;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import java.util.Objects;
@@ -81,6 +82,12 @@
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() {
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 584530c..8b80b4a 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -687,6 +687,7 @@
mUnderlyingNetworkController =
mDeps.newUnderlyingNetworkController(
mVcnContext,
+ mConnectionConfig,
subscriptionGroup,
mLastSnapshot,
mUnderlyingNetworkControllerCallback);
@@ -2376,11 +2377,12 @@
/** 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. */
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
index bea8ae9..7b26fe0 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
@@ -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 @@
*/
@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 @@
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 @@
// 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 @@
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);
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index 071c7a6..cd124ee 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -32,6 +32,8 @@
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 @@
@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 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 @@
TreeSet<UnderlyingNetworkRecord> sorted =
new TreeSet<>(
UnderlyingNetworkRecord.getComparator(
+ mVcnContext,
+ mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
mSubscriptionGroup,
mLastSnapshot,
mCurrentRecord,
@@ -495,12 +498,31 @@
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();
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
index 65c69de..27ba854 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
@@ -21,6 +21,7 @@
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.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 @@
}
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 @@
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);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 8a0af2d..5628321 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -179,7 +179,7 @@
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());
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
new file mode 100644
index 0000000..2e1aab6
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -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);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
index c954cb8..fad9669 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
@@ -42,6 +42,7 @@
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 @@
mUnderlyingNetworkController =
new UnderlyingNetworkController(
- mVcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb);
+ mVcnContext,
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mNetworkControllerCb);
}
private void resetVcnContext() {
@@ -153,7 +158,8 @@
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 @@
true /* isInTestMode */);
new UnderlyingNetworkController(
- vcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb);
+ vcnContext,
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mNetworkControllerCb);
verify(cm)
.registerNetworkCallback(
@@ -345,6 +355,17 @@
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 @@
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 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 @@
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 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 @@
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 @@
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 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 @@
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());