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

Commit d3f13bb5 authored by Benedict Wong's avatar Benedict Wong Committed by Automerger Merge Worker
Browse files

Merge "Limit VCNs to one running at a given time" into sc-dev am: dd6c8879

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15315835

Change-Id: I4e7b1c275f0b5e4f180ab3ff3047ed42c091a7e9
parents 27bc7789 dd6c8879
Loading
Loading
Loading
Loading
+55 −11
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static android.telephony.SubscriptionManager.isValidSubscriptionId;

import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -435,6 +436,15 @@ public class VcnManagementService extends IVcnManagementService.Stub {
        }
    }

    private boolean isActiveSubGroup(
            @NonNull ParcelUuid subGrp, @NonNull TelephonySubscriptionSnapshot snapshot) {
        if (subGrp == null || snapshot == null) {
            return false;
        }

        return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup());
    }

    private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback {
        /**
         * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker}
@@ -452,28 +462,49 @@ public class VcnManagementService extends IVcnManagementService.Stub {

                // Start any VCN instances as necessary
                for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
                    final ParcelUuid subGrp = entry.getKey();

                    // TODO(b/193687515): Support multiple VCNs active at the same time
                    if (snapshot.packageHasPermissionsForSubscriptionGroup(
                            entry.getKey(), entry.getValue().getProvisioningPackageName())) {
                        if (!mVcns.containsKey(entry.getKey())) {
                            startVcnLocked(entry.getKey(), entry.getValue());
                                    subGrp, entry.getValue().getProvisioningPackageName())
                            && isActiveSubGroup(subGrp, snapshot)) {
                        if (!mVcns.containsKey(subGrp)) {
                            startVcnLocked(subGrp, entry.getValue());
                        }

                        // Cancel any scheduled teardowns for active subscriptions
                        mHandler.removeCallbacksAndMessages(mVcns.get(entry.getKey()));
                        mHandler.removeCallbacksAndMessages(mVcns.get(subGrp));
                    }
                }

                // Schedule teardown of any VCN instances that have lost carrier privileges (after a
                // delay)
                for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
                    final VcnConfig config = mConfigs.get(entry.getKey());
                    final ParcelUuid subGrp = entry.getKey();
                    final VcnConfig config = mConfigs.get(subGrp);

                    final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot);
                    final boolean isValidActiveDataSubIdNotInVcnSubGrp =
                            isValidSubscriptionId(snapshot.getActiveDataSubscriptionId())
                                    && !isActiveSubGroup(subGrp, snapshot);

                    // TODO(b/193687515): Support multiple VCNs active at the same time
                    if (config == null
                            || !snapshot.packageHasPermissionsForSubscriptionGroup(
                                    entry.getKey(), config.getProvisioningPackageName())) {
                        final ParcelUuid uuidToTeardown = entry.getKey();
                                    subGrp, config.getProvisioningPackageName())
                            || !isActiveSubGrp) {
                        final ParcelUuid uuidToTeardown = subGrp;
                        final Vcn instanceToTeardown = entry.getValue();

                        // TODO(b/193687515): Support multiple VCNs active at the same time
                        // If directly switching to a subscription not in the current group,
                        // teardown immediately to prevent other subscription's network from being
                        // outscored by the VCN. Otherwise, teardown after a delay to ensure that
                        // SIM profile switches do not trigger the VCN to cycle.
                        final long teardownDelayMs =
                                isValidActiveDataSubIdNotInVcnSubGrp
                                        ? 0
                                        : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS;
                        mHandler.postDelayed(() -> {
                            synchronized (mLock) {
                                // Guard against case where this is run after a old instance was
@@ -489,7 +520,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
                                            uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
                                }
                            }
                        }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
                        }, instanceToTeardown, teardownDelayMs);
                    } else {
                        // If this VCN's status has not changed, update it with the new snapshot
                        entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
@@ -553,8 +584,13 @@ public class VcnManagementService extends IVcnManagementService.Stub {
    private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
        logDbg("Starting VCN config for subGrp: " + subscriptionGroup);

        // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
        //                    VCN.
        // TODO(b/193687515): Support multiple VCNs active at the same time
        if (!mVcns.isEmpty()) {
            // Only one VCN supported at a time; teardown all others before starting new one
            for (ParcelUuid uuidToTeardown : mVcns.keySet()) {
                stopVcnLocked(uuidToTeardown);
            }
        }

        final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup);

@@ -582,9 +618,12 @@ public class VcnManagementService extends IVcnManagementService.Stub {
            final Vcn vcn = mVcns.get(subscriptionGroup);
            vcn.updateConfig(config);
        } else {
            // TODO(b/193687515): Support multiple VCNs active at the same time
            if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) {
                startVcnLocked(subscriptionGroup, config);
            }
        }
    }

    /**
     * Sets a VCN config for a given subscription group.
@@ -1007,6 +1046,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
        }
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    void setLastSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
        mLastSnapshot = Objects.requireNonNull(snapshot);
    }

    private void logVdbg(String msg) {
        if (VDBG) {
            Slog.v(TAG, msg);
+51 −6
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -85,6 +86,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
    @NonNull private final SubscriptionManager mSubscriptionManager;
    @NonNull private final CarrierConfigManager mCarrierConfigManager;

    @NonNull private final ActiveDataSubscriptionIdListener mActiveDataSubIdListener;

    // TODO (Android T+): Add ability to handle multiple subIds per slot.
    @NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
    @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
@@ -112,6 +115,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
        mActiveDataSubIdListener = new ActiveDataSubscriptionIdListener();

        mSubscriptionChangedListener =
                new OnSubscriptionsChangedListener() {
@@ -124,16 +128,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {

    /** Registers the receivers, and starts tracking subscriptions. */
    public void register() {
        final HandlerExecutor executor = new HandlerExecutor(mHandler);

        mContext.registerReceiver(
                this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler);
        mSubscriptionManager.addOnSubscriptionsChangedListener(
                new HandlerExecutor(mHandler), mSubscriptionChangedListener);
                executor, mSubscriptionChangedListener);
        mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
    }

    /** Unregisters the receivers, and stops tracking subscriptions. */
    public void unregister() {
        mContext.unregisterReceiver(this);
        mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
        mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener);
    }

    /**
@@ -185,7 +193,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
        }

        final TelephonySubscriptionSnapshot newSnapshot =
                new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages);
                new TelephonySubscriptionSnapshot(
                        mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages);

        // If snapshot was meaningfully updated, fire the callback
        if (!newSnapshot.equals(mCurrentSnapshot)) {
@@ -242,16 +251,20 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {

    /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
    public static class TelephonySubscriptionSnapshot {
        private final int mActiveDataSubId;
        private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap;
        private final Map<ParcelUuid, Set<String>> mPrivilegedPackages;

        public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT =
                new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptyMap());
                new TelephonySubscriptionSnapshot(
                        INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap());

        @VisibleForTesting(visibility = Visibility.PRIVATE)
        TelephonySubscriptionSnapshot(
                int activeDataSubId,
                @NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap,
                @NonNull Map<ParcelUuid, Set<String>> privilegedPackages) {
            mActiveDataSubId = activeDataSubId;
            Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null");
            Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");

@@ -265,6 +278,22 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
            mPrivilegedPackages = Collections.unmodifiableMap(unmodifiableInnerSets);
        }

        /** Returns the active subscription ID. May be INVALID_SUBSCRIPTION_ID */
        public int getActiveDataSubscriptionId() {
            return mActiveDataSubId;
        }

        /** Returns the active subscription group */
        @Nullable
        public ParcelUuid getActiveDataSubscriptionGroup() {
            final SubscriptionInfo info = mSubIdToInfoMap.get(getActiveDataSubscriptionId());
            if (info == null) {
                return null;
            }

            return info.getGroupUuid();
        }

        /** Returns the active subscription groups */
        @NonNull
        public Set<ParcelUuid> getActiveSubscriptionGroups() {
@@ -313,7 +342,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {

        @Override
        public int hashCode() {
            return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages);
            return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages);
        }

        @Override
