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

Commit 919151c2 authored by Jeff Davidson's avatar Jeff Davidson
Browse files

Update subscription list when SIM state is NOT_READY.

This is required to support the eSIM boot profile, as NOT_READY is the
terminal state when this profile is active.

This also requires that we perform the update even if the IccId query
is not done, as this query don't be done in this case. The update
should nevertheless be safe since it's only doing database
manipulations local to the eSIM logic and not touching other state
within SubscriptionInfoUpdater.

Bug: 64113021
Test: TreeHugger, on-device switches and eSIM resets
Change-Id: I19c1e8d4b72aed28599178f73d335b3b10e61772
parent 02558a9f
Loading
Loading
Loading
Loading
+30 −6
Original line number Diff line number Diff line
@@ -203,6 +203,13 @@ public class SubscriptionInfoUpdater extends Handler {
                    sendMessage(obtainMessage(EVENT_SIM_IO_ERROR, slotIndex, -1));
                } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED.equals(simStatus)) {
                    sendMessage(obtainMessage(EVENT_SIM_RESTRICTED, slotIndex, -1));
                } else if (IccCardConstants.INTENT_VALUE_ICC_NOT_READY.equals(simStatus)) {
                    // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
                    // phase, the subscription list is accessible.
                    // TODO(b/64216093): Clean up this special case, likely by treating NOT_READY
                    // as equivalent to ABSENT, once the rest of the system can handle it. Currently
                    // this breaks SystemUI which shows a "No SIM" icon.
                    sendEmptyMessage(EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS);
                } else {
                    logd("Ignoring simStatus: " + simStatus);
                }
@@ -326,8 +333,7 @@ public class SubscriptionInfoUpdater extends Handler {
                break;

            case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS:
                if (isAllIccIdQueryDone()) {
                    updateEmbeddedSubscriptions();
                if (updateEmbeddedSubscriptions()) {
                    SubscriptionController.getInstance().notifySubscriptionInfoChanged();
                }
                if (msg.obj != null) {
@@ -659,26 +665,33 @@ public class SubscriptionInfoUpdater extends Handler {
        mSubscriptionManager.setDefaultDataSubId(
                mSubscriptionManager.getDefaultDataSubscriptionId());

        // No need to check return value here as we notify for the above changes anyway.
        updateEmbeddedSubscriptions();

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

    /** Update the cached list of embedded subscriptions. */
    /**
     * Update the cached list of embedded subscriptions.
     *
     * @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 void updateEmbeddedSubscriptions() {
    public boolean updateEmbeddedSubscriptions() {
        // 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;
            return false;
        }

        GetEuiccProfileInfoListResult result =
                EuiccController.get().blockingGetEuiccProfileInfoList();
        if (result == null) {
            // IPC to the eUICC controller failed.
            return;
            return false;
        }

        final EuiccProfileInfo[] embeddedProfiles;
@@ -698,6 +711,13 @@ public class SubscriptionInfoUpdater extends Handler {
            embeddedIccids[i] = embeddedProfiles[i].iccid;
        }

        // Note that this only tracks whether we make any writes to the DB. It's possible this will
        // be set to true for an update even when the row contents remain exactly unchanged from
        // before, since we don't compare against the previous value. Since this is only intended to
        // avoid some spurious broadcasts (particularly for users who don't use eSIM at all), this
        // is fine.
        boolean hasChanges = false;

        // Update or insert records for all embedded subscriptions (except non-removable ones if the
        // current eUICC is non-removable, since we assume these are still accessible though not
        // returned by the eUICC controller).
@@ -722,6 +742,7 @@ public class SubscriptionInfoUpdater extends Handler {
            values.put(SubscriptionManager.IS_REMOVABLE, isRemovable);
            values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.nickname);
            values.put(SubscriptionManager.NAME_SOURCE, SubscriptionManager.NAME_SOURCE_USER_INPUT);
            hasChanges = true;
            contentResolver.update(SubscriptionManager.CONTENT_URI, values,
                    SubscriptionManager.ICC_ID + "=\"" + embeddedProfile.iccid + "\"", null);
        }
@@ -742,8 +763,11 @@ public class SubscriptionInfoUpdater extends Handler {
                    + TextUtils.join(",", iccidsToRemove) + ")";
            ContentValues values = new ContentValues();
            values.put(SubscriptionManager.IS_EMBEDDED, 0);
            hasChanges = true;
            contentResolver.update(SubscriptionManager.CONTENT_URI, values, whereClause, null);
        }

        return hasChanges;
    }

    private static int findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid) {
+31 −2
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.internal.telephony;
import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
@@ -503,7 +505,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest {
        when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate(
                new String[] { "1", "3"}, false /* removable */)).thenReturn(subInfoList);

        mUpdater.updateEmbeddedSubscriptions();
        assertTrue(mUpdater.updateEmbeddedSubscriptions());

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

        mUpdater.updateEmbeddedSubscriptions();
        assertTrue(mUpdater.updateEmbeddedSubscriptions());

        // No new entries should be created.
        verify(mSubscriptionController, times(0)).clearSubInfo();
@@ -574,4 +576,31 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest {
        assertEquals(0,
                iccid2Values.getValue().getAsInteger(SubscriptionManager.IS_EMBEDDED).intValue());
    }

    @Test
    @SmallTest
    public void testUpdateEmbeddedSubscriptions_emptyToEmpty() throws Exception {
        when(mEuiccManager.isEnabled()).thenReturn(true);
        when(mEuiccController.blockingGetEuiccProfileInfoList())
                .thenReturn(new GetEuiccProfileInfoListResult(
                        42, null /* subscriptions */, true /* removable */));

        List<SubscriptionInfo> subInfoList = new ArrayList<>();
        // 1: not embedded.
        subInfoList.add(new SubscriptionInfo(
                0, "1", 0, "", "", 0, 0, "", 0, null, 0, 0, "", false /* isEmbedded */,
                null /* accessRules */));

        when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate(
                new String[0], false /* removable */)).thenReturn(subInfoList);

        assertFalse(mUpdater.updateEmbeddedSubscriptions());

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

        // No existing entries should have been updated.
        verify(mContentProvider, never()).update(eq(SubscriptionManager.CONTENT_URI), any(),
                any(), isNull());
    }
}
 No newline at end of file