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

Commit be8e9442 authored by Jiuyu Sun's avatar Jiuyu Sun Committed by android-build-merger
Browse files

Merge "Run SubscriptionInfoUpdater on main thread." into qt-dev

am: 15d63c11

Change-Id: I4b5ae0fb6546f19f7992d1320ba9f76d438439ad
parents 36a06d64 15d63c11
Loading
Loading
Loading
Loading
+104 −37
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,27 @@ 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);
                updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
                    if (hasChanges) {
                        SubscriptionController.getInstance().notifySubscriptionInfoChanged();
                    }
                    if (msg.obj != null) {
                        ((Runnable) msg.obj).run();
                    }
                });
                break;

            default:
@@ -353,7 +378,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 +412,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 +444,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()) {
@@ -541,7 +566,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) {
@@ -558,7 +583,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);
@@ -567,7 +592,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);
@@ -621,20 +647,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() {
@@ -655,25 +691,56 @@ public class SubscriptionInfoUpdater extends Handler {
    }

    /**
     * Update the cached list of embedded subscription for the eUICC with the given card ID
     * {@code cardId}.
     * 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 void updateEmbeddedSubscriptions(List<Integer> cardIds,
            @Nullable UpdateEmbeddedSubsCallback callback) {
        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.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    public boolean updateEmbeddedSubscriptions(int cardId) {
        if (DBG) logd("updateEmbeddedSubscriptions");
    private boolean updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result) {
        if (DBG) logd("updateEmbeddedSubscriptionsCache");
        // 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;
        }

        GetEuiccProfileInfoListResult result =
                EuiccController.get().blockingGetEuiccProfileInfoList(cardId);
        if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId);
        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());