@@ -324,7 +353,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {

            final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj;

            return mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
            return mActiveDataSubId == other.mActiveDataSubId
                    && mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
                    && mPrivilegedPackages.equals(other.mPrivilegedPackages);
        }

@@ -333,6 +363,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
            pw.println("TelephonySubscriptionSnapshot:");
            pw.increaseIndent();

            pw.println("mActiveDataSubId: " + mActiveDataSubId);
            pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap);
            pw.println("mPrivilegedPackages: " + mPrivilegedPackages);

@@ -342,7 +373,8 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
        @Override
        public String toString() {
            return "TelephonySubscriptionSnapshot{ "
                    + "mSubIdToInfoMap=" + mSubIdToInfoMap
                    + "mActiveDataSubId=" + mActiveDataSubId
                    + ", mSubIdToInfoMap=" + mSubIdToInfoMap
                    + ", mPrivilegedPackages=" + mPrivilegedPackages
                    + " }";
        }
@@ -362,6 +394,14 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
        void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot);
    }

    private class ActiveDataSubscriptionIdListener extends TelephonyCallback
            implements TelephonyCallback.ActiveDataSubscriptionIdListener {
        @Override
        public void onActiveDataSubscriptionIdChanged(int subId) {
            handleSubscriptionsChanged();
        }
    }

    /** External static dependencies for test injection */
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public static class Dependencies {
@@ -369,5 +409,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
        public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) {
            return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle);
        }

        /** Gets the active Subscription ID */
        public int getActiveDataSubscriptionId() {
            return SubscriptionManager.getActiveDataSubscriptionId();
        }
    }
}
+204 −24

