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

Commit c7c020d5 authored by Holly Jiuyu Sun's avatar Holly Jiuyu Sun Committed by Peter Wang
Browse files

Run SubscriptionInfoUpdater on main thread.

Run GetEuiccProfileInfoList should be run on background thread. Post the
following operations back to main thread.

Bug: 131695762
Test: test on phone
Change-Id: I7d819d50f568561e0dff6250da61b8f157b315ca
Merged-In: I7d819d50f568561e0dff6250da61b8f157b315ca
Merged-In: I7f6d494aa22065c09cc29b23a07a3262fe7067b7
Merged-In: Ib160ed5276fff0e1ad4fb620a7b69eb1e44251f2
parent 5be5d438
Loading
Loading
Loading
Loading
+111 −40
Original line number Diff line number Diff line
@@ -66,7 +66,6 @@ import com.android.internal.telephony.uicc.UiccSlot;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
@@ -113,12 +112,26 @@ public class SubscriptionInfoUpdater extends Handler {
    private EuiccManager mEuiccManager;
    @UnsupportedAppUsage
    private IPackageManager mPackageManager;
    private Handler mBackgroundHandler;

    // The current foreground user ID.
    @UnsupportedAppUsage
    private int mCurrentlyActiveUserId;
    private CarrierServiceBindHelper mCarrierServiceBindHelper;

    /**
     * Runnable with a boolean parameter. This is used in
     * updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback).
     */
    private interface UpdateEmbeddedSubsCallback {
        /**
         * Callback of the Runnable.
         * @param hasChanges Whether there is any subscription info change. If yes, we need to
         * notify the listeners.
         */
        void run(boolean hasChanges);
    }

    // TODO: The SubscriptionController instance should be passed in here from PhoneFactory
    // rather than invoking the static getter all over the place.
    public SubscriptionInfoUpdater(
@@ -130,8 +143,8 @@ public class SubscriptionInfoUpdater extends Handler {
    @VisibleForTesting public SubscriptionInfoUpdater(
            Looper looper, Context context, Phone[] phone,
            CommandsInterface[] ci, IPackageManager packageMgr) {
        super(looper);
        logd("Constructor invoked");
        mBackgroundHandler = new Handler(looper);

        mContext = context;
        mPhone = phone;
@@ -228,6 +241,7 @@ public class SubscriptionInfoUpdater extends Handler {

    @Override
    public void handleMessage(Message msg) {
        List<Integer> cardIds = new ArrayList<>();
        switch (msg.what) {
            case EVENT_GET_NETWORK_SELECTION_MODE_DONE: {
                AsyncResult ar = (AsyncResult)msg.obj;
@@ -279,6 +293,12 @@ public class SubscriptionInfoUpdater extends Handler {
                break;

            case EVENT_SIM_READY:
                cardIds.add(getCardIdFromPhoneId(msg.arg1));
                updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
                    if (hasChanges) {
                        SubscriptionController.getInstance().notifySubscriptionInfoChanged();
                    }
                });
                broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null);
                broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
                broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
@@ -289,22 +309,28 @@ public class SubscriptionInfoUpdater extends Handler {
                break;

            case EVENT_SIM_NOT_READY:
                handleSimNotReady(msg.arg1);
                int cardId = getCardIdFromPhoneId(msg.arg1);
                // an eUICC with no active subscriptions never becomes ready, so we need to trigger
                // the embedded subscriptions update here
                if (updateEmbeddedSubscriptions(cardId)) {
                cardIds.add(getCardIdFromPhoneId(msg.arg1));
                updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
                    if (hasChanges) {
                        SubscriptionController.getInstance().notifySubscriptionInfoChanged();
                    }
                });
                handleSimNotReady(msg.arg1);
                break;

            case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS:
                if (updateEmbeddedSubscriptions(msg.arg1)) {
                cardIds.add(msg.arg1);
                Runnable r = (Runnable) msg.obj;
                updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
                    if (hasChanges) {
                        SubscriptionController.getInstance().notifySubscriptionInfoChanged();
                    }
                if (msg.obj != null) {
                    ((Runnable) msg.obj).run();
                    if (r != null) {
                        r.run();
                    }
                });
                break;

            default:
@@ -353,7 +379,7 @@ public class SubscriptionInfoUpdater extends Handler {
            logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId);
        }

        updateSubscriptionInfoByIccId(slotId);
        updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);

        broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason);
        broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT);
@@ -387,7 +413,7 @@ public class SubscriptionInfoUpdater extends Handler {
            // phase, the subscription list is accessible. Treating NOT_READY
            // as equivalent to ABSENT, once the rest of the system can handle it.
            mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
            updateSubscriptionInfoByIccId(slotId);
            updateSubscriptionInfoByIccId(slotId, false /* updateEmbeddedSubs */);
        }

        broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
@@ -419,7 +445,7 @@ public class SubscriptionInfoUpdater extends Handler {
        }
        mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId());

        updateSubscriptionInfoByIccId(slotId);
        updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);
        List<SubscriptionInfo> subscriptionInfos = SubscriptionController.getInstance()
                .getSubInfoUsingSlotIndexPrivileged(slotId);
        if (subscriptionInfos == null || subscriptionInfos.isEmpty()) {
@@ -547,7 +573,7 @@ public class SubscriptionInfoUpdater extends Handler {
            logd("SIM" + (slotId + 1) + " hot plug out, absentAndInactive=" + absentAndInactive);
        }
        mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
        updateSubscriptionInfoByIccId(slotId);
        updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);
        // Do not broadcast if the SIM is absent and inactive, because the logical slotId here is
        // no longer correct
        if (absentAndInactive == 0) {
@@ -564,7 +590,7 @@ public class SubscriptionInfoUpdater extends Handler {
            logd("SIM" + (slotId + 1) + " Error ");
        }
        mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
        updateSubscriptionInfoByIccId(slotId);
        updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);
        broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR,
                IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
        broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR);
@@ -573,7 +599,8 @@ public class SubscriptionInfoUpdater extends Handler {
        updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
    }

    synchronized private void updateSubscriptionInfoByIccId(int slotIndex) {
    private synchronized void updateSubscriptionInfoByIccId(int slotIndex,
            boolean updateEmbeddedSubs) {
        logd("updateSubscriptionInfoByIccId:+ Start");
        if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
            loge("[updateSubscriptionInfoByIccId]- invalid slotIndex=" + slotIndex);
@@ -627,20 +654,30 @@ public class SubscriptionInfoUpdater extends Handler {
            } else {
                logd("bypass reset default data sub if inactive");
            }
            setSubInfoInitialized();
        }

        UiccController uiccController = UiccController.getInstance();
        UiccSlot[] uiccSlots = uiccController.getUiccSlots();
            if (uiccSlots != null) {
                Arrays.stream(uiccSlots)
                        .filter(uiccSlot -> uiccSlot != null && uiccSlot.getUiccCard() != null)
                        .map(uiccSlot -> uiccController.convertToPublicCardId(
                                uiccSlot.getUiccCard().getCardId()))
                        .forEach(cardId -> updateEmbeddedSubscriptions(cardId));
        if (uiccSlots != null && updateEmbeddedSubs) {
            List<Integer> cardIds = new ArrayList<>();
            for (UiccSlot uiccSlot : uiccSlots) {
                if (uiccSlot != null && uiccSlot.getUiccCard() != null) {
                    int cardId = uiccController.convertToPublicCardId(
                            uiccSlot.getUiccCard().getCardId());
                    cardIds.add(cardId);
                }
            setSubInfoInitialized();
            }
            updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
                if (hasChanges) {
                    SubscriptionController.getInstance().notifySubscriptionInfoChanged();
                }
                if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete");
            });
        }

        SubscriptionController.getInstance().notifySubscriptionInfoChanged();
        logd("updateSubscriptionInfoByIccId:- SubscriptionInfo update complete");
        if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete");
    }

    private static void setSubInfoInitialized() {
@@ -661,24 +698,58 @@ public class SubscriptionInfoUpdater extends Handler {
    }

    /**
     * Update the cached list of embedded subscription for the eUICC with the given card ID
     * {@code cardId}.
     *
     * @return true if changes may have been made. This is not a guarantee that changes were made,
     * but notifications about subscription changes may be skipped if this returns false as an
     * optimization to avoid spurious notifications.
     * Updates the cached list of embedded subscription for the eUICC with the given list of card
     * IDs {@code cardIds}. The step of reading the embedded subscription list from eUICC card is
     * executed in background thread. The callback {@code callback} is executed after the cache is
     * refreshed. The callback is executed in main thread.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    public boolean updateEmbeddedSubscriptions(int cardId) {
        if (DBG) logd("updateEmbeddedSubscriptions");
    public void updateEmbeddedSubscriptions(List<Integer> cardIds,
            @Nullable UpdateEmbeddedSubsCallback callback) {
        // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they
        // are filtered out of list calls as long as EuiccManager.isEnabled returns false).
        if (!mEuiccManager.isEnabled()) {
            return false;
            callback.run(false /* hasChanges */);
            return;
        }

        mBackgroundHandler.post(() -> {
            List<GetEuiccProfileInfoListResult> results = new ArrayList<>();
            for (int cardId : cardIds) {
                GetEuiccProfileInfoListResult result =
                        EuiccController.get().blockingGetEuiccProfileInfoList(cardId);
                if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId);
                results.add(result);
            }

            // The runnable will be executed in the main thread.
            this.post(() -> {
                boolean hasChanges = false;
                for (GetEuiccProfileInfoListResult result : results) {
                    if (updateEmbeddedSubscriptionsCache(result)) {
                        hasChanges = true;
                    }
                }
                // The latest state in the main thread may be changed when the callback is
                // triggered.
                if (callback != null) {
                    callback.run(hasChanges);
                }
            });
        });
    }

    /**
     * Update the cached list of embedded subscription based on the passed in
     * GetEuiccProfileInfoListResult {@code result}.
     *
     * @return true if changes may have been made. This is not a guarantee that changes were made,
     * but notifications about subscription changes may be skipped if this returns false as an
     * optimization to avoid spurious notifications.
     */
    private boolean updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result) {
        if (DBG) logd("updateEmbeddedSubscriptionsCache");

        if (result == null) {
            // IPC to the eUICC controller failed.
            return false;
+12 −3
Original line number Diff line number Diff line
@@ -507,7 +507,12 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest {
        when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate(
                new String[] { "1", "3"}, false /* removable */)).thenReturn(subInfoList);

        assertTrue(mUpdater.updateEmbeddedSubscriptions(FAKE_CARD_ID));
        List<Integer> cardIds = new ArrayList<>();
        cardIds.add(FAKE_CARD_ID);
        mUpdater.updateEmbeddedSubscriptions(cardIds, null /* callback */);

        // Wait for some time until the callback is triggered.
        waitForMs(100);

        // 3 is new and so a new entry should have been created.
        verify(mSubscriptionController).insertEmptySubInfoRecord(
@@ -558,7 +563,9 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest {
        when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate(
                new String[0], false /* removable */)).thenReturn(subInfoList);

        assertFalse(mUpdater.updateEmbeddedSubscriptions(FAKE_CARD_ID));
        ArrayList<Integer> cardIds = new ArrayList<>(1);
        cardIds.add(FAKE_CARD_ID);
        mUpdater.updateEmbeddedSubscriptions(cardIds, null /* callback */);

        // No new entries should be created.
        verify(mSubscriptionController, times(0)).clearSubInfo();
@@ -586,7 +593,9 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest {
        when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate(
                new String[0], false /* removable */)).thenReturn(subInfoList);

        assertFalse(mUpdater.updateEmbeddedSubscriptions(FAKE_CARD_ID));
        ArrayList<Integer> cardIds = new ArrayList<>(1);
        cardIds.add(FAKE_CARD_ID);
        mUpdater.updateEmbeddedSubscriptions(cardIds, null /* callback */);

        // No new entries should be created.
        verify(mSubscriptionController, never()).insertEmptySubInfoRecord(anyString(), anyInt());