From 31d56f82984a79b1869c79b4e8c53f7e3fb2a2fe Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 7 Jan 2022 21:05:21 +0000 Subject: [PATCH 1/2] Update TelephonySubscriptionTracker to use CarrierPrivilegesListener This change adds use for CarrierPrivilegesListener to use the callbacks as triggers to re-check carrier privileges. For simplicity, the carrier privileges returned by the callback are not used, as it requires an additional layer of caching. Instead, a query is performed, which should hit a cache in the CarrierPrivilegesTracker, thus not be performance-sensitive. Bug: 183554244 Test: atest FrameworksVcnTests Change-Id: Ia4529d087ee7f0deca7101c6849183ba7267c067 --- .../vcn/TelephonySubscriptionTracker.java | 103 ++++++++++++++++-- .../vcn/TelephonySubscriptionTrackerTest.java | 88 ++++++++++++++- 2 files changed, 179 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java index a31c56a3b7377..a17e79273e416 100644 --- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -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.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -38,15 +39,19 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.CarrierPrivilegesListener; 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 com.android.internal.util.IndentingPrintWriter; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -92,6 +97,10 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final Map mReadySubIdsBySlotId = new HashMap<>(); @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; + @NonNull + private final List mCarrierPrivilegesChangedListeners = + new ArrayList<>(); + @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot; public TelephonySubscriptionTracker( @@ -126,22 +135,71 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { }; } - /** Registers the receivers, and starts tracking subscriptions. */ + /** + * Registers the receivers, and starts tracking subscriptions. + * + *

Must always be run on the VcnManagementService thread. + */ public void register() { final HandlerExecutor executor = new HandlerExecutor(mHandler); + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); + filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED); - mContext.registerReceiver( - this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler); + mContext.registerReceiver(this, filter, null, mHandler); mSubscriptionManager.addOnSubscriptionsChangedListener( executor, mSubscriptionChangedListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); + + registerCarrierPrivilegesListeners(); } - /** Unregisters the receivers, and stops tracking subscriptions. */ + private void registerCarrierPrivilegesListeners() { + final HandlerExecutor executor = new HandlerExecutor(mHandler); + final int modemCount = mTelephonyManager.getActiveModemCount(); + try { + for (int i = 0; i < modemCount; i++) { + CarrierPrivilegesListener carrierPrivilegesListener = + new CarrierPrivilegesListener() { + @Override + public void onCarrierPrivilegesChanged( + @NonNull List privilegedPackageNames, + @NonNull int[] privilegedUids) { + // Re-trigger the synchronous check (which is also very cheap due + // to caching in CarrierPrivilegesTracker). This allows consistency + // with the onSubscriptionsChangedListener and broadcasts. + handleSubscriptionsChanged(); + } + }; + + mTelephonyManager.addCarrierPrivilegesListener( + i, executor, carrierPrivilegesListener); + mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener); + } + } catch (IllegalArgumentException e) { + Slog.wtf(TAG, "Encounted exception registering carrier privileges listeners", e); + } + } + + /** + * Unregisters the receivers, and stops tracking subscriptions. + * + *

Must always be run on the VcnManagementService thread. + */ public void unregister() { mContext.unregisterReceiver(this); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); + + unregisterCarrierPrivilegesListeners(); + } + + private void unregisterCarrierPrivilegesListeners() { + for (CarrierPrivilegesListener carrierPrivilegesListener : + mCarrierPrivilegesChangedListeners) { + mTelephonyManager.removeCarrierPrivilegesListener(carrierPrivilegesListener); + } + mCarrierPrivilegesChangedListeners.clear(); } /** @@ -178,8 +236,6 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { // group. if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX && mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) { - // TODO (b/172619301): Cache based on callbacks from CarrierPrivilegesTracker - final TelephonyManager subIdSpecificTelephonyManager = mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId()); @@ -214,12 +270,39 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { */ @Override public void onReceive(Context context, Intent intent) { - // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it - // already was for an identified carrier, we can stop waiting for initial load to complete - if (!ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { - return; + switch (intent.getAction()) { + case ACTION_CARRIER_CONFIG_CHANGED: + handleActionCarrierConfigChanged(context, intent); + break; + case ACTION_MULTI_SIM_CONFIG_CHANGED: + handleActionMultiSimConfigChanged(context, intent); + break; + default: + Slog.v(TAG, "Unknown intent received with action: " + intent.getAction()); + } + } + + private void handleActionMultiSimConfigChanged(Context context, Intent intent) { + unregisterCarrierPrivilegesListeners(); + + // Clear invalid slotIds from the mReadySubIdsBySlotId map. + final int modemCount = mTelephonyManager.getActiveModemCount(); + final Iterator slotIdIterator = mReadySubIdsBySlotId.keySet().iterator(); + while (slotIdIterator.hasNext()) { + final int slotId = slotIdIterator.next(); + + if (slotId >= modemCount) { + slotIdIterator.remove(); + } } + registerCarrierPrivilegesListeners(); + handleSubscriptionsChanged(); + } + + private void handleActionCarrierConfigChanged(Context context, Intent intent) { + // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it + // already was for an identified carrier, we can stop waiting for initial load to complete final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID); final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX); diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 1f0df62fe72c7..978bf3ed2e920 100644 --- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -22,6 +22,7 @@ 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 android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -34,8 +35,10 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -57,6 +60,8 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.CarrierPrivilegesListener; +import android.util.ArrayMap; import android.util.ArraySet; import androidx.test.filters.SmallTest; @@ -83,7 +88,7 @@ public class TelephonySubscriptionTrackerTest { private static final String PACKAGE_NAME = TelephonySubscriptionTrackerTest.class.getPackage().getName(); 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_SIM_SLOT_INDEX = 0; private static final int TEST_SUBSCRIPTION_ID_1 = 2; private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class); private static final int TEST_SUBSCRIPTION_ID_2 = 3; @@ -151,6 +156,8 @@ public class TelephonySubscriptionTrackerTest { @Before public void setUp() throws Exception { + doReturn(2).when(mTelephonyManager).getActiveModemCount(); + mCallback = mock(TelephonySubscriptionTrackerCallback.class); mTelephonySubscriptionTracker = new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps); @@ -180,6 +187,15 @@ public class TelephonySubscriptionTrackerTest { return captor.getValue(); } + private List getCarrierPrivilegesListeners() { + final ArgumentCaptor captor = + ArgumentCaptor.forClass(CarrierPrivilegesListener.class); + verify(mTelephonyManager, atLeastOnce()) + .addCarrierPrivilegesListener(anyInt(), any(), captor.capture()); + + return captor.getAllValues(); + } + private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() { final ArgumentCaptor captor = ArgumentCaptor.forClass(TelephonyCallback.class); @@ -188,6 +204,11 @@ public class TelephonySubscriptionTrackerTest { return (ActiveDataSubscriptionIdListener) captor.getValue(); } + private Intent buildTestMultiSimConfigBroadcastIntent() { + Intent intent = new Intent(ACTION_MULTI_SIM_CONFIG_CHANGED); + return intent; + } + private Intent buildTestBroadcastIntent(boolean hasValidSubscription) { Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX); @@ -239,12 +260,21 @@ public class TelephonySubscriptionTrackerTest { any(), eq(mHandler)); final IntentFilter filter = getIntentFilter(); - assertEquals(1, filter.countActions()); + assertEquals(2, filter.countActions()); assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED)); + assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED)); verify(mSubscriptionManager) .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any()); assertNotNull(getOnSubscriptionsChangedListener()); + + verify(mTelephonyManager, times(2)) + .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any()); + verify(mTelephonyManager) + .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any()); + verify(mTelephonyManager) + .addCarrierPrivilegesListener(eq(1), any(HandlerExecutor.class), any()); + assertEquals(2, getCarrierPrivilegesListeners().size()); } @Test @@ -255,6 +285,49 @@ public class TelephonySubscriptionTrackerTest { final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener)); + + for (CarrierPrivilegesListener carrierPrivilegesListener : + getCarrierPrivilegesListeners()) { + verify(mTelephonyManager) + .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener)); + } + } + + @Test + public void testMultiSimConfigChanged() throws Exception { + final ArrayMap readySubIdsBySlotId = new ArrayMap<>(); + readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1); + readySubIdsBySlotId.put(TEST_SIM_SLOT_INDEX + 1, TEST_SUBSCRIPTION_ID_1); + + mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId); + doReturn(1).when(mTelephonyManager).getActiveModemCount(); + + List carrierPrivilegesListeners = + getCarrierPrivilegesListeners(); + + mTelephonySubscriptionTracker.onReceive(mContext, buildTestMultiSimConfigBroadcastIntent()); + mTestLooper.dispatchAll(); + + for (CarrierPrivilegesListener carrierPrivilegesListener : carrierPrivilegesListeners) { + verify(mTelephonyManager) + .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener)); + } + + // Expect cache cleared for inactive slots. + assertNull( + mTelephonySubscriptionTracker + .getReadySubIdsBySlotId() + .get(TEST_SIM_SLOT_INDEX + 1)); + + // Expect a new CarrierPrivilegesListener to have been registered for slot 0, and none other + // (2 previously registered during startup, for slots 0 & 1) + verify(mTelephonyManager, times(3)) + .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any()); + verify(mTelephonyManager, times(2)) + .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any()); + + // Verify that this triggers a re-evaluation + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); } @Test @@ -313,6 +386,17 @@ public class TelephonySubscriptionTrackerTest { verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); } + @Test + public void testOnCarrierPrivilegesChanged() throws Exception { + setupReadySubIds(); + + final CarrierPrivilegesListener listener = getCarrierPrivilegesListeners().get(0); + listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {}); + mTestLooper.dispatchAll(); + + verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); + } + @Test public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception { mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true)); From fb4a590dbcb7d2782137678f12f23ae303e14e70 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 7 Jan 2022 21:56:04 +0000 Subject: [PATCH 2/2] Remove VCN Carrier Privilege grace period This change removes the grace period after the VCN is notified that a provisioning app is no longer carrier privileged. This is due to the switch to use CarrierPrivilegesTracker, which inherently has the identical grace period. This both simplifies the code, as well as removes some edge cases. As such, tests for the delay before VCN tears down are no longer necessary. Bug: 183554244 Test: atest FrameworksVcnTests Change-Id: Ia50223108e45eeaedc860adf5e29a6ea459d956f --- .../android/server/VcnManagementService.java | 58 +++------- .../server/VcnManagementServiceTest.java | 100 ++---------------- 2 files changed, 22 insertions(+), 136 deletions(-) diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 0c990ecfc827a..6a7afd90dc967 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -24,7 +24,6 @@ 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; @@ -164,10 +163,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { @VisibleForTesting(visibility = Visibility.PRIVATE) static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml"; - // TODO(b/176956496): Directly use CarrierServiceBindHelper.UNBIND_DELAY_MILLIS - @VisibleForTesting(visibility = Visibility.PRIVATE) - static final long CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS = TimeUnit.SECONDS.toMillis(30); - /* Binder context for this service */ @NonNull private final Context mContext; @NonNull private final Dependencies mDeps; @@ -372,12 +367,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Notifies the VcnManagementService that external dependencies can be set up. */ public void systemReady() { - mNetworkProvider.register(); - mContext.getSystemService(ConnectivityManager.class) - .registerNetworkCallback( - new NetworkRequest.Builder().clearCapabilities().build(), - mTrackingNetworkCallback); - mTelephonySubscriptionTracker.register(); + // Always run on the handler thread to ensure consistency. + mHandler.post(() -> { + mNetworkProvider.register(); + mContext.getSystemService(ConnectivityManager.class) + .registerNetworkCallback( + new NetworkRequest.Builder().clearCapabilities().build(), + mTrackingNetworkCallback); + mTelephonySubscriptionTracker.register(); + }); } private void enforcePrimaryUser() { @@ -471,22 +469,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!mVcns.containsKey(subGrp)) { startVcnLocked(subGrp, entry.getValue()); } - - // Cancel any scheduled teardowns for active subscriptions - mHandler.removeCallbacksAndMessages(mVcns.get(subGrp)); } } - // Schedule teardown of any VCN instances that have lost carrier privileges (after a - // delay) + // Schedule teardown of any VCN instances that have lost carrier privileges for (Entry entry : mVcns.entrySet()) { 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 @@ -496,31 +487,12 @@ public class VcnManagementService extends IVcnManagementService.Stub { 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 - // torn down, and a new instance was started. Verify to ensure - // 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) { - stopVcnLocked(uuidToTeardown); + stopVcnLocked(uuidToTeardown); - // TODO(b/181789060): invoke asynchronously after Vcn notifies - // through VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - uuidToTeardown, VCN_STATUS_CODE_INACTIVE); - } - } - }, instanceToTeardown, teardownDelayMs); + // TODO(b/181789060): invoke asynchronously after Vcn notifies + // through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + uuidToTeardown, VCN_STATUS_CODE_INACTIVE); } else { // If this VCN's status has not changed, update it with the new snapshot entry.getValue().updateSubscriptionSnapshot(mLastSnapshot); diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 7c7dc4d79e9ac..bb98bc0bab536 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -23,7 +23,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; @@ -264,6 +263,7 @@ public class VcnManagementServiceTest { @Test public void testSystemReady() throws Exception { mVcnMgmtSvc.systemReady(); + mTestLooper.dispatchAll(); verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class)); verify(mSubscriptionTracker).register(); @@ -475,10 +475,8 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); - - // Verify teardown after delay - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); verify(mMockPolicyListener).onPolicyChanged(); } @@ -504,92 +502,6 @@ public class VcnManagementServiceTest { assertEquals(0, mVcnMgmtSvc.getAllVcns().size()); } - /** - * Tests an intermediate state where carrier privileges are marked as lost before active data - * subId changes during a SIM ejection. - * - *

The expected outcome is that the VCN is torn down after a delay, as opposed to - * immediately. - */ - @Test - public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges() - throws Exception { - setupActiveSubscription(TEST_UUID_2); - - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); - - // Simulate privileges lost - triggerSubscriptionTrackerCbAndGetSnapshot( - TEST_SUBSCRIPTION_ID, - TEST_UUID_2, - Collections.emptySet(), - Collections.emptyMap(), - false /* hasCarrierPrivileges */); - - // Verify teardown after delay - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); - mTestLooper.dispatchAll(); - verify(vcn).teardownAsynchronously(); - } - - @Test - public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances() - throws Exception { - setupActiveSubscription(TEST_UUID_2); - - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2); - - // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot( - INVALID_SUBSCRIPTION_ID, - null /* activeDataSubscriptionGroup */, - Collections.emptySet(), - Collections.emptyMap(), - false /* hasCarrierPrivileges */); - - // Simulate new SIM loaded right during teardown delay. - mTestLooper.moveTimeForward( - VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); - mTestLooper.dispatchAll(); - triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); - - // Verify that even after the full timeout duration, the VCN instance is not torn down - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); - mTestLooper.dispatchAll(); - verify(vcn, never()).teardownAsynchronously(); - } - - @Test - public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception { - setupActiveSubscription(TEST_UUID_2); - - final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback(); - final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2); - - // Simulate SIM unloaded - triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet()); - - // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new - // vcnInstance. - mTestLooper.moveTimeForward( - VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); - mTestLooper.dispatchAll(); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); - triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2)); - final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); - - // Verify that new instance was different, and the old one was torn down - assertTrue(oldInstance != newInstance); - verify(oldInstance).teardownAsynchronously(); - - // Verify that even after the full timeout duration, the new VCN instance is not torn down - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); - mTestLooper.dispatchAll(); - verify(newInstance, never()).teardownAsynchronously(); - } - @Test public void testPackageChangeListenerRegistered() throws Exception { verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> { @@ -925,6 +837,8 @@ public class VcnManagementServiceTest { private void setupSubscriptionAndStartVcn( int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { mVcnMgmtSvc.systemReady(); + mTestLooper.dispatchAll(); + triggerSubscriptionTrackerCbAndGetSnapshot( subGrp, Collections.singleton(subGrp), @@ -1020,6 +934,7 @@ public class VcnManagementServiceTest { private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { mVcnMgmtSvc.systemReady(); + mTestLooper.dispatchAll(); final ArgumentCaptor captor = ArgumentCaptor.forClass(NetworkCallback.class); @@ -1264,15 +1179,14 @@ public class VcnManagementServiceTest { true /* isActive */, true /* hasCarrierPrivileges */); - // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown - // timeout so the VCN goes inactive. + // VCN is currently active. Lose carrier privileges for TEST_PACKAGE so the VCN goes + // inactive. final TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot( TEST_UUID_1, Collections.singleton(TEST_UUID_1), Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), false /* hasCarrierPrivileges */); - mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); mTestLooper.dispatchAll(); // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE