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

Commit 3b6346b4 authored by Jack Yu's avatar Jack Yu Committed by Gerrit Code Review
Browse files

Merge changes from topic "sub_cleanup" into main

* changes:
  Cleaned up the usage of SubscriptionManger.getSubId
  Fixed eSIM switch issue
  Added log to print slot/sub mapping
  Fixed eSIM deletion issue
parents cfa47674 069a1311
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -2624,7 +2624,6 @@ public class SubscriptionController extends ISub.Stub {
     * @deprecated
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @Override
    @Deprecated
    public int[] getSubIds(int slotIndex) {
        if (VDBG) printStackTrace("[getSubId]+ slotIndex=" + slotIndex);
+3 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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();
            }
+50 −6
Original line number Diff line number Diff line
@@ -898,9 +898,9 @@ public class SubscriptionManagerService extends ISub.Stub {
                .forEach(subInfo -> {
                    mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(),
                            SubscriptionManager.INVALID_SIM_SLOT_INDEX);
                    mSlotIndexToSubId.remove(simSlotIndex);
                });
        updateGroupDisabled();
        logl("markSubscriptionsInactive: " + slotMappingToString());
    }

    /**
@@ -1002,6 +1002,7 @@ public class SubscriptionManagerService extends ISub.Stub {
                return;
            }

            Set<Integer> embeddedSubs = new ArraySet<>();
            log("updateEmbeddedSubscriptions: start to get euicc profiles.");
            for (int cardId : cardIds) {
                GetEuiccProfileInfoListResult result = mEuiccController
@@ -1078,11 +1079,27 @@ public class SubscriptionManagerService extends ISub.Stub {
                        builder.setCardString(mUiccController.convertToCardString(cardId));
                    }

                    embeddedSubs.add(subInfo.getSubscriptionId());
                    subInfo = builder.build();
                    log("updateEmbeddedSubscriptions: update subscription " + subInfo);
                    mSubscriptionDatabaseManager.updateSubscription(subInfo);
                }
            }

            // embeddedSubs contains all the existing embedded subs queried from EuiccManager,
            // including active or inactive. If there are any embedded subscription in the database
            // that is not in embeddedSubs, mark them as non-embedded. These were deleted embedded
            // subscriptions, so we treated them as non-embedded (pre-U behavior) and they don't
            // show up in Settings SIM page.
            mSubscriptionDatabaseManager.getAllSubscriptions().stream()
                    .filter(SubscriptionInfoInternal::isEmbedded)
                    .filter(subInfo -> !embeddedSubs.contains(subInfo.getSubscriptionId()))
                    .forEach(subInfo -> {
                        logl("updateEmbeddedSubscriptions: Mark the deleted sub "
                                + subInfo.getSubscriptionId() + " as non-embedded.");
                        mSubscriptionDatabaseManager.setEmbedded(
                                subInfo.getSubscriptionId(), false);
                    });
        });
        log("updateEmbeddedSubscriptions: Finished embedded subscription update.");
        if (callback != null) {
@@ -1225,6 +1242,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
@@ -1247,6 +1277,7 @@ public class SubscriptionManagerService extends ISub.Stub {
                mSlotIndexToSubId.put(phoneId, subId);
                // Update the SIM slot index. This will make the subscription active.
                mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId);
                logl("updateSubscriptions: " + slotMappingToString());
            }

            // Update the card id.
@@ -1323,6 +1354,7 @@ public class SubscriptionManagerService extends ISub.Stub {
        } else {
            log("updateSubscriptions: No ICCID available for phone " + phoneId);
            mSlotIndexToSubId.remove(phoneId);
            logl("updateSubscriptions: " + slotMappingToString());
        }

        if (areAllSubscriptionsLoaded()) {
@@ -1889,6 +1921,7 @@ public class SubscriptionManagerService extends ISub.Stub {
                int subId = insertSubscriptionInfo(iccId, slotIndex, displayName, subscriptionType);
                updateGroupDisabled();
                mSlotIndexToSubId.put(slotIndex, subId);
                logl("addSubInfo: " + slotMappingToString());
            } else {
                // Record already exists.
                loge("Subscription record already existed.");
@@ -2574,11 +2607,6 @@ public class SubscriptionManagerService extends ISub.Stub {
                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    }

    @Override
    public int[] getSubIds(int slotIndex) {
        return new int[]{getSubId(slotIndex)};
    }

    /**
     * Update default sub id.
     */
@@ -3764,6 +3792,16 @@ public class SubscriptionManagerService extends ISub.Stub {
        }
    }

    /**
     * @return The logical SIM slot/sub mapping to string.
     */
    @NonNull
    private String slotMappingToString() {
        return mSlotIndexToSubId.entrySet().stream()
                .map(e -> "Slot " + e.getKey() + ": subId=" + e.getValue())
                .collect(Collectors.joining(", "));
    }

    /**
     * Log debug messages.
     *
@@ -3818,6 +3856,12 @@ public class SubscriptionManagerService extends ISub.Stub {
        mSlotIndexToSubId.forEach((slotIndex, subId)
                -> pw.println("Logical SIM slot " + slotIndex + ": subId=" + subId));
        pw.decreaseIndent();
        pw.println("ICCID:");
        pw.increaseIndent();
        for (int i = 0; i < mTelephonyManager.getActiveModemCount(); i++) {
            pw.println("slot " + i + ": " + getIccId(i));
        }
        pw.decreaseIndent();
        pw.println();
        pw.println("defaultSubId=" + getDefaultSubId());
        pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId());
+2 −0
Original line number Diff line number Diff line
@@ -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 -> {
+96 −10
Original line number Diff line number Diff line
@@ -146,7 +146,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);
@@ -160,6 +161,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();

@@ -168,6 +170,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();
@@ -210,6 +213,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.
     *
@@ -221,21 +231,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];
@@ -1825,4 +1828,87 @@ public class SubscriptionManagerServiceTest extends TelephonyTest {
                SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, CALLING_PACKAGE, CALLING_FEATURE))
                .isEmpty();
    }

    @Test
    public void testDeleteEsim() {
        // pSIM
        insertSubscription(FAKE_SUBSCRIPTION_INFO2);

        EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1)
                .setIccid(FAKE_ICCID1)
                .setNickname(FAKE_CARRIER_NAME1)
                .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL)
                .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC1, FAKE_MNC1, null, null, null,
                        null, FAKE_CARRIER_ID1, FAKE_CARRIER_ID1))
                .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules(
                        FAKE_NATIVE_ACCESS_RULES1)))
                .build();

        GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult(
                EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false);
        doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1));
        doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1));

        mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null);
        processAllMessages();

        // Now we should have two subscriptions in the database. One for pSIM, one for eSIM.
        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).isEmbedded()).isFalse();
        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isTrue();

        // Delete the eSIM. blockingGetEuiccProfileInfoList will return an empty list.
        result = new GetEuiccProfileInfoListResult(
                EuiccService.RESULT_OK, new EuiccProfileInfo[0], false);
        doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1));

        mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null);
        processAllMessages();

        // The original pSIM is still pSIM
        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).isEmbedded()).isFalse();
        // 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);
    }
}