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:
Cody Kesting
2021-02-04 18:26:09 +00:00
committed by Automerger Merge Worker
11 changed files with 480 additions and 109 deletions

View File

@@ -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();
}

View File

@@ -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. */

View File

@@ -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);
}
}
}

View File

@@ -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. */

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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));
}
}

View File

@@ -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 {

View 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));
}
}
}