Loading src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -729,6 +729,7 @@ public class SubscriptionDatabaseManager extends Handler { if (uri != null && uri.getLastPathSegment() != null) { int subId = Integer.parseInt(uri.getLastPathSegment()); if (SubscriptionManager.isValidSubscriptionId(subId)) { logv("insertNewRecordIntoDatabaseSync: contentValues=" + contentValues); logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + uri.getLastPathSegment()); return subId; Loading Loading @@ -1836,6 +1837,8 @@ public class SubscriptionDatabaseManager extends Handler { logl("Loaded " + mAllSubscriptionInfoInternalCache.size() + " records from the subscription database."); mAllSubscriptionInfoInternalCache.forEach( (subId, subInfo) -> log(" " + subInfo.toString())); } finally { mReadWriteLock.writeLock().unlock(); } Loading src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +13 −1 Original line number Diff line number Diff line Loading @@ -923,7 +923,6 @@ public class SubscriptionManagerService extends ISub.Stub { .forEach(subInfo -> { mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX); mSlotIndexToSubId.remove(simSlotIndex); }); updateGroupDisabled(); logl("markSubscriptionsInactive: " + slotMappingToString()); Loading Loading @@ -1268,6 +1267,19 @@ public class SubscriptionManagerService extends ISub.Stub { } String iccId = getIccId(phoneId); log("updateSubscriptions: Found iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + " on phone " + phoneId); // For eSIM switching, SIM absent will not happen. Below is to exam if we find ICCID // mismatch on the SIM slot, we need to mark all subscriptions on that logical slot invalid // first. The correct subscription will be assigned the correct slot later. if (mSubscriptionDatabaseManager.getAllSubscriptions().stream() .anyMatch(subInfo -> subInfo.getSimSlotIndex() == phoneId && !iccId.equals(subInfo.getIccId()))) { log("updateSubscriptions: iccId changed for phone " + phoneId); markSubscriptionsInactive(phoneId); } if (!TextUtils.isEmpty(iccId)) { // Check if the subscription already existed. SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionDatabaseManagerTest +Setup!"); super.setUp(getClass().getSimpleName()); mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, true); mSubscriptionDatabaseManagerCallback = Mockito.mock(SubscriptionDatabaseManagerCallback.class); doAnswer(invocation -> { Loading tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +55 −10 Original line number Diff line number Diff line Loading @@ -144,7 +144,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, true); mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[0]); mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC); Loading @@ -158,6 +159,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionManagerServiceCallback.class); doReturn(FAKE_ICCID1).when(mUiccCard).getCardId(); doReturn(FAKE_ICCID1).when(mUiccPort).getIccId(); doReturn(true).when(mUiccSlot).isActive(); doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); Loading @@ -167,6 +169,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper()); monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper())); monitorTestableLooper(new TestableLooper(getSubscriptionDatabaseManager().getLooper())); doAnswer(invocation -> { ((Runnable) invocation.getArguments()[0]).run(); Loading Loading @@ -211,6 +214,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { return (Handler) field.get(mSubscriptionManagerServiceUT); } private SubscriptionDatabaseManager getSubscriptionDatabaseManager() throws Exception { Field field = SubscriptionManagerService.class.getDeclaredField( "mSubscriptionDatabaseManager"); field.setAccessible(true); return (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); } /** * Insert the subscription info to the database. * Loading @@ -222,21 +232,14 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build(); Field field = SubscriptionManagerService.class.getDeclaredField( "mSubscriptionDatabaseManager"); field.setAccessible(true); SubscriptionDatabaseManager sdbm = (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); int subId = sdbm.insertSubscriptionInfo(subInfo); int subId = getSubscriptionDatabaseManager().insertSubscriptionInfo(subInfo); // Insertion is sync, but the onSubscriptionChanged callback is handled by the handler. processAllMessages(); Class<?> WatchedMapClass = Class.forName("com.android.internal.telephony.subscription" + ".SubscriptionManagerService$WatchedMap"); field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); Field field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); field.setAccessible(true); Object map = field.get(mSubscriptionManagerServiceUT); Class[] cArgs = new Class[2]; Loading Loading @@ -1858,4 +1861,46 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // The original eSIM becomes removed pSIM ¯\_(ツ)_/¯ assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isFalse(); } @Test public void testEsimSwitch() { setIdentifierAccess(true); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID2) .setIccid(FAKE_ICCID2) .setNickname(FAKE_CARRIER_NAME2) .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC2, FAKE_MNC2, null, null, null, null, FAKE_CARRIER_ID2, FAKE_CARRIER_ID2)) .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules( FAKE_NATIVE_ACCESS_RULES2))) .build(); GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false); doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); doReturn(FAKE_ICCID2).when(mUiccCard).getCardId(); doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(1)); doReturn(FAKE_ICCID2).when(mUiccPort).getIccId(); mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); processAllMessages(); mSubscriptionManagerServiceUT.updateSimState( 0, TelephonyManager.SIM_STATE_READY, null, null); processAllMessages(); mSubscriptionManagerServiceUT.updateSimState( 0, TelephonyManager.SIM_STATE_LOADED, null, null); processAllMessages(); List<SubscriptionInfo> subInfoList = mSubscriptionManagerServiceUT .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfoList).hasSize(1); assertThat(subInfoList.get(0).isActive()).isTrue(); assertThat(subInfoList.get(0).getIccId()).isEqualTo(FAKE_ICCID2); } } Loading
src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -729,6 +729,7 @@ public class SubscriptionDatabaseManager extends Handler { if (uri != null && uri.getLastPathSegment() != null) { int subId = Integer.parseInt(uri.getLastPathSegment()); if (SubscriptionManager.isValidSubscriptionId(subId)) { logv("insertNewRecordIntoDatabaseSync: contentValues=" + contentValues); logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + uri.getLastPathSegment()); return subId; Loading Loading @@ -1836,6 +1837,8 @@ public class SubscriptionDatabaseManager extends Handler { logl("Loaded " + mAllSubscriptionInfoInternalCache.size() + " records from the subscription database."); mAllSubscriptionInfoInternalCache.forEach( (subId, subInfo) -> log(" " + subInfo.toString())); } finally { mReadWriteLock.writeLock().unlock(); } Loading
src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +13 −1 Original line number Diff line number Diff line Loading @@ -923,7 +923,6 @@ public class SubscriptionManagerService extends ISub.Stub { .forEach(subInfo -> { mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX); mSlotIndexToSubId.remove(simSlotIndex); }); updateGroupDisabled(); logl("markSubscriptionsInactive: " + slotMappingToString()); Loading Loading @@ -1268,6 +1267,19 @@ public class SubscriptionManagerService extends ISub.Stub { } String iccId = getIccId(phoneId); log("updateSubscriptions: Found iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + " on phone " + phoneId); // For eSIM switching, SIM absent will not happen. Below is to exam if we find ICCID // mismatch on the SIM slot, we need to mark all subscriptions on that logical slot invalid // first. The correct subscription will be assigned the correct slot later. if (mSubscriptionDatabaseManager.getAllSubscriptions().stream() .anyMatch(subInfo -> subInfo.getSimSlotIndex() == phoneId && !iccId.equals(subInfo.getIccId()))) { log("updateSubscriptions: iccId changed for phone " + phoneId); markSubscriptionsInactive(phoneId); } if (!TextUtils.isEmpty(iccId)) { // Check if the subscription already existed. SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager Loading
tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionDatabaseManagerTest +Setup!"); super.setUp(getClass().getSimpleName()); mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, true); mSubscriptionDatabaseManagerCallback = Mockito.mock(SubscriptionDatabaseManagerCallback.class); doAnswer(invocation -> { Loading
tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +55 −10 Original line number Diff line number Diff line Loading @@ -144,7 +144,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, true); mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[0]); mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC); Loading @@ -158,6 +159,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionManagerServiceCallback.class); doReturn(FAKE_ICCID1).when(mUiccCard).getCardId(); doReturn(FAKE_ICCID1).when(mUiccPort).getIccId(); doReturn(true).when(mUiccSlot).isActive(); doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); Loading @@ -167,6 +169,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper()); monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper())); monitorTestableLooper(new TestableLooper(getSubscriptionDatabaseManager().getLooper())); doAnswer(invocation -> { ((Runnable) invocation.getArguments()[0]).run(); Loading Loading @@ -211,6 +214,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { return (Handler) field.get(mSubscriptionManagerServiceUT); } private SubscriptionDatabaseManager getSubscriptionDatabaseManager() throws Exception { Field field = SubscriptionManagerService.class.getDeclaredField( "mSubscriptionDatabaseManager"); field.setAccessible(true); return (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); } /** * Insert the subscription info to the database. * Loading @@ -222,21 +232,14 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build(); Field field = SubscriptionManagerService.class.getDeclaredField( "mSubscriptionDatabaseManager"); field.setAccessible(true); SubscriptionDatabaseManager sdbm = (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); int subId = sdbm.insertSubscriptionInfo(subInfo); int subId = getSubscriptionDatabaseManager().insertSubscriptionInfo(subInfo); // Insertion is sync, but the onSubscriptionChanged callback is handled by the handler. processAllMessages(); Class<?> WatchedMapClass = Class.forName("com.android.internal.telephony.subscription" + ".SubscriptionManagerService$WatchedMap"); field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); Field field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); field.setAccessible(true); Object map = field.get(mSubscriptionManagerServiceUT); Class[] cArgs = new Class[2]; Loading Loading @@ -1858,4 +1861,46 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // The original eSIM becomes removed pSIM ¯\_(ツ)_/¯ assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isFalse(); } @Test public void testEsimSwitch() { setIdentifierAccess(true); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID2) .setIccid(FAKE_ICCID2) .setNickname(FAKE_CARRIER_NAME2) .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC2, FAKE_MNC2, null, null, null, null, FAKE_CARRIER_ID2, FAKE_CARRIER_ID2)) .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules( FAKE_NATIVE_ACCESS_RULES2))) .build(); GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false); doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); doReturn(FAKE_ICCID2).when(mUiccCard).getCardId(); doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(1)); doReturn(FAKE_ICCID2).when(mUiccPort).getIccId(); mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); processAllMessages(); mSubscriptionManagerServiceUT.updateSimState( 0, TelephonyManager.SIM_STATE_READY, null, null); processAllMessages(); mSubscriptionManagerServiceUT.updateSimState( 0, TelephonyManager.SIM_STATE_LOADED, null, null); processAllMessages(); List<SubscriptionInfo> subInfoList = mSubscriptionManagerServiceUT .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfoList).hasSize(1); assertThat(subInfoList.get(0).isActive()).isTrue(); assertThat(subInfoList.get(0).getIccId()).isEqualTo(FAKE_ICCID2); } }