diff options
| author | 2021-05-10 10:15:15 -0700 | |
|---|---|---|
| committer | 2021-05-13 18:57:05 -0700 | |
| commit | 9028cac4fe39206ce6162ea3662a66b329563961 (patch) | |
| tree | a51e0ddb43cb23860013ed37f1568639fbfa01c3 | |
| parent | 3b2decbb34e30736a9d6fa9d8d43a37a1db165d0 (diff) | |
Custom network selection
This change adds a basic prioritization framework in the VCN, and signal
strength thresholds for WiFi.
Bug: 188104094
Test: atest FrameworksVcnTests
Change-Id: Iee4e3dbecf1102ddc127a8c8daf08a00b6fccbbd
6 files changed, 521 insertions, 150 deletions
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 9d1c1ff898e7..390c3b9453c2 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -74,6 +74,36 @@ import java.util.concurrent.Executor; public class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + /** + * Key for WiFi entry RSSI thresholds + * + * <p>The VCN will only migrate to a Carrier WiFi network that has a signal strength greater + * than, or equal to this threshold. + * + * <p>WARNING: The VCN does not listen for changes to this key made after VCN startup. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY = + "vcn_network_selection_wifi_entry_rssi_threshold"; + + /** + * Key for WiFi entry RSSI thresholds + * + * <p>If the VCN's selected Carrier WiFi network has a signal strength less than this threshold, + * the VCN will attempt to migrate away from the Carrier WiFi network. + * + * <p>WARNING: The VCN does not listen for changes to this key made after VCN startup. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY = + "vcn_network_selection_wifi_exit_rssi_threshold"; + + // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz + private static final Map< VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder> REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java index 19fbdbd86099..5565ccb6cf7c 100644 --- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -145,7 +145,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { */ public void handleSubscriptionsChanged() { final Map<ParcelUuid, Set<String>> privilegedPackages = new HashMap<>(); - final Map<Integer, ParcelUuid> newSubIdToGroupMap = new HashMap<>(); + final Map<Integer, SubscriptionInfo> newSubIdToInfoMap = new HashMap<>(); final List<SubscriptionInfo> allSubs = mSubscriptionManager.getAllSubscriptionInfoList(); if (allSubs == null) { @@ -160,7 +160,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } // Build subId -> subGrp cache - newSubIdToGroupMap.put(subInfo.getSubscriptionId(), subInfo.getGroupUuid()); + newSubIdToInfoMap.put(subInfo.getSubscriptionId(), subInfo); // Update subscription groups that are both ready, and active. For a group to be // considered active, both of the following must be true: @@ -186,7 +186,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } final TelephonySubscriptionSnapshot newSnapshot = - new TelephonySubscriptionSnapshot(newSubIdToGroupMap, privilegedPackages); + new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages); // If snapshot was meaningfully updated, fire the callback if (!newSnapshot.equals(mCurrentSnapshot)) { @@ -245,7 +245,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */ public static class TelephonySubscriptionSnapshot { - private final Map<Integer, ParcelUuid> mSubIdToGroupMap; + private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap; private final Map<ParcelUuid, Set<String>> mPrivilegedPackages; public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT = @@ -253,12 +253,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @VisibleForTesting(visibility = Visibility.PRIVATE) TelephonySubscriptionSnapshot( - @NonNull Map<Integer, ParcelUuid> subIdToGroupMap, + @NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap, @NonNull Map<ParcelUuid, Set<String>> privilegedPackages) { - Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null"); + Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null"); Objects.requireNonNull(privilegedPackages, "privilegedPackages was null"); - mSubIdToGroupMap = Collections.unmodifiableMap(subIdToGroupMap); + mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap); final Map<ParcelUuid, Set<String>> unmodifiableInnerSets = new ArrayMap<>(); for (Entry<ParcelUuid, Set<String>> entry : privilegedPackages.entrySet()) { @@ -285,7 +285,9 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { /** Returns the Subscription Group for a given subId. */ @Nullable public ParcelUuid getGroupForSubId(int subId) { - return mSubIdToGroupMap.get(subId); + return mSubIdToInfoMap.containsKey(subId) + ? mSubIdToInfoMap.get(subId).getGroupUuid() + : null; } /** @@ -295,8 +297,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { public Set<Integer> getAllSubIdsInGroup(ParcelUuid subGrp) { final Set<Integer> subIds = new ArraySet<>(); - for (Entry<Integer, ParcelUuid> entry : mSubIdToGroupMap.entrySet()) { - if (subGrp.equals(entry.getValue())) { + for (Entry<Integer, SubscriptionInfo> entry : mSubIdToInfoMap.entrySet()) { + if (subGrp.equals(entry.getValue().getGroupUuid())) { subIds.add(entry.getKey()); } } @@ -304,9 +306,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { return subIds; } + /** Checks if the requested subscription is opportunistic */ + @NonNull + public boolean isOpportunistic(int subId) { + return mSubIdToInfoMap.containsKey(subId) + ? mSubIdToInfoMap.get(subId).isOpportunistic() + : false; + } + @Override public int hashCode() { - return Objects.hash(mSubIdToGroupMap, mPrivilegedPackages); + return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages); } @Override @@ -317,7 +327,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj; - return mSubIdToGroupMap.equals(other.mSubIdToGroupMap) + return mSubIdToInfoMap.equals(other.mSubIdToInfoMap) && mPrivilegedPackages.equals(other.mPrivilegedPackages); } @@ -326,7 +336,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { pw.println("TelephonySubscriptionSnapshot:"); pw.increaseIndent(); - pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap); + pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap); pw.println("mPrivilegedPackages: " + mPrivilegedPackages); pw.decreaseIndent(); @@ -335,7 +345,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @Override public String toString() { return "TelephonySubscriptionSnapshot{ " - + "mSubIdToGroupMap=" + mSubIdToGroupMap + + "mSubIdToInfoMap=" + mSubIdToInfoMap + ", mPrivilegedPackages=" + mPrivilegedPackages + " }"; } diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java index 3bdeec0c1d8e..fb4c6236a9a0 100644 --- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -16,6 +16,10 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; + import android.annotation.NonNull; import android.annotation.Nullable; import android.net.ConnectivityManager; @@ -25,8 +29,16 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnManager; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -35,9 +47,13 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeSet; /** * Tracks a set of Networks underpinning a VcnGatewayConnection. @@ -51,6 +67,45 @@ import java.util.Set; public class UnderlyingNetworkTracker { @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName(); + /** + * Minimum signal strength for a WiFi network to be eligible for switching to + * + * <p>A network that satisfies this is eligible to become the selected underlying network with + * no additional conditions + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70; + + /** + * Minimum signal strength to continue using a WiFi network + * + * <p>A network that satisfies the conditions may ONLY continue to be used if it is already + * selected as the underlying network. A WiFi network satisfying this condition, but NOT the + * prospective-network RSSI threshold CANNOT be switched to. + */ + @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; + @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities; @@ -58,12 +113,17 @@ public class UnderlyingNetworkTracker { @NonNull private final Dependencies mDeps; @NonNull private final Handler mHandler; @NonNull private final ConnectivityManager mConnectivityManager; + @NonNull private final TelephonyCallback mActiveDataSubIdListener = + new VcnActiveDataSubscriptionIdListener(); @NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>(); @Nullable private NetworkCallback mWifiBringupCallback; - @Nullable private NetworkCallback mRouteSelectionCallback; + @Nullable private NetworkCallback mWifiEntryRssiThresholdCallback; + @Nullable private NetworkCallback mWifiExitRssiThresholdCallback; + @Nullable private UnderlyingNetworkListener mRouteSelectionCallback; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; + @Nullable private PersistableBundle mCarrierConfig; private boolean mIsQuitting = false; @Nullable private UnderlyingNetworkRecord mCurrentRecord; @@ -104,6 +164,30 @@ public class UnderlyingNetworkTracker { mHandler = new Handler(mVcnContext.getLooper()); mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); + mVcnContext + .getContext() + .getSystemService(TelephonyManager.class) + .registerTelephonyCallback(new HandlerExecutor(mHandler), mActiveDataSubIdListener); + + // TODO: Listen for changes in carrier config that affect this. + for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { + PersistableBundle config = + mVcnContext + .getContext() + .getSystemService(CarrierConfigManager.class) + .getConfigForSubId(subId); + + if (config != null) { + mCarrierConfig = config; + + // Attempt to use (any) non-opportunistic subscription. If this subscription is + // opportunistic, continue and try to find a non-opportunistic subscription, using + // the opportunistic ones as a last resort. + if (!isOpportunistic(mLastSnapshot, Collections.singleton(subId))) { + break; + } + } + } registerOrUpdateNetworkRequests(); } @@ -111,16 +195,30 @@ public class UnderlyingNetworkTracker { private void registerOrUpdateNetworkRequests() { NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback; NetworkCallback oldWifiCallback = mWifiBringupCallback; + NetworkCallback oldWifiEntryRssiThresholdCallback = mWifiEntryRssiThresholdCallback; + NetworkCallback oldWifiExitRssiThresholdCallback = mWifiExitRssiThresholdCallback; List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); // Register new callbacks. Make-before-break; always register new callbacks before removal // of old callbacks if (!mIsQuitting) { - mRouteSelectionCallback = new RouteSelectionCallback(); - mConnectivityManager.requestBackgroundNetwork( + mRouteSelectionCallback = new UnderlyingNetworkListener(); + mConnectivityManager.registerNetworkCallback( getRouteSelectionRequest(), mRouteSelectionCallback, mHandler); + mWifiEntryRssiThresholdCallback = new NetworkBringupCallback(); + mConnectivityManager.registerNetworkCallback( + getWifiEntryRssiThresholdNetworkRequest(), + mWifiEntryRssiThresholdCallback, + mHandler); + + mWifiExitRssiThresholdCallback = new NetworkBringupCallback(); + mConnectivityManager.registerNetworkCallback( + getWifiExitRssiThresholdNetworkRequest(), + mWifiExitRssiThresholdCallback, + mHandler); + mWifiBringupCallback = new NetworkBringupCallback(); mConnectivityManager.requestBackgroundNetwork( getWifiNetworkRequest(), mWifiBringupCallback, mHandler); @@ -135,6 +233,8 @@ public class UnderlyingNetworkTracker { } else { mRouteSelectionCallback = null; mWifiBringupCallback = null; + mWifiEntryRssiThresholdCallback = null; + mWifiExitRssiThresholdCallback = null; // mCellBringupCallbacks already cleared above. } @@ -145,6 +245,12 @@ public class UnderlyingNetworkTracker { if (oldWifiCallback != null) { mConnectivityManager.unregisterNetworkCallback(oldWifiCallback); } + if (oldWifiEntryRssiThresholdCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiEntryRssiThresholdCallback); + } + if (oldWifiExitRssiThresholdCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiExitRssiThresholdCallback); + } for (NetworkCallback cellBringupCallback : oldCellCallbacks) { mConnectivityManager.unregisterNetworkCallback(cellBringupCallback); } @@ -168,6 +274,8 @@ public class UnderlyingNetworkTracker { } return getBaseNetworkRequestBuilder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) .build(); } @@ -189,6 +297,38 @@ public class UnderlyingNetworkTracker { } /** + * Builds the WiFi entry threshold signal strength request + * + * <p>This request ensures that WiFi reports the crossing of the wifi entry RSSI threshold. + * Without this request, WiFi rate-limits, and reports signal strength changes at too slow a + * pace to effectively select a short-lived WiFi offload network. + */ + private NetworkRequest getWifiEntryRssiThresholdNetworkRequest() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + // Ensure wifi updates signal strengths when crossing this threshold. + .setSignalStrength(getWifiEntryRssiThreshold(mCarrierConfig)) + .build(); + } + + /** + * Builds the WiFi exit threshold signal strength request + * + * <p>This request ensures that WiFi reports the crossing of the wifi exit RSSI threshold. + * Without this request, WiFi rate-limits, and reports signal strength changes at too slow a + * pace to effectively select away from a failing WiFi network. + */ + private NetworkRequest getWifiExitRssiThresholdNetworkRequest() { + return getBaseNetworkRequestBuilder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) + // Ensure wifi updates signal strengths when crossing this threshold. + .setSignalStrength(getWifiExitRssiThreshold(mCarrierConfig)) + .build(); + } + + /** * Builds a Cellular bringup request for a given subId * * <p>This request is filed in order to ensure that the Telephony stack always has a @@ -233,10 +373,18 @@ public class UnderlyingNetworkTracker { * reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered * or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change. */ - public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) { - Objects.requireNonNull(snapshot, "Missing snapshot"); + public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot newSnapshot) { + Objects.requireNonNull(newSnapshot, "Missing newSnapshot"); + + final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; + mLastSnapshot = newSnapshot; - mLastSnapshot = snapshot; + // Only trigger re-registration if subIds in this group have changed + if (oldSnapshot + .getAllSubIdsInGroup(mSubscriptionGroup) + .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { + return; + } registerOrUpdateNetworkRequests(); } @@ -247,88 +395,43 @@ public class UnderlyingNetworkTracker { // Will unregister all existing callbacks, but not register new ones due to quitting flag. registerOrUpdateNetworkRequests(); - } - /** Returns whether the currently selected Network matches the given network. */ - private static boolean isSameNetwork( - @Nullable UnderlyingNetworkRecord.Builder recordInProgress, @NonNull Network network) { - return recordInProgress != null && recordInProgress.getNetwork().equals(network); + mVcnContext + .getContext() + .getSystemService(TelephonyManager.class) + .unregisterTelephonyCallback(mActiveDataSubIdListener); } - /** Notify the Callback if a full UnderlyingNetworkRecord exists. */ - private void maybeNotifyCallback() { - // Only forward this update if a complete record has been received - if (!mRecordInProgress.isValid()) { - return; - } + private void reevaluateNetworks() { + TreeSet<UnderlyingNetworkRecord> sorted = + new TreeSet<>( + UnderlyingNetworkRecord.getComparator( + mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig)); + sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks()); - // Only forward this update if the updated record differs form the current record - UnderlyingNetworkRecord updatedRecord = mRecordInProgress.build(); - if (!updatedRecord.equals(mCurrentRecord)) { - mCurrentRecord = updatedRecord; - - mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); - } - } - - private void handleNetworkAvailable(@NonNull Network network) { - mVcnContext.ensureRunningOnLooperThread(); - - mRecordInProgress = new UnderlyingNetworkRecord.Builder(network); - } - - private void handleNetworkLost(@NonNull Network network) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Non-underlying Network lost"); + UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); + if (Objects.equals(mCurrentRecord, candidate)) { return; } - mRecordInProgress = null; - mCurrentRecord = null; - mCb.onSelectedUnderlyingNetworkChanged(null /* underlyingNetworkRecord */); + mCurrentRecord = candidate; + mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); } - private void handleCapabilitiesChanged( - @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to NetworkCapabilities"); - return; + private static boolean isOpportunistic( + @NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) { + if (snapshot == null) { + Slog.wtf(TAG, "Got null snapshot"); + return false; } - mRecordInProgress.setNetworkCapabilities(networkCapabilities); - - maybeNotifyCallback(); - } - - private void handlePropertiesChanged( - @NonNull Network network, @NonNull LinkProperties linkProperties) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to LinkProperties"); - return; - } - - mRecordInProgress.setLinkProperties(linkProperties); - - maybeNotifyCallback(); - } - - private void handleNetworkBlocked(@NonNull Network network, boolean isBlocked) { - mVcnContext.ensureRunningOnLooperThread(); - - if (!isSameNetwork(mRecordInProgress, network)) { - Slog.wtf(TAG, "Invalid update to isBlocked"); - return; + for (int subId : subIds) { + if (snapshot.isOpportunistic(subId)) { + return true; + } } - mRecordInProgress.setIsBlocked(isBlocked); - - maybeNotifyCallback(); + return false; } /** @@ -347,36 +450,104 @@ public class UnderlyingNetworkTracker { * truth. */ @VisibleForTesting - class RouteSelectionCallback extends NetworkCallback { + class UnderlyingNetworkListener extends NetworkCallback { + private final Map<Network, UnderlyingNetworkRecord.Builder> + mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); + + private List<UnderlyingNetworkRecord> getUnderlyingNetworks() { + final List<UnderlyingNetworkRecord> records = new ArrayList<>(); + + for (UnderlyingNetworkRecord.Builder builder : + mUnderlyingNetworkRecordBuilders.values()) { + if (builder.isValid()) { + records.add(builder.build()); + } + } + + return records; + } + @Override public void onAvailable(@NonNull Network network) { - handleNetworkAvailable(network); + mUnderlyingNetworkRecordBuilders.put( + network, new UnderlyingNetworkRecord.Builder(network)); } @Override public void onLost(@NonNull Network network) { - handleNetworkLost(network); + mUnderlyingNetworkRecordBuilders.remove(network); + + reevaluateNetworks(); } @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return; - handleCapabilitiesChanged(network, networkCapabilities); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got capabilities change for unknown key: " + network); + return; + } + + builder.setNetworkCapabilities(networkCapabilities); + if (builder.isValid()) { + reevaluateNetworks(); + } } @Override public void onLinkPropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { - handlePropertiesChanged(network, linkProperties); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got link properties change for unknown key: " + network); + return; + } + + builder.setLinkProperties(linkProperties); + if (builder.isValid()) { + reevaluateNetworks(); + } } @Override public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) { - handleNetworkBlocked(network, isBlocked); + final UnderlyingNetworkRecord.Builder builder = + mUnderlyingNetworkRecordBuilders.get(network); + if (builder == null) { + Slog.wtf(TAG, "Got blocked status change for unknown key: " + network); + return; + } + + builder.setIsBlocked(isBlocked); + if (builder.isValid()) { + reevaluateNetworks(); + } } } + private static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, + WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT); + } + + return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; + } + + private static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + WIFI_EXIT_RSSI_THRESHOLD_DEFAULT); + } + + return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; + } + /** A record of a single underlying network, caching relevant fields. */ public static class UnderlyingNetworkRecord { @NonNull public final Network network; @@ -413,6 +584,89 @@ public class UnderlyingNetworkTracker { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } + /** + * 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> + */ + private int calculatePriorityClass( + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + final NetworkCapabilities caps = networkCapabilities; + + // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED + + if (isBlocked) { + Slog.wtf(TAG, "Network blocked for System Server: " + network); + return PRIORITY_ANY; + } + + if (caps.hasTransport(TRANSPORT_CELLULAR) + && isOpportunistic(snapshot, caps.getSubscriptionIds())) { + // 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, + // or switched away from, the VCN does not attempt to continue using it against the + // decision made at the telephony layer. Failure to do so may result in the modem + // switching back and forth. + // + // 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) + .contains(SubscriptionManager.getActiveDataSubscriptionId()) + || caps.getSubscriptionIds() + .contains(SubscriptionManager.getActiveDataSubscriptionId())) { + return PRIORITY_OPPORTUNISTIC_CELLULAR; + } + } + + if (caps.hasTransport(TRANSPORT_WIFI)) { + if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig) + && currentlySelected != null + && 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; + } + + private static Comparator<UnderlyingNetworkRecord> getComparator( + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + return (left, right) -> { + return Integer.compare( + left.calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig), + right.calculatePriorityClass( + subscriptionGroup, snapshot, currentlySelected, carrierConfig)); + }; + } + /** Dumps the state of this record for logging and debugging purposes. */ public void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkRecord:"); @@ -434,6 +688,8 @@ public class UnderlyingNetworkTracker { boolean mIsBlocked; boolean mWasIsBlockedSet; + @Nullable private UnderlyingNetworkRecord mCached; + private Builder(@NonNull Network network) { mNetwork = network; } @@ -445,6 +701,7 @@ public class UnderlyingNetworkTracker { private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { mNetworkCapabilities = networkCapabilities; + mCached = null; } @Nullable @@ -454,11 +711,13 @@ public class UnderlyingNetworkTracker { private void setLinkProperties(@NonNull LinkProperties linkProperties) { mLinkProperties = linkProperties; + mCached = null; } private void setIsBlocked(boolean isBlocked) { mIsBlocked = isBlocked; mWasIsBlockedSet = true; + mCached = null; } private boolean isValid() { @@ -466,12 +725,30 @@ public class UnderlyingNetworkTracker { } private UnderlyingNetworkRecord build() { - return new UnderlyingNetworkRecord( - mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + if (!isValid()) { + throw new IllegalArgumentException( + "Called build before UnderlyingNetworkRecord was valid"); + } + + if (mCached == null) { + mCached = + new UnderlyingNetworkRecord( + mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); + } + + return mCached; } } } + private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback + implements ActiveDataSubscriptionIdListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + reevaluateNetworks(); + } + } + /** Callbacks for being notified of the changes in, or to the selected underlying network. */ public interface UnderlyingNetworkTrackerCallback { /** diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 528f240b9912..ca7463884d3a 100644 --- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -88,13 +88,13 @@ public class TelephonySubscriptionTrackerTest { private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map<ParcelUuid, Set<String>> TEST_PRIVILEGED_PACKAGES = Collections.singletonMap(TEST_PARCEL_UUID, Collections.singleton(PACKAGE_NAME)); - private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP; + private static final Map<Integer, SubscriptionInfo> TEST_SUBID_TO_INFO_MAP; static { - final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>(); - subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID); - subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID); - TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap); + final Map<Integer, SubscriptionInfo> subIdToGroupMap = new HashMap<>(); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_SUBINFO_1); + subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_SUBINFO_2); + TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap); } @NonNull private final Context mContext; @@ -190,13 +190,13 @@ public class TelephonySubscriptionTrackerTest { private TelephonySubscriptionSnapshot buildExpectedSnapshot( Map<ParcelUuid, Set<String>> privilegedPackages) { - return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, privilegedPackages); + return buildExpectedSnapshot(TEST_SUBID_TO_INFO_MAP, privilegedPackages); } private TelephonySubscriptionSnapshot buildExpectedSnapshot( - Map<Integer, ParcelUuid> subIdToGroupMap, + Map<Integer, SubscriptionInfo> subIdToInfoMap, Map<ParcelUuid, Set<String>> privilegedPackages) { - return new TelephonySubscriptionSnapshot(subIdToGroupMap, privilegedPackages); + return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages); } private void verifyNoActiveSubscriptions() { @@ -371,7 +371,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1)); assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2)); @@ -380,7 +380,7 @@ public class TelephonySubscriptionTrackerTest { @Test public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception { final TelephonySubscriptionSnapshot snapshot = - new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap()); + new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap()); assertEquals( new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)), diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 0b72cd93e8b0..a36fd797d11c 100644 --- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -42,12 +42,14 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.ParcelUuid; import android.os.test.TestLooper; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; import android.util.ArraySet; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback; -import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback; +import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkListener; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; @@ -98,11 +100,13 @@ public class UnderlyingNetworkTrackerTest { @Mock private Context mContext; @Mock private VcnNetworkProvider mVcnNetworkProvider; @Mock private ConnectivityManager mConnectivityManager; + @Mock private TelephonyManager mTelephonyManager; + @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb; @Mock private Network mNetwork; - @Captor private ArgumentCaptor<RouteSelectionCallback> mRouteSelectionCallbackCaptor; + @Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor; private TestLooper mTestLooper; private VcnContext mVcnContext; @@ -127,6 +131,13 @@ public class UnderlyingNetworkTrackerTest { mConnectivityManager, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + setupSystemService( + mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + setupSystemService( + mContext, + mCarrierConfigManager, + Context.CARRIER_CONFIG_SERVICE, + CarrierConfigManager.class); when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); @@ -163,26 +174,26 @@ public class UnderlyingNetworkTrackerTest { @Test public void testNetworkCallbacksRegisteredOnStartupForTestMode() { + final ConnectivityManager cm = mock(ConnectivityManager.class); + setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); final VcnContext vcnContext = - spy( - new VcnContext( - mContext, - mTestLooper.getLooper(), - mVcnNetworkProvider, - true /* isInTestMode */)); - - mUnderlyingNetworkTracker = - new UnderlyingNetworkTracker( - vcnContext, - SUB_GROUP, - mSubscriptionSnapshot, - Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), - mNetworkTrackerCb); - - verify(mConnectivityManager) - .requestBackgroundNetwork( + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + true /* isInTestMode */); + + new UnderlyingNetworkTracker( + vcnContext, + SUB_GROUP, + mSubscriptionSnapshot, + Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET), + mNetworkTrackerCb); + + verify(cm) + .registerNetworkCallback( eq(getTestNetworkRequest(INITIAL_SUB_IDS)), - any(RouteSelectionCallback.class), + any(UnderlyingNetworkListener.class), any()); } @@ -200,9 +211,19 @@ public class UnderlyingNetworkTrackerTest { } verify(mConnectivityManager) - .requestBackgroundNetwork( + .registerNetworkCallback( eq(getRouteSelectionRequest(expectedSubIds)), - any(RouteSelectionCallback.class), + any(UnderlyingNetworkListener.class), + any()); + verify(mConnectivityManager) + .registerNetworkCallback( + eq(getWifiEntryRssiThresholdRequest(expectedSubIds)), + any(NetworkBringupCallback.class), + any()); + verify(mConnectivityManager) + .registerNetworkCallback( + eq(getWifiExitRssiThresholdRequest(expectedSubIds)), + any(NetworkBringupCallback.class), any()); } @@ -218,9 +239,10 @@ public class UnderlyingNetworkTrackerTest { mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate); // verify that initially-filed bringup requests are unregistered (cell + wifi) - verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 1)) + verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verify(mConnectivityManager) + .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); verifyNetworkRequestsRegistered(UPDATED_SUB_IDS); } @@ -231,6 +253,24 @@ public class UnderlyingNetworkTrackerTest { .build(); } + private NetworkRequest getWifiEntryRssiThresholdRequest(Set<Integer> netCapsSubIds) { + // TODO (b/187991063): Add tests for carrier-config based thresholds + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(netCapsSubIds) + .setSignalStrength(UnderlyingNetworkTracker.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) + .build(); + } + + private NetworkRequest getWifiExitRssiThresholdRequest(Set<Integer> netCapsSubIds) { + // TODO (b/187991063): Add tests for carrier-config based thresholds + return getExpectedRequestBase() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setSubscriptionIds(netCapsSubIds) + .setSignalStrength(UnderlyingNetworkTracker.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) + .build(); + } + private NetworkRequest getCellRequestForSubId(int subId) { return getExpectedRequestBase() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) @@ -239,7 +279,11 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) { - return getExpectedRequestBase().setSubscriptionIds(netCapsSubIds).build(); + return getExpectedRequestBase() + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .setSubscriptionIds(netCapsSubIds) + .build(); } private NetworkRequest getTestNetworkRequest(Set<Integer> netCapsSubIds) { @@ -265,11 +309,12 @@ public class UnderlyingNetworkTrackerTest { public void testTeardown() { mUnderlyingNetworkTracker.teardown(); - // Expect 3 NetworkBringupCallbacks to be unregistered: 1 for WiFi and 2 for Cellular (1x - // for each subId) - verify(mConnectivityManager, times(3)) + // Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for + // each subId), and 1 for each of the Wifi signal strength thresholds + verify(mConnectivityManager, times(5)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verify(mConnectivityManager) + .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); } @Test @@ -302,19 +347,19 @@ public class UnderlyingNetworkTrackerTest { verifyRegistrationOnAvailableAndGetCallback(); } - private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback() { + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() { return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); } - private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback( + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback( NetworkCapabilities networkCapabilities) { verify(mConnectivityManager) - .requestBackgroundNetwork( + .registerNetworkCallback( eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), - mRouteSelectionCallbackCaptor.capture(), + mUnderlyingNetworkListenerCaptor.capture(), any()); - RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue(); + UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue(); cb.onAvailable(mNetwork); cb.onCapabilitiesChanged(mNetwork, networkCapabilities); cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES); @@ -332,7 +377,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES); @@ -347,7 +392,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES); @@ -362,7 +407,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES); @@ -381,7 +426,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkResumed() { - RouteSelectionCallback cb = + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); @@ -401,7 +446,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForBlocked() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); @@ -416,7 +461,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackNotifiedForNetworkLoss() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLost(mNetwork); @@ -425,7 +470,7 @@ public class UnderlyingNetworkTrackerTest { @Test public void testRecordTrackerCallbackIgnoresDuplicateRecord() { - RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback(); + UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES); @@ -433,4 +478,6 @@ public class UnderlyingNetworkTrackerTest { // UnderlyingNetworkRecord does not actually change verifyNoMoreInteractions(mNetworkTrackerCb); } + + // TODO (b/187991063): Add tests for network prioritization } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index 1ecb4c9ee298..c747bc096a6f 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -54,6 +54,7 @@ import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.test.TestLooper; +import android.telephony.SubscriptionInfo; import com.android.internal.util.State; import com.android.internal.util.WakeupMessage; @@ -73,6 +74,12 @@ import java.util.concurrent.TimeUnit; public class VcnGatewayConnectionTestBase { protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); + protected static final SubscriptionInfo TEST_SUB_INFO = mock(SubscriptionInfo.class); + + static { + doReturn(TEST_SUB_GRP).when(TEST_SUB_INFO).getGroupUuid(); + } + protected static final InetAddress TEST_DNS_ADDR = InetAddresses.parseNumericAddress("2001:DB8:0:1::"); protected static final InetAddress TEST_DNS_ADDR_2 = @@ -116,7 +123,7 @@ public class VcnGatewayConnectionTestBase { protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = new TelephonySubscriptionSnapshot( - Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP); + Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP); @NonNull protected final Context mContext; @NonNull protected final TestLooper mTestLooper; |