Merge changes Ia5022310,Ia4529d08
* changes:
Remove VCN Carrier Privilege grace period
Update TelephonySubscriptionTracker to use CarrierPrivilegesListener
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 0c990ec..6a7afd9 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_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 @@
@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 @@
/** 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 @@
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<ParcelUuid, Vcn> 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 @@
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/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index a31c56a..a17e792 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_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.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 @@
@NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
@NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
+ @NonNull
+ private final List<CarrierPrivilegesListener> mCarrierPrivilegesChangedListeners =
+ new ArrayList<>();
+
@NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot;
public TelephonySubscriptionTracker(
@@ -126,22 +135,71 @@
};
}
- /** Registers the receivers, and starts tracking subscriptions. */
+ /**
+ * Registers the receivers, and starts tracking subscriptions.
+ *
+ * <p>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<String> 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.
+ *
+ * <p>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 @@
// 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 @@
*/
@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<Integer> 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/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 7c7dc4d..bb98bc0 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_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 @@
@Test
public void testSystemReady() throws Exception {
mVcnMgmtSvc.systemReady();
+ mTestLooper.dispatchAll();
verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
verify(mSubscriptionTracker).register();
@@ -475,10 +475,8 @@
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 @@
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.
- *
- * <p>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 @@
private void setupSubscriptionAndStartVcn(
int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
mVcnMgmtSvc.systemReady();
+ mTestLooper.dispatchAll();
+
triggerSubscriptionTrackerCbAndGetSnapshot(
subGrp,
Collections.singleton(subGrp),
@@ -1020,6 +934,7 @@
private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
mVcnMgmtSvc.systemReady();
+ mTestLooper.dispatchAll();
final ArgumentCaptor<NetworkCallback> captor =
ArgumentCaptor.forClass(NetworkCallback.class);
@@ -1264,15 +1179,14 @@
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
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 1f0df62..978bf3e 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.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.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.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 @@
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 @@
@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 @@
return captor.getValue();
}
+ private List<CarrierPrivilegesListener> getCarrierPrivilegesListeners() {
+ final ArgumentCaptor<CarrierPrivilegesListener> captor =
+ ArgumentCaptor.forClass(CarrierPrivilegesListener.class);
+ verify(mTelephonyManager, atLeastOnce())
+ .addCarrierPrivilegesListener(anyInt(), any(), captor.capture());
+
+ return captor.getAllValues();
+ }
+
private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() {
final ArgumentCaptor<TelephonyCallback> captor =
ArgumentCaptor.forClass(TelephonyCallback.class);
@@ -188,6 +204,11 @@
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 @@
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 @@
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<Integer, Integer> 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<CarrierPrivilegesListener> 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
@@ -314,6 +387,17 @@
}
@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));
mTestLooper.dispatchAll();