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

Commit c182c2e8 authored by Nathan Harold's avatar Nathan Harold
Browse files

Hook CarrierConfigLoader<->SubscriptionInfoUpdater

Add a hook so that when CarrierConfigs are loaded,
the data is first passed to SubscriptionInfoUpdater
to possibly update fields in the SubscriptionInfo
before the CARRIER_CONFIG_CHANGE broadcast is sent
to inform apps that the new subscription is ready
for use.

Bug: 123721160
Test: atest SubscriptionInfoUpdater
Merged-In: I864ae3355ea9689a43743e2d6fc7f8b55fef6524
Change-Id: I864ae3355ea9689a43743e2d6fc7f8b55fef6524
(cherry picked from commit 4587f197)
parent 273fdad8
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -545,6 +545,20 @@ public class SubscriptionController extends ISub.Stub {
        return null;
    }

    /**
     * Get a single subscription info record for a given subscription.
     *
     * @param subId the subId to query.
     *
     * @hide
     */
    public SubscriptionInfo getSubscriptionInfo(int subId) {
        List<SubscriptionInfo> subInfoList = getSubInfo(
                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + subId, null);
        if (subInfoList == null || subInfoList.isEmpty()) return null;
        return subInfoList.get(0);
    }

    /**
     * Get the active SubscriptionInfo associated with the iccId
     * @param iccId the IccId of SIM card
+112 −2
Original line number Diff line number Diff line
@@ -32,12 +32,15 @@ import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.SettingNotFoundException;
import android.service.carrier.CarrierService;
import android.service.euicc.EuiccProfileInfo;
import android.service.euicc.EuiccService;
import android.service.euicc.GetEuiccProfileInfoListResult;
@@ -90,6 +93,9 @@ public class SubscriptionInfoUpdater extends Handler {

    private static final String ICCID_STRING_FOR_NO_SIM = "";

    private static final ParcelUuid REMOVE_GROUP_UUID =
            ParcelUuid.fromString(CarrierConfigManager.REMOVE_GROUP_UUID_STRING);

    // Key used to read/write the current IMSI. Updated on SIM_STATE_CHANGED - LOADED.
    public static final String CURR_SUBID = "curr_subid";

@@ -111,6 +117,8 @@ public class SubscriptionInfoUpdater extends Handler {
    private int mCurrentlyActiveUserId;
    private CarrierServiceBindHelper mCarrierServiceBindHelper;

    // TODO: The SubscriptionController instance should be passed in here from PhoneFactory
    // rather than invoking the static getter all over the place.
    public SubscriptionInfoUpdater(
            Looper looper, Context context, Phone[] phone, CommandsInterface[] ci) {
        this(looper, context, phone, ci,
@@ -512,8 +520,8 @@ public class SubscriptionInfoUpdater extends Handler {
    }

    private void updateCarrierServices(int slotId, String simState) {
        CarrierConfigManager configManager = (CarrierConfigManager)
                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
        CarrierConfigManager configManager =
                (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
        configManager.updateConfigForPhoneId(slotId, simState);
        mCarrierServiceBindHelper.updateForPhoneId(slotId, simState);
    }
@@ -753,6 +761,108 @@ public class SubscriptionInfoUpdater extends Handler {
        return hasChanges;
    }

    /**
     * Called by CarrierConfigLoader to update the subscription before sending a broadcast.
     */
    public void updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId,
            String configPackageName, PersistableBundle config, Message onComplete) {
        post(() -> {
            updateSubscriptionByCarrierConfig(phoneId, configPackageName, config);
            onComplete.sendToTarget();
        });
    }

    private String getDefaultCarrierServicePackageName() {
        CarrierConfigManager configManager =
                (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
        return configManager.getDefaultCarrierServicePackageName();
    }

    private boolean isCarrierServicePackage(int phoneId, String pkgName) {
        if (pkgName.equals(getDefaultCarrierServicePackageName())) return false;

        List<String> carrierPackageNames = TelephonyManager.from(mContext)
                .getCarrierPackageNamesForIntentAndPhone(
                        new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
        if (DBG) logd("Carrier Packages For Subscription = " + carrierPackageNames);
        return carrierPackageNames != null && carrierPackageNames.contains(pkgName);
    }

    /**
     * Update the currently active Subscription based on information from CarrierConfig
     */
    @VisibleForTesting
    public void updateSubscriptionByCarrierConfig(
            int phoneId, String configPackageName, PersistableBundle config) {
        if (!SubscriptionManager.isValidPhoneId(phoneId)
                || TextUtils.isEmpty(configPackageName) || config == null) {
            if (DBG) {
                logd("In updateSubscriptionByCarrierConfig(): phoneId=" + phoneId
                        + " configPackageName=" + configPackageName + " config="
                        + ((config == null) ? "null" : config.hashCode()));
            }
            return;
        }

        SubscriptionController sc = SubscriptionController.getInstance();
        if (sc == null) {
            loge("SubscriptionController was null");
            return;
        }

        int currentSubId = sc.getSubIdUsingPhoneId(phoneId);
        if (!SubscriptionManager.isValidSubscriptionId(currentSubId)
                || currentSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
            if (DBG) logd("No subscription is active for phone being updated");
            return;
        }

        SubscriptionInfo currentSubInfo = sc.getSubscriptionInfo(currentSubId);
        if (currentSubInfo == null) {
            loge("Couldn't retrieve subscription info for current subscription");
            return;
        }

        if (!isCarrierServicePackage(phoneId, configPackageName)) {
            loge("Cannot manage subId=" + currentSubId + ", carrierPackage=" + configPackageName);
            return;
        }

        ContentValues cv = new ContentValues();
        boolean isOpportunistic = config.getBoolean(
                CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
        if (currentSubInfo.isOpportunistic() != isOpportunistic) {
            if (DBG) logd("Set SubId=" + currentSubId + " isOpportunistic=" + isOpportunistic);
            cv.put(SubscriptionManager.IS_OPPORTUNISTIC, isOpportunistic ? "1" : "0");
        }

        String groupUuidString =
                config.getString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
        ParcelUuid groupId = null;
        if (!TextUtils.isEmpty(groupUuidString)) {
            try {
                // Update via a UUID Structure to ensure consistent formatting
                ParcelUuid groupUuid = ParcelUuid.fromString(groupUuidString);
                if (groupUuid.equals(REMOVE_GROUP_UUID)
                            && currentSubInfo.getGroupUuid() != null) {
                    cv.put(SubscriptionManager.GROUP_UUID, (String) null);
                    if (DBG) logd("Group Removed for" + currentSubId);
                } else {
                    // TODO: validate and update group owner information once feasible.
                    cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString());
                    if (DBG) logd("Group Added for" + currentSubId);
                }
            } catch (IllegalArgumentException e) {
                loge("Invalid Group UUID=" + groupUuidString);
            }
        }
        if (cv.size() > 0 && mContext.getContentResolver().update(SubscriptionManager
                    .getUriForSubscriptionId(currentSubId), cv, null, null) > 0) {
            sc.refreshCachedActiveSubscriptionInfoList();
            sc.notifySubscriptionInfoChanged();
        }
    }

    private static int findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid) {
        for (int i = 0; i < list.size(); i++) {
            if (TextUtils.equals(iccid, list.get(i).getIccId())) {
+126 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ 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.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.any;
@@ -40,6 +41,8 @@ import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.HandlerThread;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.service.euicc.EuiccProfileInfo;
import android.service.euicc.EuiccService;
import android.service.euicc.GetEuiccProfileInfoListResult;
@@ -64,6 +67,7 @@ import org.mockito.stubbing.Answer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

@@ -571,4 +575,126 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest {
                eq(FAKE_SUB_ID_1));
        verify(mSubscriptionController, times(0)).clearSubInfo();
    }

    PersistableBundle getCarrierConfigForSubInfoUpdate(
            boolean isOpportunistic, String groupUuid) {
        PersistableBundle p = new PersistableBundle();
        p.putBoolean(CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, isOpportunistic);
        p.putString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, groupUuid);
        return p;
    }

    @Test
    @SmallTest
    public void testUpdateFromCarrierConfigOpportunisticUnchanged() throws Exception {
        final int phoneId = mPhone.getPhoneId();
        String carrierPackageName = "FakeCarrierPackageName";

        doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
        doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1));
        doReturn(Collections.singletonList(carrierPackageName)).when(mTelephonyManager)
                .getCarrierPackageNamesForIntentAndPhone(any(), eq(phoneId));
        ((MockContentResolver) mContext.getContentResolver()).addProvider(
                SubscriptionManager.CONTENT_URI.getAuthority(),
                new FakeSubscriptionContentProvider());

        mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(),
                carrierPackageName, new PersistableBundle());

        verify(mContentProvider, never()).update(any(), any(), any(), any());
        verify(mSubscriptionController, never()).refreshCachedActiveSubscriptionInfoList();
        verify(mSubscriptionController, never()).notifySubscriptionInfoChanged();
    }

    @Test
    @SmallTest
    public void testUpdateFromCarrierConfigOpportunisticSetOpportunistic() throws Exception {
        final int phoneId = mPhone.getPhoneId();
        PersistableBundle carrierConfig = getCarrierConfigForSubInfoUpdate(
                true, "");
        String carrierPackageName = "FakeCarrierPackageName";

        doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
        doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1));
        doReturn(false).when(mSubInfo).isOpportunistic();
        doReturn(Collections.singletonList(carrierPackageName)).when(mTelephonyManager)
                .getCarrierPackageNamesForIntentAndPhone(any(), eq(phoneId));
        ((MockContentResolver) mContext.getContentResolver()).addProvider(
                SubscriptionManager.CONTENT_URI.getAuthority(),
                new FakeSubscriptionContentProvider());

        mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(),
                carrierPackageName, carrierConfig);

        ArgumentCaptor<ContentValues> cvCaptor = ArgumentCaptor.forClass(ContentValues.class);
        verify(mContentProvider, times(1)).update(
                eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)),
                cvCaptor.capture(), eq(null), eq(null));
        assertEquals(1, cvCaptor.getValue().getAsInteger(
                SubscriptionManager.IS_OPPORTUNISTIC).intValue());
        assertEquals(1, cvCaptor.getValue().size());
        verify(mSubscriptionController, times(1)).refreshCachedActiveSubscriptionInfoList();
        verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
    }

    @Test
    @SmallTest
    public void testUpdateFromCarrierConfigOpportunisticAddToGroup() throws Exception {
        final int phoneId = mPhone.getPhoneId();
        PersistableBundle carrierConfig = getCarrierConfigForSubInfoUpdate(
                true, "11111111-2222-3333-4444-555555555555");
        String carrierPackageName = "FakeCarrierPackageName";

        doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
        doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1));
        doReturn(Collections.singletonList(carrierPackageName)).when(mTelephonyManager)
                .getCarrierPackageNamesForIntentAndPhone(any(), eq(phoneId));
        ((MockContentResolver) mContext.getContentResolver()).addProvider(
                SubscriptionManager.CONTENT_URI.getAuthority(),
                new FakeSubscriptionContentProvider());

        mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(),
                carrierPackageName, carrierConfig);

        ArgumentCaptor<ContentValues> cvCaptor = ArgumentCaptor.forClass(ContentValues.class);
        verify(mContentProvider, times(1)).update(
                eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)),
                cvCaptor.capture(), eq(null), eq(null));
        assertEquals(1, cvCaptor.getValue().getAsInteger(
                SubscriptionManager.IS_OPPORTUNISTIC).intValue());
        assertEquals("11111111-2222-3333-4444-555555555555",
                cvCaptor.getValue().getAsString(SubscriptionManager.GROUP_UUID));
        assertEquals(2, cvCaptor.getValue().size());
    }

    @Test
    @SmallTest
    public void testUpdateFromCarrierConfigOpportunisticRemoveFromGroup() throws Exception {
        final int phoneId = mPhone.getPhoneId();
        PersistableBundle carrierConfig = getCarrierConfigForSubInfoUpdate(
                true, "00000000-0000-0000-0000-000000000000");
        String carrierPackageName = "FakeCarrierPackageName";

        doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
        doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1));
        doReturn(ParcelUuid.fromString("11111111-2222-3333-4444-555555555555"))
            .when(mSubInfo).getGroupUuid();
        doReturn(Collections.singletonList(carrierPackageName)).when(mTelephonyManager)
                .getCarrierPackageNamesForIntentAndPhone(any(), eq(phoneId));
        ((MockContentResolver) mContext.getContentResolver()).addProvider(
                SubscriptionManager.CONTENT_URI.getAuthority(),
                new FakeSubscriptionContentProvider());

        mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(),
                carrierPackageName, carrierConfig);

        ArgumentCaptor<ContentValues> cvCaptor = ArgumentCaptor.forClass(ContentValues.class);
        verify(mContentProvider, times(1)).update(
                eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)),
                cvCaptor.capture(), eq(null), eq(null));
        assertEquals(1, cvCaptor.getValue().getAsInteger(
                SubscriptionManager.IS_OPPORTUNISTIC).intValue());
        assertNull(cvCaptor.getValue().getAsString(SubscriptionManager.GROUP_UUID));
        assertEquals(2, cvCaptor.getValue().size());
    }
}