Merge changes from topic "vcn-network-policy" am: e980914d42 am: 8804aed91c
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1555540 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Iaae55908a50ab13bb335e4ca742c1335f2d088f1
This commit is contained in:
@@ -67,7 +67,6 @@ import java.util.concurrent.Executor;
|
||||
public class VcnManager {
|
||||
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static final Map<
|
||||
VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
|
||||
|
||||
@@ -27,10 +27,12 @@ import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.IVcnManagementService;
|
||||
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
||||
import android.net.vcn.VcnConfig;
|
||||
import android.net.vcn.VcnUnderlyingNetworkPolicy;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
@@ -291,6 +293,12 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
@NonNull VcnConfig config) {
|
||||
return new Vcn(vcnContext, subscriptionGroup, config);
|
||||
}
|
||||
|
||||
/** Gets the subId indicated by the given {@link WifiInfo}. */
|
||||
public int getSubIdForWifiInfo(@NonNull WifiInfo wifiInfo) {
|
||||
// TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId
|
||||
return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
}
|
||||
}
|
||||
|
||||
/** Notifies the VcnManagementService that external dependencies can be set up. */
|
||||
@@ -582,8 +590,36 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
"Must have permission NETWORK_FACTORY or be the SystemServer to get underlying"
|
||||
+ " Network policies");
|
||||
|
||||
// TODO(b/175914059): implement policy generation once VcnManagementService is able to
|
||||
// determine policies
|
||||
// Defensive copy in case this call is in-process and the given NetworkCapabilities mutates
|
||||
networkCapabilities = new NetworkCapabilities(networkCapabilities);
|
||||
|
||||
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
&& networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) {
|
||||
TelephonyNetworkSpecifier telephonyNetworkSpecifier =
|
||||
(TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier();
|
||||
subId = telephonyNetworkSpecifier.getSubscriptionId();
|
||||
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
&& networkCapabilities.getTransportInfo() instanceof WifiInfo) {
|
||||
WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
|
||||
subId = mDeps.getSubIdForWifiInfo(wifiInfo);
|
||||
}
|
||||
|
||||
boolean isVcnManagedNetwork = false;
|
||||
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
synchronized (mLock) {
|
||||
ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId);
|
||||
|
||||
// TODO(b/178140910): only mark the Network as VCN-managed if not in safe mode
|
||||
if (mVcns.containsKey(subGroup)) {
|
||||
isVcnManagedNetwork = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isVcnManagedNetwork) {
|
||||
networkCapabilities.removeCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
}
|
||||
|
||||
return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
|
||||
}
|
||||
|
||||
@@ -18,16 +18,28 @@ package com.android.server.vcn;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.ConnectivityManager.NetworkCallback;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkCapabilities.NetCapability;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.os.Handler;
|
||||
import android.os.ParcelUuid;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Tracks a set of Networks underpinning a VcnGatewayConnection.
|
||||
@@ -38,53 +50,385 @@ import java.util.Objects;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class UnderlyingNetworkTracker extends Handler {
|
||||
public class UnderlyingNetworkTracker {
|
||||
@NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName();
|
||||
|
||||
@NonNull private final VcnContext mVcnContext;
|
||||
@NonNull private final ParcelUuid mSubscriptionGroup;
|
||||
@NonNull private final UnderlyingNetworkTrackerCallback mCb;
|
||||
@NonNull private final Dependencies mDeps;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final ConnectivityManager mConnectivityManager;
|
||||
@NonNull private final SubscriptionManager mSubscriptionManager;
|
||||
|
||||
@NonNull private final SparseArray<NetworkCallback> mCellBringupCallbacks = new SparseArray<>();
|
||||
@NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback();
|
||||
@NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback();
|
||||
|
||||
@NonNull private final Set<Integer> mSubIds = new ArraySet<>();
|
||||
|
||||
@NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
|
||||
|
||||
@Nullable private UnderlyingNetworkRecord mCurrentRecord;
|
||||
@Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
|
||||
|
||||
public UnderlyingNetworkTracker(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
|
||||
@NonNull UnderlyingNetworkTrackerCallback cb) {
|
||||
this(vcnContext, subscriptionGroup, cb, new Dependencies());
|
||||
this(
|
||||
vcnContext,
|
||||
subscriptionGroup,
|
||||
requiredUnderlyingNetworkCapabilities,
|
||||
cb,
|
||||
new Dependencies());
|
||||
}
|
||||
|
||||
private UnderlyingNetworkTracker(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
|
||||
@NonNull UnderlyingNetworkTrackerCallback cb,
|
||||
@NonNull Dependencies deps) {
|
||||
super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
||||
mVcnContext = vcnContext;
|
||||
mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
|
||||
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
|
||||
mRequiredUnderlyingNetworkCapabilities =
|
||||
Objects.requireNonNull(
|
||||
requiredUnderlyingNetworkCapabilities,
|
||||
"Missing requiredUnderlyingNetworkCapabilities");
|
||||
mCb = Objects.requireNonNull(cb, "Missing cb");
|
||||
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
||||
|
||||
mHandler = new Handler(mVcnContext.getLooper());
|
||||
|
||||
mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
|
||||
mSubscriptionManager = mVcnContext.getContext().getSystemService(SubscriptionManager.class);
|
||||
|
||||
registerNetworkRequests();
|
||||
}
|
||||
|
||||
private void registerNetworkRequests() {
|
||||
// register bringup requests for underlying Networks
|
||||
mConnectivityManager.requestBackgroundNetwork(
|
||||
getWifiNetworkRequest(), mHandler, mWifiBringupCallback);
|
||||
updateSubIdsAndCellularRequests();
|
||||
|
||||
// register Network-selection request used to decide selected underlying Network
|
||||
mConnectivityManager.requestBackgroundNetwork(
|
||||
getNetworkRequestBase().build(), mHandler, mRouteSelectionCallback);
|
||||
}
|
||||
|
||||
private NetworkRequest getWifiNetworkRequest() {
|
||||
return getNetworkRequestBase().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
|
||||
}
|
||||
|
||||
private NetworkRequest getCellNetworkRequestForSubId(int subId) {
|
||||
return getNetworkRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
|
||||
.build();
|
||||
}
|
||||
|
||||
private NetworkRequest.Builder getNetworkRequestBase() {
|
||||
NetworkRequest.Builder requestBase = new NetworkRequest.Builder();
|
||||
for (@NetCapability int capability : mRequiredUnderlyingNetworkCapabilities) {
|
||||
requestBase.addCapability(capability);
|
||||
}
|
||||
|
||||
return requestBase
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||
.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current subIds and Cellular bringup requests for this UnderlyingNetworkTracker.
|
||||
*/
|
||||
private void updateSubIdsAndCellularRequests() {
|
||||
mVcnContext.ensureRunningOnLooperThread();
|
||||
|
||||
Set<Integer> prevSubIds = new ArraySet<>(mSubIds);
|
||||
mSubIds.clear();
|
||||
|
||||
// Ensure NetworkRequests filed for all current subIds in mSubscriptionGroup
|
||||
// STOPSHIP: b/177364490 use TelephonySubscriptionSnapshot to avoid querying Telephony
|
||||
List<SubscriptionInfo> subInfos =
|
||||
mSubscriptionManager.getSubscriptionsInGroup(mSubscriptionGroup);
|
||||
|
||||
for (SubscriptionInfo subInfo : subInfos) {
|
||||
final int subId = subInfo.getSubscriptionId();
|
||||
mSubIds.add(subId);
|
||||
|
||||
if (!mCellBringupCallbacks.contains(subId)) {
|
||||
final NetworkBringupCallback cb = new NetworkBringupCallback();
|
||||
mCellBringupCallbacks.put(subId, cb);
|
||||
|
||||
mConnectivityManager.requestBackgroundNetwork(
|
||||
getCellNetworkRequestForSubId(subId), mHandler, cb);
|
||||
}
|
||||
}
|
||||
|
||||
// unregister all NetworkCallbacks for outdated subIds
|
||||
for (final int subId : prevSubIds) {
|
||||
if (!mSubIds.contains(subId)) {
|
||||
final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
|
||||
mConnectivityManager.unregisterNetworkCallback(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Tears down this Tracker, and releases all underlying network requests. */
|
||||
public void teardown() {}
|
||||
public void teardown() {
|
||||
mVcnContext.ensureRunningOnLooperThread();
|
||||
|
||||
/** An record of a single underlying network, caching relevant fields. */
|
||||
mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback);
|
||||
mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback);
|
||||
|
||||
for (final int subId : mSubIds) {
|
||||
final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
|
||||
mConnectivityManager.unregisterNetworkCallback(cb);
|
||||
}
|
||||
mSubIds.clear();
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
// 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");
|
||||
return;
|
||||
}
|
||||
|
||||
mRecordInProgress = null;
|
||||
mCurrentRecord = null;
|
||||
mCb.onSelectedUnderlyingNetworkChanged(null /* underlyingNetworkRecord */);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
maybeNotifyCallback();
|
||||
}
|
||||
|
||||
private void handleNetworkSuspended(@NonNull Network network, boolean isSuspended) {
|
||||
mVcnContext.ensureRunningOnLooperThread();
|
||||
|
||||
if (!isSameNetwork(mRecordInProgress, network)) {
|
||||
Slog.wtf(TAG, "Invalid update to isSuspended");
|
||||
return;
|
||||
}
|
||||
|
||||
final NetworkCapabilities newCaps =
|
||||
new NetworkCapabilities(mRecordInProgress.getNetworkCapabilities());
|
||||
if (isSuspended) {
|
||||
newCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
|
||||
} else {
|
||||
newCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
|
||||
}
|
||||
|
||||
handleCapabilitiesChanged(network, newCaps);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* NetworkBringupCallback is used to keep background, VCN-managed Networks from being reaped.
|
||||
*
|
||||
* <p>NetworkBringupCallback only exists to prevent matching (VCN-managed) Networks from being
|
||||
* reaped, and no action is taken on any events firing.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
class NetworkBringupCallback extends NetworkCallback {}
|
||||
|
||||
/**
|
||||
* RouteSelectionCallback is used to select the "best" underlying Network.
|
||||
*
|
||||
* <p>The "best" network is determined by ConnectivityService, which is treated as a source of
|
||||
* truth.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
class RouteSelectionCallback extends NetworkCallback {
|
||||
@Override
|
||||
public void onAvailable(@NonNull Network network) {
|
||||
handleNetworkAvailable(network);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(@NonNull Network network) {
|
||||
handleNetworkLost(network);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCapabilitiesChanged(
|
||||
@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
|
||||
handleCapabilitiesChanged(network, networkCapabilities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNetworkSuspended(@NonNull Network network) {
|
||||
handleNetworkSuspended(network, true /* isSuspended */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNetworkResumed(@NonNull Network network) {
|
||||
handleNetworkSuspended(network, false /* isSuspended */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLinkPropertiesChanged(
|
||||
@NonNull Network network, @NonNull LinkProperties linkProperties) {
|
||||
handlePropertiesChanged(network, linkProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) {
|
||||
handleNetworkBlocked(network, isBlocked);
|
||||
}
|
||||
}
|
||||
|
||||
/** A record of a single underlying network, caching relevant fields. */
|
||||
public static class UnderlyingNetworkRecord {
|
||||
@NonNull public final Network network;
|
||||
@NonNull public final NetworkCapabilities networkCapabilities;
|
||||
@NonNull public final LinkProperties linkProperties;
|
||||
public final boolean blocked;
|
||||
public final boolean isBlocked;
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
UnderlyingNetworkRecord(
|
||||
@NonNull Network network,
|
||||
@NonNull NetworkCapabilities networkCapabilities,
|
||||
@NonNull LinkProperties linkProperties,
|
||||
boolean blocked) {
|
||||
boolean isBlocked) {
|
||||
this.network = network;
|
||||
this.networkCapabilities = networkCapabilities;
|
||||
this.linkProperties = linkProperties;
|
||||
this.blocked = blocked;
|
||||
this.isBlocked = isBlocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof UnderlyingNetworkRecord)) return false;
|
||||
final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o;
|
||||
|
||||
return network.equals(that.network)
|
||||
&& networkCapabilities.equals(that.networkCapabilities)
|
||||
&& linkProperties.equals(that.linkProperties)
|
||||
&& isBlocked == that.isBlocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
|
||||
}
|
||||
|
||||
/** Builder to incrementally construct an UnderlyingNetworkRecord. */
|
||||
private static class Builder {
|
||||
@NonNull private final Network mNetwork;
|
||||
|
||||
@Nullable private NetworkCapabilities mNetworkCapabilities;
|
||||
@Nullable private LinkProperties mLinkProperties;
|
||||
boolean mIsBlocked;
|
||||
boolean mWasIsBlockedSet;
|
||||
|
||||
private Builder(@NonNull Network network) {
|
||||
mNetwork = network;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Network getNetwork() {
|
||||
return mNetwork;
|
||||
}
|
||||
|
||||
private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
|
||||
mNetworkCapabilities = networkCapabilities;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private NetworkCapabilities getNetworkCapabilities() {
|
||||
return mNetworkCapabilities;
|
||||
}
|
||||
|
||||
private void setLinkProperties(@NonNull LinkProperties linkProperties) {
|
||||
mLinkProperties = linkProperties;
|
||||
}
|
||||
|
||||
private void setIsBlocked(boolean isBlocked) {
|
||||
mIsBlocked = isBlocked;
|
||||
mWasIsBlockedSet = true;
|
||||
}
|
||||
|
||||
private boolean isValid() {
|
||||
return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
|
||||
}
|
||||
|
||||
private UnderlyingNetworkRecord build() {
|
||||
return new UnderlyingNetworkRecord(
|
||||
mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +439,10 @@ public class UnderlyingNetworkTracker extends Handler {
|
||||
*
|
||||
* <p>This callback does NOT signal a mobility event.
|
||||
*
|
||||
* @param underlying The details of the new underlying network
|
||||
* @param underlyingNetworkRecord The details of the new underlying network
|
||||
*/
|
||||
void onSelectedUnderlyingNetworkChanged(@Nullable UnderlyingNetworkRecord underlying);
|
||||
void onSelectedUnderlyingNetworkChanged(
|
||||
@Nullable UnderlyingNetworkRecord underlyingNetworkRecord);
|
||||
}
|
||||
|
||||
private static class Dependencies {}
|
||||
|
||||
@@ -55,4 +55,15 @@ public class VcnContext {
|
||||
public VcnNetworkProvider getVcnNetworkProvider() {
|
||||
return mVcnNetworkProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the caller is running on the VcnContext Thread.
|
||||
*
|
||||
* @throwsIllegalStateException if the caller is not running on the VcnContext Thread.
|
||||
*/
|
||||
public void ensureRunningOnLooperThread() {
|
||||
if (getLooper().getThread() != Thread.currentThread()) {
|
||||
throw new IllegalStateException("Not running on VcnMgmtSvc thread");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -476,7 +477,10 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
|
||||
mUnderlyingNetworkTracker =
|
||||
mDeps.newUnderlyingNetworkTracker(
|
||||
mVcnContext, subscriptionGroup, mUnderlyingNetworkTrackerCallback);
|
||||
mVcnContext,
|
||||
subscriptionGroup,
|
||||
mConnectionConfig.getAllUnderlyingCapabilities(),
|
||||
mUnderlyingNetworkTrackerCallback);
|
||||
mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
|
||||
|
||||
IpSecTunnelInterface iface;
|
||||
@@ -1134,8 +1138,10 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
public UnderlyingNetworkTracker newUnderlyingNetworkTracker(
|
||||
VcnContext vcnContext,
|
||||
ParcelUuid subscriptionGroup,
|
||||
Set<Integer> requiredUnderlyingNetworkCapabilities,
|
||||
UnderlyingNetworkTrackerCallback callback) {
|
||||
return new UnderlyingNetworkTracker(vcnContext, subscriptionGroup, callback);
|
||||
return new UnderlyingNetworkTracker(
|
||||
vcnContext, subscriptionGroup, requiredUnderlyingNetworkCapabilities, callback);
|
||||
}
|
||||
|
||||
/** Builds a new IkeSession. */
|
||||
|
||||
@@ -22,7 +22,6 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
@@ -30,6 +29,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyBoolean;
|
||||
import static org.mockito.Mockito.argThat;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
@@ -39,16 +39,20 @@ import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkCapabilities.Transport;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
|
||||
import android.net.vcn.VcnConfig;
|
||||
import android.net.vcn.VcnConfigTest;
|
||||
import android.net.vcn.VcnUnderlyingNetworkPolicy;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.PersistableBundle;
|
||||
@@ -253,7 +257,14 @@ public class VcnManagementServiceTest {
|
||||
verify(mConfigReadWriteHelper).readFromDisk();
|
||||
}
|
||||
|
||||
private void triggerSubscriptionTrackerCallback(Set<ParcelUuid> activeSubscriptionGroups) {
|
||||
private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
|
||||
Set<ParcelUuid> activeSubscriptionGroups) {
|
||||
return triggerSubscriptionTrackerCbAndGetSnapshot(
|
||||
activeSubscriptionGroups, Collections.emptyMap());
|
||||
}
|
||||
|
||||
private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
|
||||
Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) {
|
||||
final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
|
||||
doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
|
||||
|
||||
@@ -267,8 +278,14 @@ public class VcnManagementServiceTest {
|
||||
argThat(val -> activeSubscriptionGroups.contains(val)),
|
||||
eq(TEST_PACKAGE_NAME));
|
||||
|
||||
doAnswer(invocation -> {
|
||||
return subIdToGroupMap.get(invocation.getArgument(0));
|
||||
}).when(snapshot).getGroupForSubId(anyInt());
|
||||
|
||||
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
|
||||
cb.onNewSnapshot(snapshot);
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() {
|
||||
@@ -287,7 +304,7 @@ public class VcnManagementServiceTest {
|
||||
|
||||
@Test
|
||||
public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
|
||||
triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_1));
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
|
||||
verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG));
|
||||
}
|
||||
|
||||
@@ -296,7 +313,7 @@ public class VcnManagementServiceTest {
|
||||
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
|
||||
final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
|
||||
|
||||
triggerSubscriptionTrackerCallback(Collections.emptySet());
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
|
||||
|
||||
// Verify teardown after delay
|
||||
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
|
||||
@@ -311,13 +328,13 @@ public class VcnManagementServiceTest {
|
||||
final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
|
||||
|
||||
// Simulate SIM unloaded
|
||||
triggerSubscriptionTrackerCallback(Collections.emptySet());
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
|
||||
|
||||
// Simulate new SIM loaded right during teardown delay.
|
||||
mTestLooper.moveTimeForward(
|
||||
VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
|
||||
mTestLooper.dispatchAll();
|
||||
triggerSubscriptionTrackerCallback(Collections.singleton(TEST_UUID_2));
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
|
||||
|
||||
// Verify that even after the full timeout duration, the VCN instance is not torn down
|
||||
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
|
||||
@@ -331,7 +348,7 @@ public class VcnManagementServiceTest {
|
||||
final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
|
||||
|
||||
// Simulate SIM unloaded
|
||||
triggerSubscriptionTrackerCallback(Collections.emptySet());
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
|
||||
|
||||
// Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
|
||||
// vcnInstance.
|
||||
@@ -496,14 +513,73 @@ public class VcnManagementServiceTest {
|
||||
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
|
||||
}
|
||||
|
||||
private void setUpVcnSubscription(int subId, ParcelUuid subGroup) {
|
||||
mVcnMgmtSvc.setVcnConfig(subGroup, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(
|
||||
Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup));
|
||||
}
|
||||
|
||||
private void verifyMergedNetworkCapabilities(
|
||||
NetworkCapabilities mergedCapabilities, @Transport int transportType) {
|
||||
assertTrue(mergedCapabilities.hasTransport(transportType));
|
||||
assertFalse(
|
||||
mergedCapabilities.hasCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnderlyingNetworkPolicy() throws Exception {
|
||||
public void testGetUnderlyingNetworkPolicyTransportCell() throws Exception {
|
||||
setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
|
||||
|
||||
NetworkCapabilities nc =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID))
|
||||
.build();
|
||||
|
||||
VcnUnderlyingNetworkPolicy policy =
|
||||
mVcnMgmtSvc.getUnderlyingNetworkPolicy(
|
||||
new NetworkCapabilities(), new LinkProperties());
|
||||
mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
|
||||
|
||||
assertFalse(policy.isTeardownRequested());
|
||||
assertNotNull(policy.getMergedNetworkCapabilities());
|
||||
verifyMergedNetworkCapabilities(
|
||||
policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnderlyingNetworkPolicyTransportWifi() throws Exception {
|
||||
setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
|
||||
|
||||
WifiInfo wifiInfo = mock(WifiInfo.class);
|
||||
when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo);
|
||||
when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID);
|
||||
NetworkCapabilities nc =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.setTransportInfo(wifiInfo)
|
||||
.build();
|
||||
|
||||
VcnUnderlyingNetworkPolicy policy =
|
||||
mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
|
||||
|
||||
assertFalse(policy.isTeardownRequested());
|
||||
verifyMergedNetworkCapabilities(
|
||||
policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
|
||||
NetworkCapabilities nc =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID))
|
||||
.build();
|
||||
|
||||
VcnUnderlyingNetworkPolicy policy =
|
||||
mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
|
||||
|
||||
assertFalse(policy.isTeardownRequested());
|
||||
assertEquals(nc, policy.getMergedNetworkCapabilities());
|
||||
}
|
||||
|
||||
@Test(expected = SecurityException.class)
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vcn;
|
||||
|
||||
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UnderlyingNetworkTrackerTest {
|
||||
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
|
||||
private static final int INITIAL_SUB_ID_1 = 1;
|
||||
private static final int INITIAL_SUB_ID_2 = 2;
|
||||
|
||||
private static final NetworkCapabilities INITIAL_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
.build();
|
||||
private static final NetworkCapabilities SUSPENDED_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder(INITIAL_NETWORK_CAPABILITIES)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
|
||||
.build();
|
||||
private static final NetworkCapabilities UPDATED_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.build();
|
||||
|
||||
private static final LinkProperties INITIAL_LINK_PROPERTIES =
|
||||
getLinkPropertiesWithName("initial_iface");
|
||||
private static final LinkProperties UPDATED_LINK_PROPERTIES =
|
||||
getLinkPropertiesWithName("updated_iface");
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private VcnNetworkProvider mVcnNetworkProvider;
|
||||
@Mock private ConnectivityManager mConnectivityManager;
|
||||
@Mock private SubscriptionManager mSubscriptionManager;
|
||||
@Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
|
||||
@Mock private Network mNetwork;
|
||||
|
||||
@Captor private ArgumentCaptor<RouteSelectionCallback> mRouteSelectionCallbackCaptor;
|
||||
|
||||
private TestLooper mTestLooper;
|
||||
private VcnContext mVcnContext;
|
||||
private UnderlyingNetworkTracker mUnderlyingNetworkTracker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mTestLooper = new TestLooper();
|
||||
mVcnContext = spy(new VcnContext(mContext, mTestLooper.getLooper(), mVcnNetworkProvider));
|
||||
doNothing().when(mVcnContext).ensureRunningOnLooperThread();
|
||||
|
||||
setupSystemService(
|
||||
mContext,
|
||||
mConnectivityManager,
|
||||
Context.CONNECTIVITY_SERVICE,
|
||||
ConnectivityManager.class);
|
||||
setupSystemService(
|
||||
mContext,
|
||||
mSubscriptionManager,
|
||||
Context.TELEPHONY_SUBSCRIPTION_SERVICE,
|
||||
SubscriptionManager.class);
|
||||
|
||||
List<SubscriptionInfo> initialSubInfos =
|
||||
Arrays.asList(
|
||||
getSubscriptionInfoForSubId(INITIAL_SUB_ID_1),
|
||||
getSubscriptionInfoForSubId(INITIAL_SUB_ID_2));
|
||||
when(mSubscriptionManager.getSubscriptionsInGroup(eq(SUB_GROUP)))
|
||||
.thenReturn(initialSubInfos);
|
||||
|
||||
mUnderlyingNetworkTracker =
|
||||
new UnderlyingNetworkTracker(
|
||||
mVcnContext,
|
||||
SUB_GROUP,
|
||||
Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
|
||||
mNetworkTrackerCb);
|
||||
}
|
||||
|
||||
private static LinkProperties getLinkPropertiesWithName(String iface) {
|
||||
LinkProperties linkProperties = new LinkProperties();
|
||||
linkProperties.setInterfaceName(iface);
|
||||
return linkProperties;
|
||||
}
|
||||
|
||||
private SubscriptionInfo getSubscriptionInfoForSubId(int subId) {
|
||||
SubscriptionInfo subInfo = mock(SubscriptionInfo.class);
|
||||
when(subInfo.getSubscriptionId()).thenReturn(subId);
|
||||
return subInfo;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkCallbacksRegisteredOnStartup() {
|
||||
// verify NetworkCallbacks registered when instantiated
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getWifiRequest()),
|
||||
any(),
|
||||
any(NetworkBringupCallback.class));
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getCellRequestForSubId(INITIAL_SUB_ID_1)),
|
||||
any(),
|
||||
any(NetworkBringupCallback.class));
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getCellRequestForSubId(INITIAL_SUB_ID_2)),
|
||||
any(),
|
||||
any(NetworkBringupCallback.class));
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getRouteSelectionRequest()),
|
||||
any(),
|
||||
any(RouteSelectionCallback.class));
|
||||
|
||||
verify(mSubscriptionManager).getSubscriptionsInGroup(eq(SUB_GROUP));
|
||||
}
|
||||
|
||||
private NetworkRequest getWifiRequest() {
|
||||
return getExpectedRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
.build();
|
||||
}
|
||||
|
||||
private NetworkRequest getCellRequestForSubId(int subId) {
|
||||
return getExpectedRequestBase()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
|
||||
.build();
|
||||
}
|
||||
|
||||
private NetworkRequest getRouteSelectionRequest() {
|
||||
return getExpectedRequestBase().build();
|
||||
}
|
||||
|
||||
private NetworkRequest.Builder getExpectedRequestBase() {
|
||||
return new NetworkRequest.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||
.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
.unregisterNetworkCallback(any(NetworkBringupCallback.class));
|
||||
verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnderlyingNetworkRecordEquals() {
|
||||
UnderlyingNetworkRecord recordA =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
UnderlyingNetworkRecord recordB =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
UnderlyingNetworkRecord recordC =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
UPDATED_NETWORK_CAPABILITIES,
|
||||
UPDATED_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
|
||||
assertEquals(recordA, recordB);
|
||||
assertNotEquals(recordA, recordC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackNotifiedForNetworkChange() {
|
||||
verifyRegistrationOnAvailableAndGetCallback();
|
||||
}
|
||||
|
||||
private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback() {
|
||||
return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES);
|
||||
}
|
||||
|
||||
private RouteSelectionCallback verifyRegistrationOnAvailableAndGetCallback(
|
||||
NetworkCapabilities networkCapabilities) {
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getRouteSelectionRequest()),
|
||||
any(),
|
||||
mRouteSelectionCallbackCaptor.capture());
|
||||
|
||||
RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue();
|
||||
cb.onAvailable(mNetwork);
|
||||
cb.onCapabilitiesChanged(mNetwork, networkCapabilities);
|
||||
cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES);
|
||||
cb.onBlockedStatusChanged(mNetwork, false /* isFalse */);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
networkCapabilities,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
return cb;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() {
|
||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
UPDATED_NETWORK_CAPABILITIES,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() {
|
||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
UPDATED_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
|
||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onNetworkSuspended(mNetwork);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
SUSPENDED_NETWORK_CAPABILITIES,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackNotifiedForNetworkResumed() {
|
||||
RouteSelectionCallback cb =
|
||||
verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
|
||||
|
||||
cb.onNetworkResumed(mNetwork);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
false /* isBlocked */);
|
||||
verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackNotifiedForBlocked() {
|
||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
|
||||
|
||||
UnderlyingNetworkRecord expectedRecord =
|
||||
new UnderlyingNetworkRecord(
|
||||
mNetwork,
|
||||
INITIAL_NETWORK_CAPABILITIES,
|
||||
INITIAL_LINK_PROPERTIES,
|
||||
true /* isBlocked */);
|
||||
verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackNotifiedForNetworkLoss() {
|
||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onLost(mNetwork);
|
||||
|
||||
verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordTrackerCallbackIgnoresDuplicateRecord() {
|
||||
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
|
||||
|
||||
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
|
||||
|
||||
// Verify no more calls to the UnderlyingNetworkTrackerCallback when the
|
||||
// UnderlyingNetworkRecord does not actually change
|
||||
verifyNoMoreInteractions(mNetworkTrackerCb);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ public class VcnGatewayConnectionTestBase {
|
||||
|
||||
doReturn(mUnderlyingNetworkTracker)
|
||||
.when(mDeps)
|
||||
.newUnderlyingNetworkTracker(any(), any(), any());
|
||||
.newUnderlyingNetworkTracker(any(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
||||
Reference in New Issue
Block a user