Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b075451 authored by Cody Kesting's avatar Cody Kesting
Browse files

Notify UnderlyingNetworkTracker for Subscription changes.

This CL updates VcnManagementService to notify active VCNs when it is
notified of subscription changes by TelephonySubscriptionTracker. These
subscription changes are passed down to each VCN's
UnderlyingNetworkTracker, which determines whether it needs to register
or unregister bringup NetworkRequests based on subIds within that VCN's
Subscription Group.

Bug: 177364490
Test: atest FrameworksVcnTests
Change-Id: I15bc9aaf3d5f97046d0ce9fcf1e12c9b1e0e1446
parent 9a59faa3
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -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())) {
@@ -399,6 +401,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                                }
                            }
                        }, 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);
                    }
                }
            }
@@ -412,7 +417,7 @@ 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);
    }

+49 −33
Original line number Diff line number Diff line
@@ -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;

@@ -59,27 +58,29 @@ public class UnderlyingNetworkTracker {
    @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;

    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 +89,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 +106,6 @@ public class UnderlyingNetworkTracker {
        mHandler = new Handler(mVcnContext.getLooper());

        mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
        mSubscriptionManager = mVcnContext.getContext().getSystemService(SubscriptionManager.class);

        registerNetworkRequests();
    }
@@ -149,34 +151,47 @@ public class UnderlyingNetworkTracker {
    private void updateSubIdsAndCellularRequests() {
        mVcnContext.ensureRunningOnLooperThread();

        Set<Integer> prevSubIds = new ArraySet<>(mSubIds);
        mSubIds.clear();
        // Don't bother re-filing NetworkRequests if this Tracker has been torn down.
        if (!mIsRunning) {
            return;
        }

        // Ensure NetworkRequests filed for all current subIds in mSubscriptionGroup
        // STOPSHIP: b/177364490 use TelephonySubscriptionSnapshot to avoid querying Telephony
        List<SubscriptionInfo> subInfos =
                mSubscriptionManager.getSubscriptionsInGroup(mSubscriptionGroup);
        final Set<Integer> subIdsInSubGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup);

        for (SubscriptionInfo subInfo : subInfos) {
            final int subId = subInfo.getSubscriptionId();
            mSubIds.add(subId);
        // new subIds to track = (updated list of subIds) - (currently tracked subIds)
        final Set<Integer> subIdsToRegister = new ArraySet<>(subIdsInSubGroup);
        subIdsToRegister.removeAll(mCellBringupCallbacks.keySet());

            if (!mCellBringupCallbacks.contains(subId)) {
        // 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);
        }
        }

        // unregister all NetworkCallbacks for outdated subIds
        for (final int subId : prevSubIds) {
            if (!mSubIds.contains(subId)) {
                final NetworkCallback cb = mCellBringupCallbacks.removeReturnOld(subId);
        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 +201,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. */
+41 −3
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.os.Message;
import android.os.ParcelUuid;
import android.util.Slog;

import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -63,6 +65,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 +87,23 @@ 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(
            @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 +112,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,6 +125,13 @@ 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));
@@ -137,6 +159,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;
@@ -193,12 +218,25 @@ public class Vcn extends Handler {

                final VcnGatewayConnection vcnGatewayConnection =
                        new VcnGatewayConnection(
                                mVcnContext, mSubscriptionGroup, gatewayConnectionConfig);
                                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();
+52 −3
Original line number Diff line number Diff line
@@ -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. */
+11 −4
Original line number Diff line number Diff line
@@ -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,8 +304,10 @@ public class VcnManagementServiceTest {

    @Test
    public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
        TelephonySubscriptionSnapshot snapshot =
                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
        verify(mMockDeps).newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG));
        verify(mMockDeps)
                .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot));
    }

    @Test
@@ -473,7 +475,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);
Loading