Merge "Custom network selection"
This commit is contained in:
@@ -74,6 +74,36 @@ import java.util.concurrent.Executor;
|
|||||||
public class VcnManager {
|
public class VcnManager {
|
||||||
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
|
@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<
|
private static final Map<
|
||||||
VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
|
VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
|
||||||
REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
|
REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
*/
|
*/
|
||||||
public void handleSubscriptionsChanged() {
|
public void handleSubscriptionsChanged() {
|
||||||
final Map<ParcelUuid, Set<String>> privilegedPackages = new HashMap<>();
|
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();
|
final List<SubscriptionInfo> allSubs = mSubscriptionManager.getAllSubscriptionInfoList();
|
||||||
if (allSubs == null) {
|
if (allSubs == null) {
|
||||||
@@ -160,7 +160,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build subId -> subGrp cache
|
// 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
|
// Update subscription groups that are both ready, and active. For a group to be
|
||||||
// considered active, both of the following must be true:
|
// considered active, both of the following must be true:
|
||||||
@@ -186,7 +186,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final TelephonySubscriptionSnapshot newSnapshot =
|
final TelephonySubscriptionSnapshot newSnapshot =
|
||||||
new TelephonySubscriptionSnapshot(newSubIdToGroupMap, privilegedPackages);
|
new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages);
|
||||||
|
|
||||||
// If snapshot was meaningfully updated, fire the callback
|
// If snapshot was meaningfully updated, fire the callback
|
||||||
if (!newSnapshot.equals(mCurrentSnapshot)) {
|
if (!newSnapshot.equals(mCurrentSnapshot)) {
|
||||||
@@ -245,7 +245,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
|
|
||||||
/** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
|
/** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
|
||||||
public static class TelephonySubscriptionSnapshot {
|
public static class TelephonySubscriptionSnapshot {
|
||||||
private final Map<Integer, ParcelUuid> mSubIdToGroupMap;
|
private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap;
|
||||||
private final Map<ParcelUuid, Set<String>> mPrivilegedPackages;
|
private final Map<ParcelUuid, Set<String>> mPrivilegedPackages;
|
||||||
|
|
||||||
public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT =
|
public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT =
|
||||||
@@ -253,12 +253,12 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
|
|
||||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
TelephonySubscriptionSnapshot(
|
TelephonySubscriptionSnapshot(
|
||||||
@NonNull Map<Integer, ParcelUuid> subIdToGroupMap,
|
@NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap,
|
||||||
@NonNull Map<ParcelUuid, Set<String>> privilegedPackages) {
|
@NonNull Map<ParcelUuid, Set<String>> privilegedPackages) {
|
||||||
Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null");
|
Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null");
|
||||||
Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
|
Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
|
||||||
|
|
||||||
mSubIdToGroupMap = Collections.unmodifiableMap(subIdToGroupMap);
|
mSubIdToInfoMap = Collections.unmodifiableMap(subIdToInfoMap);
|
||||||
|
|
||||||
final Map<ParcelUuid, Set<String>> unmodifiableInnerSets = new ArrayMap<>();
|
final Map<ParcelUuid, Set<String>> unmodifiableInnerSets = new ArrayMap<>();
|
||||||
for (Entry<ParcelUuid, Set<String>> entry : privilegedPackages.entrySet()) {
|
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. */
|
/** Returns the Subscription Group for a given subId. */
|
||||||
@Nullable
|
@Nullable
|
||||||
public ParcelUuid getGroupForSubId(int subId) {
|
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) {
|
public Set<Integer> getAllSubIdsInGroup(ParcelUuid subGrp) {
|
||||||
final Set<Integer> subIds = new ArraySet<>();
|
final Set<Integer> subIds = new ArraySet<>();
|
||||||
|
|
||||||
for (Entry<Integer, ParcelUuid> entry : mSubIdToGroupMap.entrySet()) {
|
for (Entry<Integer, SubscriptionInfo> entry : mSubIdToInfoMap.entrySet()) {
|
||||||
if (subGrp.equals(entry.getValue())) {
|
if (subGrp.equals(entry.getValue().getGroupUuid())) {
|
||||||
subIds.add(entry.getKey());
|
subIds.add(entry.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,9 +306,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
return subIds;
|
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(mSubIdToGroupMap, mPrivilegedPackages);
|
return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -317,7 +327,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
|
|
||||||
final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj;
|
final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj;
|
||||||
|
|
||||||
return mSubIdToGroupMap.equals(other.mSubIdToGroupMap)
|
return mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
|
||||||
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
|
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +336,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
pw.println("TelephonySubscriptionSnapshot:");
|
pw.println("TelephonySubscriptionSnapshot:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
|
|
||||||
pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap);
|
pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap);
|
||||||
pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
|
pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
|
||||||
|
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
@@ -335,7 +345,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TelephonySubscriptionSnapshot{ "
|
return "TelephonySubscriptionSnapshot{ "
|
||||||
+ "mSubIdToGroupMap=" + mSubIdToGroupMap
|
+ "mSubIdToInfoMap=" + mSubIdToInfoMap
|
||||||
+ ", mPrivilegedPackages=" + mPrivilegedPackages
|
+ ", mPrivilegedPackages=" + mPrivilegedPackages
|
||||||
+ " }";
|
+ " }";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.android.server.vcn;
|
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.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
@@ -25,8 +29,16 @@ import android.net.Network;
|
|||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.TelephonyNetworkSpecifier;
|
import android.net.TelephonyNetworkSpecifier;
|
||||||
|
import android.net.vcn.VcnManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerExecutor;
|
||||||
import android.os.ParcelUuid;
|
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 android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -35,9 +47,13 @@ import com.android.internal.util.IndentingPrintWriter;
|
|||||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks a set of Networks underpinning a VcnGatewayConnection.
|
* Tracks a set of Networks underpinning a VcnGatewayConnection.
|
||||||
@@ -51,6 +67,45 @@ import java.util.Set;
|
|||||||
public class UnderlyingNetworkTracker {
|
public class UnderlyingNetworkTracker {
|
||||||
@NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName();
|
@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 VcnContext mVcnContext;
|
||||||
@NonNull private final ParcelUuid mSubscriptionGroup;
|
@NonNull private final ParcelUuid mSubscriptionGroup;
|
||||||
@NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
|
@NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
|
||||||
@@ -58,12 +113,17 @@ public class UnderlyingNetworkTracker {
|
|||||||
@NonNull private final Dependencies mDeps;
|
@NonNull private final Dependencies mDeps;
|
||||||
@NonNull private final Handler mHandler;
|
@NonNull private final Handler mHandler;
|
||||||
@NonNull private final ConnectivityManager mConnectivityManager;
|
@NonNull private final ConnectivityManager mConnectivityManager;
|
||||||
|
@NonNull private final TelephonyCallback mActiveDataSubIdListener =
|
||||||
|
new VcnActiveDataSubscriptionIdListener();
|
||||||
|
|
||||||
@NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>();
|
@NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>();
|
||||||
@Nullable private NetworkCallback mWifiBringupCallback;
|
@Nullable private NetworkCallback mWifiBringupCallback;
|
||||||
@Nullable private NetworkCallback mRouteSelectionCallback;
|
@Nullable private NetworkCallback mWifiEntryRssiThresholdCallback;
|
||||||
|
@Nullable private NetworkCallback mWifiExitRssiThresholdCallback;
|
||||||
|
@Nullable private UnderlyingNetworkListener mRouteSelectionCallback;
|
||||||
|
|
||||||
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
|
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
|
||||||
|
@Nullable private PersistableBundle mCarrierConfig;
|
||||||
private boolean mIsQuitting = false;
|
private boolean mIsQuitting = false;
|
||||||
|
|
||||||
@Nullable private UnderlyingNetworkRecord mCurrentRecord;
|
@Nullable private UnderlyingNetworkRecord mCurrentRecord;
|
||||||
@@ -104,6 +164,30 @@ public class UnderlyingNetworkTracker {
|
|||||||
mHandler = new Handler(mVcnContext.getLooper());
|
mHandler = new Handler(mVcnContext.getLooper());
|
||||||
|
|
||||||
mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
|
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();
|
registerOrUpdateNetworkRequests();
|
||||||
}
|
}
|
||||||
@@ -111,16 +195,30 @@ public class UnderlyingNetworkTracker {
|
|||||||
private void registerOrUpdateNetworkRequests() {
|
private void registerOrUpdateNetworkRequests() {
|
||||||
NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback;
|
NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback;
|
||||||
NetworkCallback oldWifiCallback = mWifiBringupCallback;
|
NetworkCallback oldWifiCallback = mWifiBringupCallback;
|
||||||
|
NetworkCallback oldWifiEntryRssiThresholdCallback = mWifiEntryRssiThresholdCallback;
|
||||||
|
NetworkCallback oldWifiExitRssiThresholdCallback = mWifiExitRssiThresholdCallback;
|
||||||
List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks);
|
List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks);
|
||||||
mCellBringupCallbacks.clear();
|
mCellBringupCallbacks.clear();
|
||||||
|
|
||||||
// Register new callbacks. Make-before-break; always register new callbacks before removal
|
// Register new callbacks. Make-before-break; always register new callbacks before removal
|
||||||
// of old callbacks
|
// of old callbacks
|
||||||
if (!mIsQuitting) {
|
if (!mIsQuitting) {
|
||||||
mRouteSelectionCallback = new RouteSelectionCallback();
|
mRouteSelectionCallback = new UnderlyingNetworkListener();
|
||||||
mConnectivityManager.requestBackgroundNetwork(
|
mConnectivityManager.registerNetworkCallback(
|
||||||
getRouteSelectionRequest(), mRouteSelectionCallback, mHandler);
|
getRouteSelectionRequest(), mRouteSelectionCallback, mHandler);
|
||||||
|
|
||||||
|
mWifiEntryRssiThresholdCallback = new NetworkBringupCallback();
|
||||||
|
mConnectivityManager.registerNetworkCallback(
|
||||||
|
getWifiEntryRssiThresholdNetworkRequest(),
|
||||||
|
mWifiEntryRssiThresholdCallback,
|
||||||
|
mHandler);
|
||||||
|
|
||||||
|
mWifiExitRssiThresholdCallback = new NetworkBringupCallback();
|
||||||
|
mConnectivityManager.registerNetworkCallback(
|
||||||
|
getWifiExitRssiThresholdNetworkRequest(),
|
||||||
|
mWifiExitRssiThresholdCallback,
|
||||||
|
mHandler);
|
||||||
|
|
||||||
mWifiBringupCallback = new NetworkBringupCallback();
|
mWifiBringupCallback = new NetworkBringupCallback();
|
||||||
mConnectivityManager.requestBackgroundNetwork(
|
mConnectivityManager.requestBackgroundNetwork(
|
||||||
getWifiNetworkRequest(), mWifiBringupCallback, mHandler);
|
getWifiNetworkRequest(), mWifiBringupCallback, mHandler);
|
||||||
@@ -135,6 +233,8 @@ public class UnderlyingNetworkTracker {
|
|||||||
} else {
|
} else {
|
||||||
mRouteSelectionCallback = null;
|
mRouteSelectionCallback = null;
|
||||||
mWifiBringupCallback = null;
|
mWifiBringupCallback = null;
|
||||||
|
mWifiEntryRssiThresholdCallback = null;
|
||||||
|
mWifiExitRssiThresholdCallback = null;
|
||||||
// mCellBringupCallbacks already cleared above.
|
// mCellBringupCallbacks already cleared above.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +245,12 @@ public class UnderlyingNetworkTracker {
|
|||||||
if (oldWifiCallback != null) {
|
if (oldWifiCallback != null) {
|
||||||
mConnectivityManager.unregisterNetworkCallback(oldWifiCallback);
|
mConnectivityManager.unregisterNetworkCallback(oldWifiCallback);
|
||||||
}
|
}
|
||||||
|
if (oldWifiEntryRssiThresholdCallback != null) {
|
||||||
|
mConnectivityManager.unregisterNetworkCallback(oldWifiEntryRssiThresholdCallback);
|
||||||
|
}
|
||||||
|
if (oldWifiExitRssiThresholdCallback != null) {
|
||||||
|
mConnectivityManager.unregisterNetworkCallback(oldWifiExitRssiThresholdCallback);
|
||||||
|
}
|
||||||
for (NetworkCallback cellBringupCallback : oldCellCallbacks) {
|
for (NetworkCallback cellBringupCallback : oldCellCallbacks) {
|
||||||
mConnectivityManager.unregisterNetworkCallback(cellBringupCallback);
|
mConnectivityManager.unregisterNetworkCallback(cellBringupCallback);
|
||||||
}
|
}
|
||||||
@@ -168,6 +274,8 @@ public class UnderlyingNetworkTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return getBaseNetworkRequestBuilder()
|
return getBaseNetworkRequestBuilder()
|
||||||
|
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
||||||
|
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
|
||||||
.setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
|
.setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
@@ -188,6 +296,38 @@ public class UnderlyingNetworkTracker {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Builds a Cellular bringup request for a given subId
|
||||||
*
|
*
|
||||||
@@ -233,10 +373,18 @@ public class UnderlyingNetworkTracker {
|
|||||||
* reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered
|
* reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered
|
||||||
* or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change.
|
* or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change.
|
||||||
*/
|
*/
|
||||||
public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
|
public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot newSnapshot) {
|
||||||
Objects.requireNonNull(snapshot, "Missing snapshot");
|
Objects.requireNonNull(newSnapshot, "Missing newSnapshot");
|
||||||
|
|
||||||
mLastSnapshot = snapshot;
|
final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot;
|
||||||
|
mLastSnapshot = newSnapshot;
|
||||||
|
|
||||||
|
// Only trigger re-registration if subIds in this group have changed
|
||||||
|
if (oldSnapshot
|
||||||
|
.getAllSubIdsInGroup(mSubscriptionGroup)
|
||||||
|
.equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
registerOrUpdateNetworkRequests();
|
registerOrUpdateNetworkRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,88 +395,43 @@ public class UnderlyingNetworkTracker {
|
|||||||
|
|
||||||
// Will unregister all existing callbacks, but not register new ones due to quitting flag.
|
// Will unregister all existing callbacks, but not register new ones due to quitting flag.
|
||||||
registerOrUpdateNetworkRequests();
|
registerOrUpdateNetworkRequests();
|
||||||
|
|
||||||
|
mVcnContext
|
||||||
|
.getContext()
|
||||||
|
.getSystemService(TelephonyManager.class)
|
||||||
|
.unregisterTelephonyCallback(mActiveDataSubIdListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether the currently selected Network matches the given network. */
|
private void reevaluateNetworks() {
|
||||||
private static boolean isSameNetwork(
|
TreeSet<UnderlyingNetworkRecord> sorted =
|
||||||
@Nullable UnderlyingNetworkRecord.Builder recordInProgress, @NonNull Network network) {
|
new TreeSet<>(
|
||||||
return recordInProgress != null && recordInProgress.getNetwork().equals(network);
|
UnderlyingNetworkRecord.getComparator(
|
||||||
}
|
mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig));
|
||||||
|
sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks());
|
||||||
|
|
||||||
/** Notify the Callback if a full UnderlyingNetworkRecord exists. */
|
UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first();
|
||||||
private void maybeNotifyCallback() {
|
if (Objects.equals(mCurrentRecord, candidate)) {
|
||||||
// Only forward this update if a complete record has been received
|
|
||||||
if (!mRecordInProgress.isValid()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only forward this update if the updated record differs form the current record
|
mCurrentRecord = candidate;
|
||||||
UnderlyingNetworkRecord updatedRecord = mRecordInProgress.build();
|
mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord);
|
||||||
if (!updatedRecord.equals(mCurrentRecord)) {
|
|
||||||
mCurrentRecord = updatedRecord;
|
|
||||||
|
|
||||||
mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleNetworkAvailable(@NonNull Network network) {
|
private static boolean isOpportunistic(
|
||||||
mVcnContext.ensureRunningOnLooperThread();
|
@NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) {
|
||||||
|
if (snapshot == null) {
|
||||||
mRecordInProgress = new UnderlyingNetworkRecord.Builder(network);
|
Slog.wtf(TAG, "Got null snapshot");
|
||||||
}
|
return false;
|
||||||
|
|
||||||
private void handleNetworkLost(@NonNull Network network) {
|
|
||||||
mVcnContext.ensureRunningOnLooperThread();
|
|
||||||
|
|
||||||
if (!isSameNetwork(mRecordInProgress, network)) {
|
|
||||||
Slog.wtf(TAG, "Non-underlying Network lost");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mRecordInProgress = null;
|
for (int subId : subIds) {
|
||||||
mCurrentRecord = null;
|
if (snapshot.isOpportunistic(subId)) {
|
||||||
mCb.onSelectedUnderlyingNetworkChanged(null /* underlyingNetworkRecord */);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCapabilitiesChanged(
|
|
||||||
@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
|
|
||||||
mVcnContext.ensureRunningOnLooperThread();
|
|
||||||
|
|
||||||
if (!isSameNetwork(mRecordInProgress, network)) {
|
|
||||||
Slog.wtf(TAG, "Invalid update to NetworkCapabilities");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mRecordInProgress.setNetworkCapabilities(networkCapabilities);
|
return false;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
mRecordInProgress.setIsBlocked(isBlocked);
|
|
||||||
|
|
||||||
maybeNotifyCallback();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -347,36 +450,104 @@ public class UnderlyingNetworkTracker {
|
|||||||
* truth.
|
* truth.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@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
|
@Override
|
||||||
public void onAvailable(@NonNull Network network) {
|
public void onAvailable(@NonNull Network network) {
|
||||||
handleNetworkAvailable(network);
|
mUnderlyingNetworkRecordBuilders.put(
|
||||||
|
network, new UnderlyingNetworkRecord.Builder(network));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLost(@NonNull Network network) {
|
public void onLost(@NonNull Network network) {
|
||||||
handleNetworkLost(network);
|
mUnderlyingNetworkRecordBuilders.remove(network);
|
||||||
|
|
||||||
|
reevaluateNetworks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCapabilitiesChanged(
|
public void onCapabilitiesChanged(
|
||||||
@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
|
@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
|
||||||
if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return;
|
final UnderlyingNetworkRecord.Builder builder =
|
||||||
handleCapabilitiesChanged(network, networkCapabilities);
|
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
|
@Override
|
||||||
public void onLinkPropertiesChanged(
|
public void onLinkPropertiesChanged(
|
||||||
@NonNull Network network, @NonNull LinkProperties linkProperties) {
|
@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
|
@Override
|
||||||
public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) {
|
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. */
|
/** A record of a single underlying network, caching relevant fields. */
|
||||||
public static class UnderlyingNetworkRecord {
|
public static class UnderlyingNetworkRecord {
|
||||||
@NonNull public final Network network;
|
@NonNull public final Network network;
|
||||||
@@ -413,6 +584,89 @@ public class UnderlyingNetworkTracker {
|
|||||||
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
|
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. */
|
/** Dumps the state of this record for logging and debugging purposes. */
|
||||||
public void dump(IndentingPrintWriter pw) {
|
public void dump(IndentingPrintWriter pw) {
|
||||||
pw.println("UnderlyingNetworkRecord:");
|
pw.println("UnderlyingNetworkRecord:");
|
||||||
@@ -434,6 +688,8 @@ public class UnderlyingNetworkTracker {
|
|||||||
boolean mIsBlocked;
|
boolean mIsBlocked;
|
||||||
boolean mWasIsBlockedSet;
|
boolean mWasIsBlockedSet;
|
||||||
|
|
||||||
|
@Nullable private UnderlyingNetworkRecord mCached;
|
||||||
|
|
||||||
private Builder(@NonNull Network network) {
|
private Builder(@NonNull Network network) {
|
||||||
mNetwork = network;
|
mNetwork = network;
|
||||||
}
|
}
|
||||||
@@ -445,6 +701,7 @@ public class UnderlyingNetworkTracker {
|
|||||||
|
|
||||||
private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
|
private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
|
||||||
mNetworkCapabilities = networkCapabilities;
|
mNetworkCapabilities = networkCapabilities;
|
||||||
|
mCached = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -454,11 +711,13 @@ public class UnderlyingNetworkTracker {
|
|||||||
|
|
||||||
private void setLinkProperties(@NonNull LinkProperties linkProperties) {
|
private void setLinkProperties(@NonNull LinkProperties linkProperties) {
|
||||||
mLinkProperties = linkProperties;
|
mLinkProperties = linkProperties;
|
||||||
|
mCached = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setIsBlocked(boolean isBlocked) {
|
private void setIsBlocked(boolean isBlocked) {
|
||||||
mIsBlocked = isBlocked;
|
mIsBlocked = isBlocked;
|
||||||
mWasIsBlockedSet = true;
|
mWasIsBlockedSet = true;
|
||||||
|
mCached = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValid() {
|
private boolean isValid() {
|
||||||
@@ -466,12 +725,30 @@ public class UnderlyingNetworkTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private UnderlyingNetworkRecord build() {
|
private UnderlyingNetworkRecord build() {
|
||||||
return new UnderlyingNetworkRecord(
|
if (!isValid()) {
|
||||||
mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
|
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. */
|
/** Callbacks for being notified of the changes in, or to the selected underlying network. */
|
||||||
public interface UnderlyingNetworkTrackerCallback {
|
public interface UnderlyingNetworkTrackerCallback {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -88,13 +88,13 @@ public class TelephonySubscriptionTrackerTest {
|
|||||||
private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
|
private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
|
||||||
private static final Map<ParcelUuid, Set<String>> TEST_PRIVILEGED_PACKAGES =
|
private static final Map<ParcelUuid, Set<String>> TEST_PRIVILEGED_PACKAGES =
|
||||||
Collections.singletonMap(TEST_PARCEL_UUID, Collections.singleton(PACKAGE_NAME));
|
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 {
|
static {
|
||||||
final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
|
final Map<Integer, SubscriptionInfo> subIdToGroupMap = new HashMap<>();
|
||||||
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
|
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_SUBINFO_1);
|
||||||
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID);
|
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_SUBINFO_2);
|
||||||
TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap);
|
TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull private final Context mContext;
|
@NonNull private final Context mContext;
|
||||||
@@ -190,13 +190,13 @@ public class TelephonySubscriptionTrackerTest {
|
|||||||
|
|
||||||
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
|
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
|
||||||
Map<ParcelUuid, Set<String>> privilegedPackages) {
|
Map<ParcelUuid, Set<String>> privilegedPackages) {
|
||||||
return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, privilegedPackages);
|
return buildExpectedSnapshot(TEST_SUBID_TO_INFO_MAP, privilegedPackages);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
|
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
|
||||||
Map<Integer, ParcelUuid> subIdToGroupMap,
|
Map<Integer, SubscriptionInfo> subIdToInfoMap,
|
||||||
Map<ParcelUuid, Set<String>> privilegedPackages) {
|
Map<ParcelUuid, Set<String>> privilegedPackages) {
|
||||||
return new TelephonySubscriptionSnapshot(subIdToGroupMap, privilegedPackages);
|
return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyNoActiveSubscriptions() {
|
private void verifyNoActiveSubscriptions() {
|
||||||
@@ -371,7 +371,7 @@ public class TelephonySubscriptionTrackerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
|
public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
|
||||||
final TelephonySubscriptionSnapshot snapshot =
|
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_1));
|
||||||
assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
|
assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
|
||||||
@@ -380,7 +380,7 @@ public class TelephonySubscriptionTrackerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
|
public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
|
||||||
final TelephonySubscriptionSnapshot snapshot =
|
final TelephonySubscriptionSnapshot snapshot =
|
||||||
new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, emptyMap());
|
new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap());
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
|
new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
|
||||||
|
|||||||
@@ -42,12 +42,14 @@ import android.net.NetworkRequest;
|
|||||||
import android.net.TelephonyNetworkSpecifier;
|
import android.net.TelephonyNetworkSpecifier;
|
||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
|
import android.telephony.CarrierConfigManager;
|
||||||
import android.telephony.SubscriptionInfo;
|
import android.telephony.SubscriptionInfo;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||||
import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback;
|
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.UnderlyingNetworkRecord;
|
||||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
|
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
|
||||||
|
|
||||||
@@ -98,11 +100,13 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
@Mock private Context mContext;
|
@Mock private Context mContext;
|
||||||
@Mock private VcnNetworkProvider mVcnNetworkProvider;
|
@Mock private VcnNetworkProvider mVcnNetworkProvider;
|
||||||
@Mock private ConnectivityManager mConnectivityManager;
|
@Mock private ConnectivityManager mConnectivityManager;
|
||||||
|
@Mock private TelephonyManager mTelephonyManager;
|
||||||
|
@Mock private CarrierConfigManager mCarrierConfigManager;
|
||||||
@Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
@Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
||||||
@Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
|
@Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
|
||||||
@Mock private Network mNetwork;
|
@Mock private Network mNetwork;
|
||||||
|
|
||||||
@Captor private ArgumentCaptor<RouteSelectionCallback> mRouteSelectionCallbackCaptor;
|
@Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor;
|
||||||
|
|
||||||
private TestLooper mTestLooper;
|
private TestLooper mTestLooper;
|
||||||
private VcnContext mVcnContext;
|
private VcnContext mVcnContext;
|
||||||
@@ -127,6 +131,13 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
mConnectivityManager,
|
mConnectivityManager,
|
||||||
Context.CONNECTIVITY_SERVICE,
|
Context.CONNECTIVITY_SERVICE,
|
||||||
ConnectivityManager.class);
|
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);
|
when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS);
|
||||||
|
|
||||||
@@ -163,26 +174,26 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNetworkCallbacksRegisteredOnStartupForTestMode() {
|
public void testNetworkCallbacksRegisteredOnStartupForTestMode() {
|
||||||
|
final ConnectivityManager cm = mock(ConnectivityManager.class);
|
||||||
|
setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
|
||||||
final VcnContext vcnContext =
|
final VcnContext vcnContext =
|
||||||
spy(
|
new VcnContext(
|
||||||
new VcnContext(
|
mContext,
|
||||||
mContext,
|
mTestLooper.getLooper(),
|
||||||
mTestLooper.getLooper(),
|
mVcnNetworkProvider,
|
||||||
mVcnNetworkProvider,
|
true /* isInTestMode */);
|
||||||
true /* isInTestMode */));
|
|
||||||
|
|
||||||
mUnderlyingNetworkTracker =
|
new UnderlyingNetworkTracker(
|
||||||
new UnderlyingNetworkTracker(
|
vcnContext,
|
||||||
vcnContext,
|
SUB_GROUP,
|
||||||
SUB_GROUP,
|
mSubscriptionSnapshot,
|
||||||
mSubscriptionSnapshot,
|
Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
|
||||||
Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
|
mNetworkTrackerCb);
|
||||||
mNetworkTrackerCb);
|
|
||||||
|
|
||||||
verify(mConnectivityManager)
|
verify(cm)
|
||||||
.requestBackgroundNetwork(
|
.registerNetworkCallback(
|
||||||
eq(getTestNetworkRequest(INITIAL_SUB_IDS)),
|
eq(getTestNetworkRequest(INITIAL_SUB_IDS)),
|
||||||
any(RouteSelectionCallback.class),
|
any(UnderlyingNetworkListener.class),
|
||||||
any());
|
any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,9 +211,19 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
verify(mConnectivityManager)
|
verify(mConnectivityManager)
|
||||||
.requestBackgroundNetwork(
|
.registerNetworkCallback(
|
||||||
eq(getRouteSelectionRequest(expectedSubIds)),
|
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());
|
any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,9 +239,10 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
|
mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
|
||||||
|
|
||||||
// verify that initially-filed bringup requests are unregistered (cell + wifi)
|
// 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));
|
.unregisterNetworkCallback(any(NetworkBringupCallback.class));
|
||||||
verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class));
|
verify(mConnectivityManager)
|
||||||
|
.unregisterNetworkCallback(any(UnderlyingNetworkListener.class));
|
||||||
verifyNetworkRequestsRegistered(UPDATED_SUB_IDS);
|
verifyNetworkRequestsRegistered(UPDATED_SUB_IDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +253,24 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
.build();
|
.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) {
|
private NetworkRequest getCellRequestForSubId(int subId) {
|
||||||
return getExpectedRequestBase()
|
return getExpectedRequestBase()
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||||
@@ -239,7 +279,11 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
|
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) {
|
private NetworkRequest getTestNetworkRequest(Set<Integer> netCapsSubIds) {
|
||||||
@@ -265,11 +309,12 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
public void testTeardown() {
|
public void testTeardown() {
|
||||||
mUnderlyingNetworkTracker.teardown();
|
mUnderlyingNetworkTracker.teardown();
|
||||||
|
|
||||||
// Expect 3 NetworkBringupCallbacks to be unregistered: 1 for WiFi and 2 for Cellular (1x
|
// Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for
|
||||||
// for each subId)
|
// each subId), and 1 for each of the Wifi signal strength thresholds
|
||||||
verify(mConnectivityManager, times(3))
|
verify(mConnectivityManager, times(5))
|
||||||
.unregisterNetworkCallback(any(NetworkBringupCallback.class));
|
.unregisterNetworkCallback(any(NetworkBringupCallback.class));
|
||||||
verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class));
|
verify(mConnectivityManager)
|
||||||
|
.unregisterNetworkCallback(any(UnderlyingNetworkListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -302,19 +347,19 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
verifyRegistrationOnAvailableAndGetCallback();
|
verifyRegistrationOnAvailableAndGetCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback() {
|
private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() {
|
||||||
return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES);
|
return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback(
|
private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback(
|
||||||
NetworkCapabilities networkCapabilities) {
|
NetworkCapabilities networkCapabilities) {
|
||||||
verify(mConnectivityManager)
|
verify(mConnectivityManager)
|
||||||
.requestBackgroundNetwork(
|
.registerNetworkCallback(
|
||||||
eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
|
eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
|
||||||
mRouteSelectionCallbackCaptor.capture(),
|
mUnderlyingNetworkListenerCaptor.capture(),
|
||||||
any());
|
any());
|
||||||
|
|
||||||
RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue();
|
UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue();
|
||||||
cb.onAvailable(mNetwork);
|
cb.onAvailable(mNetwork);
|
||||||
cb.onCapabilitiesChanged(mNetwork, networkCapabilities);
|
cb.onCapabilitiesChanged(mNetwork, networkCapabilities);
|
||||||
cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES);
|
cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES);
|
||||||
@@ -332,7 +377,7 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() {
|
public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() {
|
||||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||||
|
|
||||||
cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
|
cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
|
||||||
|
|
||||||
@@ -347,7 +392,7 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() {
|
public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() {
|
||||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||||
|
|
||||||
cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES);
|
cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES);
|
||||||
|
|
||||||
@@ -362,7 +407,7 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
|
public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
|
||||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||||
|
|
||||||
cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
|
cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
|
||||||
|
|
||||||
@@ -381,7 +426,7 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordTrackerCallbackNotifiedForNetworkResumed() {
|
public void testRecordTrackerCallbackNotifiedForNetworkResumed() {
|
||||||
RouteSelectionCallback cb =
|
UnderlyingNetworkListener cb =
|
||||||
verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
|
verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
|
||||||
|
|
||||||
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
||||||
@@ -401,7 +446,7 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordTrackerCallbackNotifiedForBlocked() {
|
public void testRecordTrackerCallbackNotifiedForBlocked() {
|
||||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||||
|
|
||||||
cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
|
cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
|
||||||
|
|
||||||
@@ -416,7 +461,7 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordTrackerCallbackNotifiedForNetworkLoss() {
|
public void testRecordTrackerCallbackNotifiedForNetworkLoss() {
|
||||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||||
|
|
||||||
cb.onLost(mNetwork);
|
cb.onLost(mNetwork);
|
||||||
|
|
||||||
@@ -425,7 +470,7 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordTrackerCallbackIgnoresDuplicateRecord() {
|
public void testRecordTrackerCallbackIgnoresDuplicateRecord() {
|
||||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||||
|
|
||||||
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
||||||
|
|
||||||
@@ -433,4 +478,6 @@ public class UnderlyingNetworkTrackerTest {
|
|||||||
// UnderlyingNetworkRecord does not actually change
|
// UnderlyingNetworkRecord does not actually change
|
||||||
verifyNoMoreInteractions(mNetworkTrackerCb);
|
verifyNoMoreInteractions(mNetworkTrackerCb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO (b/187991063): Add tests for network prioritization
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import android.net.vcn.VcnGatewayConnectionConfigTest;
|
|||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
|
import android.telephony.SubscriptionInfo;
|
||||||
|
|
||||||
import com.android.internal.util.State;
|
import com.android.internal.util.State;
|
||||||
import com.android.internal.util.WakeupMessage;
|
import com.android.internal.util.WakeupMessage;
|
||||||
@@ -73,6 +74,12 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
public class VcnGatewayConnectionTestBase {
|
public class VcnGatewayConnectionTestBase {
|
||||||
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
|
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 =
|
protected static final InetAddress TEST_DNS_ADDR =
|
||||||
InetAddresses.parseNumericAddress("2001:DB8:0:1::");
|
InetAddresses.parseNumericAddress("2001:DB8:0:1::");
|
||||||
protected static final InetAddress TEST_DNS_ADDR_2 =
|
protected static final InetAddress TEST_DNS_ADDR_2 =
|
||||||
@@ -116,7 +123,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
|
|
||||||
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
|
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
|
||||||
new TelephonySubscriptionSnapshot(
|
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 Context mContext;
|
||||||
@NonNull protected final TestLooper mTestLooper;
|
@NonNull protected final TestLooper mTestLooper;
|
||||||
|
|||||||
Reference in New Issue
Block a user