Merge changes I03be15d6,Ie1671925,Ie87f4aa3,I24474419,I15bc9aaf am: 6d02108df5
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1569845 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I271653dfbcffcccc49884c8c5ae345c242580abd
This commit is contained in:
@@ -290,8 +290,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
public Vcn newVcn(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull VcnConfig config) {
|
||||
return new Vcn(vcnContext, subscriptionGroup, config);
|
||||
@NonNull VcnConfig config,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
return new Vcn(vcnContext, subscriptionGroup, config, snapshot);
|
||||
}
|
||||
|
||||
/** Gets the subId indicated by the given {@link WifiInfo}. */
|
||||
@@ -382,6 +383,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
// delay)
|
||||
for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
|
||||
final VcnConfig config = mConfigs.get(entry.getKey());
|
||||
|
||||
if (config == null
|
||||
|| !snapshot.packageHasPermissionsForSubscriptionGroup(
|
||||
entry.getKey(), config.getProvisioningPackageName())) {
|
||||
@@ -395,16 +397,40 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
// correct instance is torn down. This could happen as a result of a
|
||||
// Carrier App manually removing/adding a VcnConfig.
|
||||
if (mVcns.get(uuidToTeardown) == instanceToTeardown) {
|
||||
mVcns.remove(uuidToTeardown).teardownAsynchronously();
|
||||
stopVcnLocked(uuidToTeardown);
|
||||
}
|
||||
}
|
||||
}, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
|
||||
} else {
|
||||
// If this VCN's status has not changed, update it with the new snapshot
|
||||
entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) {
|
||||
final Vcn vcnToTeardown = mVcns.remove(uuidToTeardown);
|
||||
if (vcnToTeardown == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
vcnToTeardown.teardownAsynchronously();
|
||||
|
||||
// Now that the VCN is removed, notify all registered listeners to refresh their
|
||||
// UnderlyingNetworkPolicy.
|
||||
notifyAllPolicyListenersLocked();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void notifyAllPolicyListenersLocked() {
|
||||
for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) {
|
||||
Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged());
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
|
||||
Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
|
||||
@@ -412,8 +438,12 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
// TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
|
||||
// VCN.
|
||||
|
||||
final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config);
|
||||
final Vcn newInstance = mDeps.newVcn(mVcnContext, subscriptionGroup, config, mLastSnapshot);
|
||||
mVcns.put(subscriptionGroup, newInstance);
|
||||
|
||||
// Now that a new VCN has started, notify all registered listeners to refresh their
|
||||
// UnderlyingNetworkPolicy.
|
||||
notifyAllPolicyListenersLocked();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@@ -476,9 +506,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
synchronized (mLock) {
|
||||
mConfigs.remove(subscriptionGroup);
|
||||
|
||||
if (mVcns.containsKey(subscriptionGroup)) {
|
||||
mVcns.remove(subscriptionGroup).teardownAsynchronously();
|
||||
}
|
||||
stopVcnLocked(subscriptionGroup);
|
||||
|
||||
writeConfigsToDiskLocked();
|
||||
}
|
||||
|
||||
@@ -28,16 +28,15 @@ 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.ArrayMap;
|
||||
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 com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -55,19 +54,18 @@ public class UnderlyingNetworkTracker {
|
||||
|
||||
@NonNull private final VcnContext mVcnContext;
|
||||
@NonNull private final ParcelUuid mSubscriptionGroup;
|
||||
@NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
|
||||
@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 Map<Integer, NetworkCallback> mCellBringupCallbacks = new ArrayMap<>();
|
||||
@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;
|
||||
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
|
||||
private boolean mIsRunning = true;
|
||||
|
||||
@Nullable private UnderlyingNetworkRecord mCurrentRecord;
|
||||
@Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
|
||||
@@ -75,11 +73,13 @@ public class UnderlyingNetworkTracker {
|
||||
public UnderlyingNetworkTracker(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
|
||||
@NonNull UnderlyingNetworkTrackerCallback cb) {
|
||||
this(
|
||||
vcnContext,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
requiredUnderlyingNetworkCapabilities,
|
||||
cb,
|
||||
new Dependencies());
|
||||
@@ -88,11 +88,13 @@ public class UnderlyingNetworkTracker {
|
||||
private UnderlyingNetworkTracker(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
|
||||
@NonNull UnderlyingNetworkTrackerCallback cb,
|
||||
@NonNull Dependencies deps) {
|
||||
mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
|
||||
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
|
||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
mRequiredUnderlyingNetworkCapabilities =
|
||||
Objects.requireNonNull(
|
||||
requiredUnderlyingNetworkCapabilities,
|
||||
@@ -103,7 +105,6 @@ public class UnderlyingNetworkTracker {
|
||||
mHandler = new Handler(mVcnContext.getLooper());
|
||||
|
||||
mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
|
||||
mSubscriptionManager = mVcnContext.getContext().getSystemService(SubscriptionManager.class);
|
||||
|
||||
registerNetworkRequests();
|
||||
}
|
||||
@@ -149,34 +150,47 @@ public class 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);
|
||||
}
|
||||
// Don't bother re-filing NetworkRequests if this Tracker has been torn down.
|
||||
if (!mIsRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unregister all NetworkCallbacks for outdated subIds
|
||||
for (final int subId : prevSubIds) {
|
||||
if (!mSubIds.contains(subId)) {
|
||||
final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
|
||||
mConnectivityManager.unregisterNetworkCallback(cb);
|
||||
}
|
||||
final Set<Integer> subIdsInSubGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup);
|
||||
|
||||
// new subIds to track = (updated list of subIds) - (currently tracked subIds)
|
||||
final Set<Integer> subIdsToRegister = new ArraySet<>(subIdsInSubGroup);
|
||||
subIdsToRegister.removeAll(mCellBringupCallbacks.keySet());
|
||||
|
||||
// subIds to stop tracking = (currently tracked subIds) - (updated list of subIds)
|
||||
final Set<Integer> subIdsToUnregister = new ArraySet<>(mCellBringupCallbacks.keySet());
|
||||
subIdsToUnregister.removeAll(subIdsInSubGroup);
|
||||
|
||||
for (final int subId : subIdsToRegister) {
|
||||
final NetworkBringupCallback cb = new NetworkBringupCallback();
|
||||
mCellBringupCallbacks.put(subId, cb);
|
||||
|
||||
mConnectivityManager.requestBackgroundNetwork(
|
||||
getCellNetworkRequestForSubId(subId), mHandler, cb);
|
||||
}
|
||||
|
||||
for (final int subId : subIdsToUnregister) {
|
||||
final NetworkCallback cb = mCellBringupCallbacks.remove(subId);
|
||||
mConnectivityManager.unregisterNetworkCallback(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot.
|
||||
*
|
||||
* <p>Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkTracker to
|
||||
* reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered
|
||||
* or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change.
|
||||
*/
|
||||
public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
|
||||
mLastSnapshot = snapshot;
|
||||
updateSubIdsAndCellularRequests();
|
||||
}
|
||||
|
||||
/** Tears down this Tracker, and releases all underlying network requests. */
|
||||
@@ -186,11 +200,12 @@ public class UnderlyingNetworkTracker {
|
||||
mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback);
|
||||
mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback);
|
||||
|
||||
for (final int subId : mSubIds) {
|
||||
final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
|
||||
for (final NetworkCallback cb : mCellBringupCallbacks.values()) {
|
||||
mConnectivityManager.unregisterNetworkCallback(cb);
|
||||
}
|
||||
mSubIds.clear();
|
||||
mCellBringupCallbacks.clear();
|
||||
|
||||
mIsRunning = false;
|
||||
}
|
||||
|
||||
/** Returns whether the currently selected Network matches the given network. */
|
||||
|
||||
@@ -27,9 +27,16 @@ import android.os.Message;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents an single instance of a VCN.
|
||||
@@ -63,6 +70,15 @@ public class Vcn extends Handler {
|
||||
*/
|
||||
private static final int MSG_EVENT_NETWORK_REQUESTED = MSG_EVENT_BASE + 1;
|
||||
|
||||
/**
|
||||
* The TelephonySubscriptionSnapshot tracked by VcnManagementService has changed.
|
||||
*
|
||||
* <p>This updated snapshot should be cached locally and passed to all VcnGatewayConnections.
|
||||
*
|
||||
* @param obj TelephonySubscriptionSnapshot
|
||||
*/
|
||||
private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2;
|
||||
|
||||
/** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
|
||||
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
|
||||
|
||||
@@ -76,20 +92,24 @@ public class Vcn extends Handler {
|
||||
new HashMap<>();
|
||||
|
||||
@NonNull private VcnConfig mConfig;
|
||||
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
|
||||
|
||||
private boolean mIsRunning = true;
|
||||
|
||||
public Vcn(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull VcnConfig config) {
|
||||
this(vcnContext, subscriptionGroup, config, new Dependencies());
|
||||
@NonNull VcnConfig config,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
this(vcnContext, subscriptionGroup, config, snapshot, new Dependencies());
|
||||
}
|
||||
|
||||
private Vcn(
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public Vcn(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull VcnConfig config,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull Dependencies deps) {
|
||||
super(Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
||||
mVcnContext = vcnContext;
|
||||
@@ -98,6 +118,7 @@ public class Vcn extends Handler {
|
||||
mRequestListener = new VcnNetworkRequestListener();
|
||||
|
||||
mConfig = Objects.requireNonNull(config, "Missing config");
|
||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
|
||||
// Register to receive cached and future NetworkRequests
|
||||
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
|
||||
@@ -110,11 +131,24 @@ public class Vcn extends Handler {
|
||||
sendMessage(obtainMessage(MSG_EVENT_CONFIG_UPDATED, config));
|
||||
}
|
||||
|
||||
/** Asynchronously updates the Subscription snapshot for this VCN. */
|
||||
public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
|
||||
sendMessage(obtainMessage(MSG_EVENT_SUBSCRIPTIONS_CHANGED, snapshot));
|
||||
}
|
||||
|
||||
/** Asynchronously tears down this Vcn instance, including VcnGatewayConnection(s) */
|
||||
public void teardownAsynchronously() {
|
||||
sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN));
|
||||
}
|
||||
|
||||
/** Get current Gateways for testing purposes */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public Set<VcnGatewayConnection> getVcnGatewayConnections() {
|
||||
return Collections.unmodifiableSet(new HashSet<>(mVcnGatewayConnections.values()));
|
||||
}
|
||||
|
||||
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
|
||||
@Override
|
||||
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
|
||||
@@ -137,6 +171,9 @@ public class Vcn extends Handler {
|
||||
case MSG_EVENT_NETWORK_REQUESTED:
|
||||
handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
|
||||
break;
|
||||
case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
|
||||
handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
|
||||
break;
|
||||
case MSG_CMD_TEARDOWN:
|
||||
handleTeardown();
|
||||
break;
|
||||
@@ -192,13 +229,26 @@ public class Vcn extends Handler {
|
||||
"Bringing up new VcnGatewayConnection for request " + request.requestId);
|
||||
|
||||
final VcnGatewayConnection vcnGatewayConnection =
|
||||
new VcnGatewayConnection(
|
||||
mVcnContext, mSubscriptionGroup, gatewayConnectionConfig);
|
||||
mDeps.newVcnGatewayConnection(
|
||||
mVcnContext,
|
||||
mSubscriptionGroup,
|
||||
mLastSnapshot,
|
||||
gatewayConnectionConfig);
|
||||
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
mLastSnapshot = snapshot;
|
||||
|
||||
if (mIsRunning) {
|
||||
for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
|
||||
gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requestSatisfiedByGatewayConnectionConfig(
|
||||
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
|
||||
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
|
||||
@@ -221,5 +271,17 @@ public class Vcn extends Handler {
|
||||
return 52;
|
||||
}
|
||||
|
||||
private static class Dependencies {}
|
||||
/** External dependencies used by Vcn, for injection in tests */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static class Dependencies {
|
||||
/** Builds a new VcnGatewayConnection */
|
||||
public VcnGatewayConnection newVcnGatewayConnection(
|
||||
VcnContext vcnContext,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
VcnGatewayConnectionConfig connectionConfig) {
|
||||
return new VcnGatewayConnection(
|
||||
vcnContext, subscriptionGroup, snapshot, connectionConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +61,12 @@ import android.os.ParcelUuid;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.internal.util.StateMachine;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
|
||||
|
||||
@@ -371,6 +373,16 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
*/
|
||||
private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8;
|
||||
|
||||
/**
|
||||
* Sent when this VcnGatewayConnection is notified of a change in TelephonySubscriptions.
|
||||
*
|
||||
* <p>Relevant in all states.
|
||||
*
|
||||
* @param arg1 The "all" token; this signal is always honored.
|
||||
*/
|
||||
// TODO(b/178426520): implement handling of this event
|
||||
private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9;
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
@NonNull
|
||||
final DisconnectedState mDisconnectedState = new DisconnectedState();
|
||||
@@ -391,6 +403,11 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@NonNull
|
||||
final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
|
||||
|
||||
@NonNull private final Object mLock = new Object();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
|
||||
|
||||
@NonNull private final VcnContext mVcnContext;
|
||||
@NonNull private final ParcelUuid mSubscriptionGroup;
|
||||
@NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
|
||||
@@ -469,14 +486,16 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
public VcnGatewayConnection(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull VcnGatewayConnectionConfig connectionConfig) {
|
||||
this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies());
|
||||
this(vcnContext, subscriptionGroup, snapshot, connectionConfig, new Dependencies());
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
VcnGatewayConnection(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
||||
@NonNull Dependencies deps) {
|
||||
super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
||||
@@ -485,12 +504,17 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
|
||||
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
||||
|
||||
synchronized (mLock) {
|
||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
}
|
||||
|
||||
mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback();
|
||||
|
||||
mUnderlyingNetworkTracker =
|
||||
mDeps.newUnderlyingNetworkTracker(
|
||||
mVcnContext,
|
||||
subscriptionGroup,
|
||||
mLastSnapshot,
|
||||
mConnectionConfig.getAllUnderlyingCapabilities(),
|
||||
mUnderlyingNetworkTrackerCallback);
|
||||
mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
|
||||
@@ -545,6 +569,25 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
mUnderlyingNetworkTracker.teardown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify this Gateway that subscriptions have changed.
|
||||
*
|
||||
* <p>This snapshot should be used to update any keepalive requests necessary for potential
|
||||
* underlying Networks in this Gateway's subscription group.
|
||||
*/
|
||||
public void updateSubscriptionSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
|
||||
// Vcn is the only user of this method and runs on the same Thread, but lock around
|
||||
// mLastSnapshot to be technically correct.
|
||||
synchronized (mLock) {
|
||||
mLastSnapshot = snapshot;
|
||||
mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot);
|
||||
}
|
||||
|
||||
sendMessage(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL);
|
||||
}
|
||||
|
||||
private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
|
||||
@Override
|
||||
public void onSelectedUnderlyingNetworkChanged(
|
||||
@@ -682,7 +725,8 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
case EVENT_TRANSFORM_CREATED: // Fallthrough
|
||||
case EVENT_SETUP_COMPLETED: // Fallthrough
|
||||
case EVENT_DISCONNECT_REQUESTED: // Fallthrough
|
||||
case EVENT_TEARDOWN_TIMEOUT_EXPIRED:
|
||||
case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough
|
||||
case EVENT_SUBSCRIPTIONS_CHANGED:
|
||||
logUnexpectedEvent(msg.what);
|
||||
break;
|
||||
default:
|
||||
@@ -1384,10 +1428,15 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
public UnderlyingNetworkTracker newUnderlyingNetworkTracker(
|
||||
VcnContext vcnContext,
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
Set<Integer> requiredUnderlyingNetworkCapabilities,
|
||||
UnderlyingNetworkTrackerCallback callback) {
|
||||
return new UnderlyingNetworkTracker(
|
||||
vcnContext, subscriptionGroup, requiredUnderlyingNetworkCapabilities, callback);
|
||||
vcnContext,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
requiredUnderlyingNetworkCapabilities,
|
||||
callback);
|
||||
}
|
||||
|
||||
/** Builds a new IkeSession. */
|
||||
|
||||
@@ -25,6 +25,9 @@ import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -52,8 +55,13 @@ public class VcnNetworkProvider extends NetworkProvider {
|
||||
super(context, looper, VcnNetworkProvider.class.getSimpleName());
|
||||
}
|
||||
|
||||
// Package-private
|
||||
void registerListener(@NonNull NetworkRequestListener listener) {
|
||||
/**
|
||||
* Registers a NetworkRequestListener with this NetworkProvider.
|
||||
*
|
||||
* <p>Upon registering, the provided listener will receive all cached requests.
|
||||
*/
|
||||
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
||||
public void registerListener(@NonNull NetworkRequestListener listener) {
|
||||
mListeners.add(listener);
|
||||
|
||||
// Send listener all cached requests
|
||||
@@ -62,8 +70,9 @@ public class VcnNetworkProvider extends NetworkProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// Package-private
|
||||
void unregisterListener(@NonNull NetworkRequestListener listener) {
|
||||
/** Unregisters the specified listener from receiving future NetworkRequests. */
|
||||
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
||||
public void unregisterListener(@NonNull NetworkRequestListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ public class VcnManagementServiceTest {
|
||||
doAnswer((invocation) -> {
|
||||
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
|
||||
return mock(Vcn.class);
|
||||
}).when(mMockDeps).newVcn(any(), any(), any());
|
||||
}).when(mMockDeps).newVcn(any(), any(), any(), any());
|
||||
|
||||
final PersistableBundle bundle =
|
||||
PersistableBundleUtils.fromMap(
|
||||
@@ -304,14 +304,17 @@ public class VcnManagementServiceTest {
|
||||
|
||||
@Test
|
||||
public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
|
||||
verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG));
|
||||
TelephonySubscriptionSnapshot snapshot =
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
|
||||
verify(mMockDeps)
|
||||
.newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception {
|
||||
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
|
||||
final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
|
||||
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
|
||||
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
|
||||
|
||||
@@ -319,6 +322,7 @@ public class VcnManagementServiceTest {
|
||||
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
|
||||
mTestLooper.dispatchAll();
|
||||
verify(vcn).teardownAsynchronously();
|
||||
verify(mMockPolicyListener).onPolicyChanged();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -389,6 +393,7 @@ public class VcnManagementServiceTest {
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
fail("Expected security exception for non system user");
|
||||
} catch (SecurityException expected) {
|
||||
verify(mMockPolicyListener, never()).onPolicyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,6 +405,7 @@ public class VcnManagementServiceTest {
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
fail("Expected security exception for missing carrier privileges");
|
||||
} catch (SecurityException expected) {
|
||||
verify(mMockPolicyListener, never()).onPolicyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,6 +415,7 @@ public class VcnManagementServiceTest {
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage");
|
||||
fail("Expected exception due to mismatched packages in config and method call");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
verify(mMockPolicyListener, never()).onPolicyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +480,12 @@ public class VcnManagementServiceTest {
|
||||
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
|
||||
|
||||
// Verify Vcn is started
|
||||
verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG));
|
||||
verify(mMockDeps)
|
||||
.newVcn(
|
||||
eq(mVcnContext),
|
||||
eq(TEST_UUID_2),
|
||||
eq(TEST_VCN_CONFIG),
|
||||
eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT));
|
||||
|
||||
// Verify Vcn is updated if it was previously started
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
@@ -520,7 +532,7 @@ public class VcnManagementServiceTest {
|
||||
Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup));
|
||||
}
|
||||
|
||||
private void verifyMergedNetworkCapabilities(
|
||||
private void verifyMergedNetworkCapabilitiesIsVcnManaged(
|
||||
NetworkCapabilities mergedCapabilities, @Transport int transportType) {
|
||||
assertTrue(mergedCapabilities.hasTransport(transportType));
|
||||
assertFalse(
|
||||
@@ -529,7 +541,7 @@ public class VcnManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnderlyingNetworkPolicyTransportCell() throws Exception {
|
||||
public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
|
||||
setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
|
||||
|
||||
NetworkCapabilities nc =
|
||||
@@ -542,12 +554,12 @@ public class VcnManagementServiceTest {
|
||||
mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
|
||||
|
||||
assertFalse(policy.isTeardownRequested());
|
||||
verifyMergedNetworkCapabilities(
|
||||
verifyMergedNetworkCapabilitiesIsVcnManaged(
|
||||
policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnderlyingNetworkPolicyTransportWifi() throws Exception {
|
||||
public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
|
||||
setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
|
||||
|
||||
WifiInfo wifiInfo = mock(WifiInfo.class);
|
||||
@@ -563,7 +575,7 @@ public class VcnManagementServiceTest {
|
||||
mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
|
||||
|
||||
assertFalse(policy.isTeardownRequested());
|
||||
verifyMergedNetworkCapabilities(
|
||||
verifyMergedNetworkCapabilitiesIsVcnManaged(
|
||||
policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI);
|
||||
}
|
||||
|
||||
@@ -591,4 +603,35 @@ public class VcnManagementServiceTest {
|
||||
|
||||
mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionSnapshotUpdateNotifiesVcn() {
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
|
||||
final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
|
||||
|
||||
TelephonySubscriptionSnapshot snapshot =
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
|
||||
|
||||
verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNewVcnUpdatesPolicyListener() throws Exception {
|
||||
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
|
||||
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
|
||||
verify(mMockPolicyListener).onPolicyChanged();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveVcnUpdatesPolicyListener() throws Exception {
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
|
||||
|
||||
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
|
||||
|
||||
verify(mMockPolicyListener).onPolicyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,9 @@ import android.net.TelephonyNetworkSpecifier;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.RouteSelectionCallback;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
|
||||
@@ -58,13 +59,19 @@ import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
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 int UPDATED_SUB_ID = 3;
|
||||
|
||||
private static final Set<Integer> INITIAL_SUB_IDS =
|
||||
new ArraySet<>(Arrays.asList(INITIAL_SUB_ID_1, INITIAL_SUB_ID_2));
|
||||
private static final Set<Integer> UPDATED_SUB_IDS =
|
||||
new ArraySet<>(Arrays.asList(UPDATED_SUB_ID));
|
||||
|
||||
private static final NetworkCapabilities INITIAL_NETWORK_CAPABILITIES =
|
||||
new NetworkCapabilities.Builder()
|
||||
@@ -90,7 +97,7 @@ public class UnderlyingNetworkTrackerTest {
|
||||
@Mock private Context mContext;
|
||||
@Mock private VcnNetworkProvider mVcnNetworkProvider;
|
||||
@Mock private ConnectivityManager mConnectivityManager;
|
||||
@Mock private SubscriptionManager mSubscriptionManager;
|
||||
@Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
||||
@Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
|
||||
@Mock private Network mNetwork;
|
||||
|
||||
@@ -113,23 +120,14 @@ public class UnderlyingNetworkTrackerTest {
|
||||
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);
|
||||
when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS);
|
||||
|
||||
mUnderlyingNetworkTracker =
|
||||
new UnderlyingNetworkTracker(
|
||||
mVcnContext,
|
||||
SUB_GROUP,
|
||||
mSubscriptionSnapshot,
|
||||
Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
|
||||
mNetworkTrackerCb);
|
||||
}
|
||||
@@ -154,23 +152,45 @@ public class UnderlyingNetworkTrackerTest {
|
||||
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));
|
||||
verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS);
|
||||
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getRouteSelectionRequest()),
|
||||
any(),
|
||||
any(RouteSelectionCallback.class));
|
||||
}
|
||||
|
||||
verify(mSubscriptionManager).getSubscriptionsInGroup(eq(SUB_GROUP));
|
||||
private void verifyBackgroundCellRequests(
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
ParcelUuid subGroup,
|
||||
Set<Integer> expectedSubIds) {
|
||||
verify(snapshot).getAllSubIdsInGroup(eq(subGroup));
|
||||
|
||||
for (final int subId : expectedSubIds) {
|
||||
verify(mConnectivityManager)
|
||||
.requestBackgroundNetwork(
|
||||
eq(getCellRequestForSubId(subId)),
|
||||
any(),
|
||||
any(NetworkBringupCallback.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateSubscriptionSnapshot() {
|
||||
// Verify initial cell background requests filed
|
||||
verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS);
|
||||
|
||||
TelephonySubscriptionSnapshot subscriptionUpdate =
|
||||
mock(TelephonySubscriptionSnapshot.class);
|
||||
when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS);
|
||||
|
||||
mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
|
||||
|
||||
// verify that initially-filed bringup requests are unregistered
|
||||
verify(mConnectivityManager, times(INITIAL_SUB_IDS.size()))
|
||||
.unregisterNetworkCallback(any(NetworkBringupCallback.class));
|
||||
verifyBackgroundCellRequests(subscriptionUpdate, SUB_GROUP, UPDATED_SUB_IDS);
|
||||
}
|
||||
|
||||
private NetworkRequest getWifiRequest() {
|
||||
|
||||
@@ -44,7 +44,8 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
||||
@Test
|
||||
public void testEnterWhileNotRunningTriggersQuit() throws Exception {
|
||||
final VcnGatewayConnection vgc =
|
||||
new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
|
||||
new VcnGatewayConnection(
|
||||
mVcnContext, TEST_SUB_GRP, TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mDeps);
|
||||
|
||||
vgc.setIsRunning(false);
|
||||
vgc.transitionTo(vgc.mDisconnectedState);
|
||||
|
||||
@@ -24,10 +24,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
@@ -37,14 +37,15 @@ import android.net.vcn.VcnTransportInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.Process;
|
||||
import android.os.test.TestLooper;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -56,8 +57,9 @@ import java.util.UUID;
|
||||
/** Tests for TelephonySubscriptionTracker */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class VcnGatewayConnectionTest {
|
||||
public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
||||
private static final int TEST_UID = Process.myUid();
|
||||
|
||||
private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
|
||||
private static final int TEST_SIM_SLOT_INDEX = 1;
|
||||
private static final int TEST_SUBSCRIPTION_ID_1 = 2;
|
||||
@@ -73,17 +75,12 @@ public class VcnGatewayConnectionTest {
|
||||
TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap);
|
||||
}
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final TestLooper mTestLooper;
|
||||
@NonNull private final VcnNetworkProvider mVcnNetworkProvider;
|
||||
@NonNull private final VcnGatewayConnection.Dependencies mDeps;
|
||||
@NonNull private final WifiInfo mWifiInfo;
|
||||
private WifiInfo mWifiInfo;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
public VcnGatewayConnectionTest() {
|
||||
mContext = mock(Context.class);
|
||||
mTestLooper = new TestLooper();
|
||||
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
|
||||
mDeps = mock(VcnGatewayConnection.Dependencies.class);
|
||||
mWifiInfo = mock(WifiInfo.class);
|
||||
}
|
||||
|
||||
@@ -132,4 +129,13 @@ public class VcnGatewayConnectionTest {
|
||||
public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception {
|
||||
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() {
|
||||
final TelephonySubscriptionSnapshot updatedSnapshot =
|
||||
mock(TelephonySubscriptionSnapshot.class);
|
||||
mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot);
|
||||
|
||||
verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,12 @@ import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
|
||||
import com.android.server.IpSecService;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
public class VcnGatewayConnectionTestBase {
|
||||
@@ -54,6 +56,7 @@ public class VcnGatewayConnectionTestBase {
|
||||
protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
|
||||
protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2;
|
||||
protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 3;
|
||||
protected static final int TEST_SUB_ID = 5;
|
||||
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
|
||||
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
|
||||
new UnderlyingNetworkRecord(
|
||||
@@ -68,6 +71,10 @@ public class VcnGatewayConnectionTestBase {
|
||||
new LinkProperties(),
|
||||
false /* blocked */);
|
||||
|
||||
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
|
||||
new TelephonySubscriptionSnapshot(
|
||||
Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP);
|
||||
|
||||
@NonNull protected final Context mContext;
|
||||
@NonNull protected final TestLooper mTestLooper;
|
||||
@NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
|
||||
@@ -99,7 +106,7 @@ public class VcnGatewayConnectionTestBase {
|
||||
|
||||
doReturn(mUnderlyingNetworkTracker)
|
||||
.when(mDeps)
|
||||
.newUnderlyingNetworkTracker(any(), any(), any(), any());
|
||||
.newUnderlyingNetworkTracker(any(), any(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -114,7 +121,9 @@ public class VcnGatewayConnectionTestBase {
|
||||
mMockIkeSession = mock(VcnIkeSession.class);
|
||||
doReturn(mMockIkeSession).when(mDeps).newIkeSession(any(), any(), any(), any(), any());
|
||||
|
||||
mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
|
||||
mGatewayConnection =
|
||||
new VcnGatewayConnection(
|
||||
mVcnContext, TEST_SUB_GRP, TEST_SUBSCRIPTION_SNAPSHOT, mConfig, mDeps);
|
||||
}
|
||||
|
||||
protected IpSecTransform makeDummyIpSecTransform() throws Exception {
|
||||
|
||||
129
tests/vcn/java/com/android/server/vcn/VcnTest.java
Normal file
129
tests/vcn/java/com/android/server/vcn/VcnTest.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.vcn.VcnConfig;
|
||||
import android.net.vcn.VcnGatewayConnectionConfigTest;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class VcnTest {
|
||||
private static final String PKG_NAME = VcnTest.class.getPackage().getName();
|
||||
private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
|
||||
private static final int NETWORK_SCORE = 0;
|
||||
private static final int PROVIDER_ID = 5;
|
||||
|
||||
private Context mContext;
|
||||
private VcnContext mVcnContext;
|
||||
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
||||
private VcnNetworkProvider mVcnNetworkProvider;
|
||||
private Vcn.Dependencies mDeps;
|
||||
|
||||
private TestLooper mTestLooper;
|
||||
private VcnConfig mConfig;
|
||||
private Vcn mVcn;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = mock(Context.class);
|
||||
mVcnContext = mock(VcnContext.class);
|
||||
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
|
||||
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
|
||||
mDeps = mock(Vcn.Dependencies.class);
|
||||
|
||||
mTestLooper = new TestLooper();
|
||||
|
||||
doReturn(PKG_NAME).when(mContext).getOpPackageName();
|
||||
doReturn(mContext).when(mVcnContext).getContext();
|
||||
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
|
||||
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
|
||||
|
||||
// Setup VcnGatewayConnection instance generation
|
||||
doAnswer((invocation) -> {
|
||||
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
|
||||
return mock(VcnGatewayConnection.class);
|
||||
}).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any());
|
||||
|
||||
mConfig =
|
||||
new VcnConfig.Builder(mContext)
|
||||
.addGatewayConnectionConfig(
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig())
|
||||
.build();
|
||||
|
||||
mVcn = new Vcn(mVcnContext, TEST_SUB_GROUP, mConfig, mSubscriptionSnapshot, mDeps);
|
||||
}
|
||||
|
||||
private NetworkRequestListener verifyAndGetRequestListener() {
|
||||
ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
|
||||
ArgumentCaptor.forClass(NetworkRequestListener.class);
|
||||
verify(mVcnNetworkProvider).registerListener(mNetworkRequestListenerCaptor.capture());
|
||||
|
||||
return mNetworkRequestListenerCaptor.getValue();
|
||||
}
|
||||
|
||||
private NetworkRequest getNetworkRequestWithCapabilities(int[] networkCapabilities) {
|
||||
final NetworkRequest.Builder builder = new NetworkRequest.Builder();
|
||||
for (final int netCapability : networkCapabilities) {
|
||||
builder.addCapability(netCapability);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
|
||||
requestListener.onNetworkRequested(
|
||||
getNetworkRequestWithCapabilities(VcnGatewayConnectionConfigTest.EXPOSED_CAPS),
|
||||
NETWORK_SCORE,
|
||||
PROVIDER_ID);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
|
||||
assertFalse(gatewayConnections.isEmpty());
|
||||
|
||||
final TelephonySubscriptionSnapshot updatedSnapshot =
|
||||
mock(TelephonySubscriptionSnapshot.class);
|
||||
|
||||
mVcn.updateSubscriptionSnapshot(updatedSnapshot);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
for (final VcnGatewayConnection gateway : gatewayConnections) {
|
||||
verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user