File changed.

Preview size limit exceeded, changes collapsed.

+42 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;

import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -54,6 +55,7 @@ import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArraySet;

@@ -178,6 +180,14 @@ public class TelephonySubscriptionTrackerTest {
        return captor.getValue();
    }

    private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() {
        final ArgumentCaptor<TelephonyCallback> captor =
                ArgumentCaptor.forClass(TelephonyCallback.class);
        verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture());

        return (ActiveDataSubscriptionIdListener) captor.getValue();
    }

    private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
        Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
        intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
@@ -196,7 +206,14 @@ public class TelephonySubscriptionTrackerTest {
    private TelephonySubscriptionSnapshot buildExpectedSnapshot(
            Map<Integer, SubscriptionInfo> subIdToInfoMap,
            Map<ParcelUuid, Set<String>> privilegedPackages) {
        return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages);
        return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages);
    }

    private TelephonySubscriptionSnapshot buildExpectedSnapshot(
            int activeSubId,
            Map<Integer, SubscriptionInfo> subIdToInfoMap,
            Map<ParcelUuid, Set<String>> privilegedPackages) {
        return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages);
    }

    private void verifyNoActiveSubscriptions() {
@@ -249,6 +266,26 @@ public class TelephonySubscriptionTrackerTest {
        verifyNoActiveSubscriptions();
    }

    @Test
    public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception {
        setupReadySubIds();
        setPrivilegedPackagesForMock(Collections.emptyList());

        doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId();
        final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener();
        listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2);
        mTestLooper.dispatchAll();

        ArgumentCaptor<TelephonySubscriptionSnapshot> snapshotCaptor =
                ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class);
        verify(mCallback).onNewSnapshot(snapshotCaptor.capture());

        TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue();
        assertNotNull(snapshot);
        assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId());
        assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup());
    }

    @Test
    public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages()
            throws Exception {
@@ -371,7 +408,8 @@ public class TelephonySubscriptionTrackerTest {
    @Test
    public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
        final TelephonySubscriptionSnapshot snapshot =
                new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap());
                new TelephonySubscriptionSnapshot(
                        TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());

        assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
        assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
@@ -380,7 +418,8 @@ public class TelephonySubscriptionTrackerTest {
    @Test
    public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
        final TelephonySubscriptionSnapshot snapshot =
                new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap());
                new TelephonySubscriptionSnapshot(
                        TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());

        assertEquals(
                new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
+3 −1
Original line number Diff line number Diff line
@@ -127,7 +127,9 @@ public class VcnGatewayConnectionTestBase {

    protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
            new TelephonySubscriptionSnapshot(
                    Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP);
                    TEST_SUB_ID,
                    Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO),
                    Collections.EMPTY_MAP);

    @NonNull protected final Context mContext;
    @NonNull protected final TestLooper mTestLooper;