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

Commit 9e8d41c7 authored by Xiangyu/Malcolm Chen's avatar Xiangyu/Malcolm Chen Committed by Android (Google) Code Review
Browse files

Merge "Implement addSubscriptionsIntoGroup." into qt-dev

parents 95ffdffd 9572bc99
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -144,14 +144,18 @@ public class MultiSimSettingController {
     * When a subscription group is created or new subscriptions are added in the group, make
     * sure the settings among them are synced.
     */
    public synchronized void onSubscriptionGroupCreated(int[] subGroup) {
        if (DBG) log("onSubscriptionGroupCreated");
        if (subGroup == null || subGroup.length == 0) return;
    public synchronized void onSubscriptionGroupChanged(ParcelUuid groupUuid) {
        if (DBG) log("onSubscriptionGroupChanged");

        List<SubscriptionInfo> infoList = mSubController.getSubscriptionsInGroup(
                groupUuid, mContext.getOpPackageName());
        if (infoList == null || infoList.isEmpty()) return;

        // Get a reference subscription to copy settings from.
        // TODO: the reference sub should be passed in from external caller.
        int refSubId = subGroup[0];
        for (int subId : subGroup) {
        int refSubId = infoList.get(0).getSubscriptionId();
        for (SubscriptionInfo info : infoList) {
            int subId = info.getSubscriptionId();
            if (mSubController.isActiveSubId(subId) && !mSubController.isOpportunistic(subId)) {
                refSubId = subId;
                break;
+96 −17
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.RadioAccessFamily;
import android.telephony.Rlog;
import android.telephony.SubscriptionInfo;
@@ -100,6 +101,8 @@ public class SubscriptionController extends ISub.Stub {
    static final boolean DBG_CACHE = false;
    static final int MAX_LOCAL_LOG_LINES = 500; // TODO: Reduce to 100 when 17678050 is fixed
    private static final int DEPRECATED_SETTING = -1;
    private static final ParcelUuid INVALID_GROUP_UUID =
            ParcelUuid.fromString(CarrierConfigManager.REMOVE_GROUP_UUID_STRING);
    private ScLocalLog mLocalLog = new ScLocalLog(MAX_LOCAL_LOG_LINES);

    // Lock that both mCacheActiveSubInfoList and mCacheOpportunisticSubInfoList use.
@@ -2793,6 +2796,8 @@ public class SubscriptionController extends ISub.Stub {
     *
     * @throws SecurityException if the caller doesn't meet the requirements
     *             outlined above.
     * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist.
     * @throws IllegalStateException if Telephony service is in bad state.
     *
     * @param subIdList list of subId that will be in the same group
     * @return groupUUID a UUID assigned to the subscription group. It returns
@@ -2802,15 +2807,15 @@ public class SubscriptionController extends ISub.Stub {
    @Override
    public ParcelUuid createSubscriptionGroup(int[] subIdList, String callingPackage) {
        if (subIdList == null || subIdList.length == 0) {
            return null;
            throw new IllegalArgumentException("Invalid subIdList " + subIdList);
        }
        // If it doesn't have modify phone state permission, or carrier privilege permission,
        // a SecurityException will be thrown. If it's due to invalid parameter or internal state,
        // it will return null.
        // a SecurityException will be thrown.
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                != PERMISSION_GRANTED && !checkCarrierPrivilegeOnSubList(
                        subIdList, callingPackage)) {
            return null;
            throw new SecurityException("CreateSubscriptionGroup needs MODIFY_PHONE_STATE or"
                    + " carrier privilege permission on all specified subscriptions");
        }

        long identity = Binder.clearCallingIdentity();
@@ -2830,7 +2835,7 @@ public class SubscriptionController extends ISub.Stub {

            notifySubscriptionInfoChanged();

            MultiSimSettingController.getInstance().onSubscriptionGroupCreated(subIdList);
            MultiSimSettingController.getInstance().onSubscriptionGroupChanged(groupUUID);

            return groupUUID;
        } finally {
@@ -2838,10 +2843,78 @@ public class SubscriptionController extends ISub.Stub {
        }
    }

    // TODO: when having a group owner or packageName for subscription, use that to check.
    // Currently for this method to return false, all subscriptions in the group needs to have
    // carrier privilege rules loaded, which means active or available.
    private boolean canPackageManageGroup(ParcelUuid groupUuid, String callingPackage) {
        if (groupUuid == null) {
            throw new IllegalArgumentException("Invalid groupUuid");
        }

        List<SubscriptionInfo> infoList;

        // Getting all subscriptions in the group.
        long identity = Binder.clearCallingIdentity();
        try {
            infoList = getSubInfo(SubscriptionManager.GROUP_UUID
                    + "=\'" + groupUuid.toString() + "\'", null);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }

        if (infoList == null || infoList.isEmpty()) {
            throw new IllegalArgumentException("No subscription in group " + groupUuid);
        }

        // Check carrier privilege for all subscriptions in the group.
        int[] subIdArray = infoList.stream().mapToInt(info -> info.getSubscriptionId()).toArray();
        return checkCarrierPrivilegeOnSubList(subIdArray, callingPackage);
    }

    @Override
    public void addSubscriptionsIntoGroup(int[] subIdList, ParcelUuid groupUuid,
            String callingPackage) {
        // TODO: implement it.
        if (subIdList == null || subIdList.length == 0) {
            throw new IllegalArgumentException("Invalid subId list");
        }

        if (groupUuid == null || groupUuid.equals(INVALID_GROUP_UUID)) {
            throw new IllegalArgumentException("Invalid groupUuid");
        }

        // If it doesn't have modify phone state permission, or carrier privilege permission,
        // a SecurityException will be thrown.
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                != PERMISSION_GRANTED && !(checkCarrierPrivilegeOnSubList(subIdList, callingPackage)
                && canPackageManageGroup(groupUuid, callingPackage))) {
            throw new SecurityException("Requires MODIFY_PHONE_STATE or carrier privilege"
                    + " permissions on subscriptions and the group.");
        }

        long identity = Binder.clearCallingIdentity();

        try {
            if (DBG) {
                logdl("addSubscriptionsIntoGroup sub list "
                        + Arrays.toString(subIdList) + " into group " + groupUuid);
            }

            ContentValues value = new ContentValues();
            value.put(SubscriptionManager.GROUP_UUID, groupUuid.toString());
            int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI,
                    value, getSelectionForSubIdList(subIdList), null);

            if (DBG) logdl("addSubscriptionsIntoGroup update DB result: " + result);

            if (result > 0) {
                refreshCachedActiveSubscriptionInfoList();
                notifySubscriptionInfoChanged();
                MultiSimSettingController.getInstance().onSubscriptionGroupChanged(groupUuid);
            }

        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
@@ -2872,7 +2945,8 @@ public class SubscriptionController extends ISub.Stub {
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                != PERMISSION_GRANTED && !checkCarrierPrivilegeOnSubList(
                subIdList, callingPackage)) {
            return;
            throw new SecurityException("removeSubscriptionsFromGroup needs MODIFY_PHONE_STATE or"
                    + " carrier privilege permission on all specified subscriptions");
        }

        long identity = Binder.clearCallingIdentity();
@@ -2906,10 +2980,10 @@ public class SubscriptionController extends ISub.Stub {
     *  The check can either be processed against access rules on currently active SIM cards, or
     *  the access rules we keep in our database for currently inactive eSIMs.
     *
     *  Throws {@link SecurityException} if it fails.
     * @throws IllegalArgumentException if the some subId is invalid or doesn't exist.
     * @throws IllegalStateException if Telephony is in bad state.
     *
     *  @return true if checking passes on all subId. false if subId is invalid or doesn't exist,
     *  or sub controller is not ready yet.
     *  @return true if checking passes on all subId, false otherwise.
     */
    private boolean checkCarrierPrivilegeOnSubList(int[] subIdList, String callingPackage) {
        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
@@ -2920,7 +2994,7 @@ public class SubscriptionController extends ISub.Stub {
        for (int subId : subIdList) {
            if (isActiveSubId(subId)) {
                if (!mTelephonyManager.hasCarrierPrivileges(subId)) {
                    throw new SecurityException("Need carrier privilege on subId " + subId);
                    return false;
                }
            } else {
                checkSubList.add(subId);
@@ -2935,22 +3009,27 @@ public class SubscriptionController extends ISub.Stub {

        try {
            if (!isSubInfoReady()) {
                if (DBG) logdl("[getSubscriptionInfoList] Sub Controller not ready");
                return false;
                throw new IllegalStateException("Sub Controller not ready");
            }

            // Check access rules for each sub info.
            SubscriptionManager subscriptionManager = (SubscriptionManager)
                    mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
            List<SubscriptionInfo> subList = getSubInfo(getSelectionForSubIdList(subIdList), null);
            for (SubscriptionInfo subInfo : subList) {
            List<SubscriptionInfo> subInfoList = getSubInfo(
                    getSelectionForSubIdList(subIdList), null);

            // Didn't find all the subscriptions specified in subIdList.
            if (subInfoList == null || subInfoList.size() != subIdList.length) {
                throw new IllegalArgumentException("Invalid subInfoList.");
            }

            for (SubscriptionInfo subInfo : subInfoList) {
                if (checkSubList.contains(subInfo.getSubscriptionId())) {
                    if (subInfo.isEmbedded() && subscriptionManager.canManageSubscription(
                            subInfo, callingPackage)) {
                        checkSubList.remove(subInfo.getSubscriptionId());
                    } else {
                        throw new SecurityException("Need carrier privilege on subId "
                                + subInfo.getSubscriptionId());
                        return false;
                    }
                }
            }
+1 −0
Original line number Diff line number Diff line
@@ -860,6 +860,7 @@ public class SubscriptionInfoUpdater extends Handler {
                    .getUriForSubscriptionId(currentSubId), cv, null, null) > 0) {
            sc.refreshCachedActiveSubscriptionInfoList();
            sc.notifySubscriptionInfoChanged();
            MultiSimSettingController.getInstance().onSubscriptionGroupChanged(groupId);
        }
    }

+2 −4
Original line number Diff line number Diff line
@@ -176,7 +176,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest {
        // Create subscription grouping.
        doReturn(Arrays.asList(mSubInfo2, mSubInfo3, mSubInfo4)).when(mSubControllerMock)
                .getSubscriptionsInGroup(any(), anyString());
        mMultiSimSettingControllerUT.onSubscriptionGroupCreated(new int[] {2, 3, 4});
        mMultiSimSettingControllerUT.onSubscriptionGroupChanged(mGroupUuid1);
        // This should result in setting sync.
        assertTrue(GlobalSettingsHelper.getBoolean(
                mContext, Settings.Global.MOBILE_DATA, 3, false));
@@ -265,9 +265,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest {
        // Group sub 1 with sub 2.
        doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock)
                .getSubscriptionsInGroup(any(), anyString());
        doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock)
                .getSubscriptionsInGroup(any(), anyString());
        mMultiSimSettingControllerUT.onSubscriptionGroupCreated(new int[] {1, 2});
        mMultiSimSettingControllerUT.onSubscriptionGroupChanged(mGroupUuid1);
        // This should result in setting sync.
        verify(mDataEnabledSettingsMock1).setUserDataEnabled(false);
        assertFalse(GlobalSettingsHelper.getBoolean(
+37 −1
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ public class SubscriptionControllerTest extends TelephonyTest {
    private FakeTelephonyProvider mFakeTelephonyProvider;
    @Mock
    private ITelephonyRegistry.Stub mTelephonyRegisteryMock;
    @Mock
    private MultiSimSettingController mMultiSimSettingControllerMock;

    private static final String MAC_ADDRESS_PREFIX = "mac_";
    private static final String DISPLAY_NAME_PREFIX = "my_phone_";
@@ -79,6 +81,8 @@ public class SubscriptionControllerTest extends TelephonyTest {
        mMockContentResolver.addProvider(SubscriptionManager.CONTENT_URI.getAuthority(),
                mFakeTelephonyProvider);
        replaceInstance(SubscriptionController.class, "sInstance", null, null);
        replaceInstance(MultiSimSettingController.class, "sInstance", null,
                mMultiSimSettingControllerMock);

        SubscriptionController.init(mContext, null);
        mSubscriptionControllerUT = SubscriptionController.getInstance();
@@ -605,7 +609,7 @@ public class SubscriptionControllerTest extends TelephonyTest {

    @Test
    @SmallTest
    public void testSetSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
    public void testCreateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
        testInsertSim();
        // Adding a second profile and mark as embedded.
        // TODO b/123300875 slot index 1 is not expected to be valid
@@ -663,6 +667,38 @@ public class SubscriptionControllerTest extends TelephonyTest {
        assertNotEquals(groupId, newGroupId);
    }

    @Test
    @SmallTest
    public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
        testInsertSim();
        // Adding a second profile and mark as embedded.
        // TODO b/123300875 slot index 1 is not expected to be valid
        mSubscriptionControllerUT.addSubInfoRecord("test2", 1);
        ContentValues values = new ContentValues();
        values.put(SubscriptionManager.IS_EMBEDDED, 1);
        mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null);
        mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();

        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE);

        int[] subIdList = new int[] {1};

        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2);

        ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup(
                subIdList, mContext.getOpPackageName());
        assertNotEquals(null, groupId);

        mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                new int[] {2}, groupId, mContext.getOpPackageName());

        mSubscriptionControllerUT.removeSubscriptionsFromGroup(
                new int[] {2}, groupId, mContext.getOpPackageName());
    }

    @Test
    @SmallTest
    public void testDisabledSubscriptionGroup() throws Exception {