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

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

Merge "Adding subscription group owner." into qt-dev

parents e7a1c604 5b7544f2
Loading
Loading
Loading
Loading
+73 −14
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.util.ArrayUtils;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -388,6 +389,8 @@ public class SubscriptionController extends ISub.Stub {
                SubscriptionManager.PROFILE_CLASS));
        int subType = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.SUBSCRIPTION_TYPE));
        String groupOwner = getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER,
                /*defaultVal*/ null);

        if (VDBG) {
            String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId);
@@ -411,11 +414,18 @@ public class SubscriptionController extends ISub.Stub {
        SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
                carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
                countryIso, isEmbedded, accessRules, cardId, publicCardId, isOpportunistic,
                groupUUID, false /* isGroupDisabled */, carrierId, profileClass, subType);
                groupUUID, false /* isGroupDisabled */, carrierId, profileClass, subType,
                groupOwner);
        info.setAssociatedPlmns(ehplmns, hplmns);
        return info;
    }

    private String getOptionalStringFromCursor(Cursor cursor, String column, String defaultVal) {
        // Return defaultVal if the column doesn't exist.
        int columnIndex = cursor.getColumnIndex(column);
        return (columnIndex == -1) ? defaultVal : cursor.getString(columnIndex);
    }

    /**
     * Query SubInfoRecord(s) from subinfo database
     * @param selection A filter declaring which rows to return
@@ -2868,6 +2878,7 @@ public class SubscriptionController extends ISub.Stub {

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

@@ -2885,14 +2896,31 @@ 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) {
    private String getOwnerPackageOfSubGroup(ParcelUuid groupUuid) {
        if (groupUuid == null) return null;

        List<SubscriptionInfo> infoList = getSubInfo(SubscriptionManager.GROUP_UUID
                + "=\'" + groupUuid.toString() + "\'", null);

        return ArrayUtils.isEmpty(infoList) ? null : infoList.get(0).getGroupOwner();
    }

    /**
     *
     * @param groupUuid a UUID assigned to the subscription group.
     * @param callingPackage the package making the IPC.
     * @return if callingPackage has carrier privilege on sublist.
     *
     */
    public boolean canPackageManageGroup(ParcelUuid groupUuid, String callingPackage) {
        if (groupUuid == null) {
            throw new IllegalArgumentException("Invalid groupUuid");
        }

        if (TextUtils.isEmpty(callingPackage)) {
            throw new IllegalArgumentException("Empty callingPackage");
        }

        List<SubscriptionInfo> infoList;

        // Getting all subscriptions in the group.
@@ -2904,13 +2932,36 @@ public class SubscriptionController extends ISub.Stub {
            Binder.restoreCallingIdentity(identity);
        }

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

        // If the calling package is the group owner, skip carrier permission check and return
        // true as it was done before.
        if (callingPackage.equals(infoList.get(0).getGroupOwner())) return true;

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

    private int updateGroupOwner(ParcelUuid groupUuid, String groupOwner) {
        // If the existing group owner is different from current caller, make caller the new
        // owner of all subscriptions in group.
        // This is for use-case of:
        // 1) Both package1 and package2 has permission (MODIFY_PHONE_STATE or carrier
        // privilege permission) of all related subscriptions.
        // 2) Package 1 created a group.
        // 3) Package 2 wants to add a subscription into it.
        // Step 3 should be granted as all operations are permission based. Which means as
        // long as the package passes the permission check, it can modify the subscription
        // and the group. And package 2 becomes the new group owner as it's the last to pass
        // permission checks on all members.
        ContentValues value = new ContentValues(1);
        value.put(SubscriptionManager.GROUP_OWNER, groupOwner);
        return mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI,
                value, SubscriptionManager.GROUP_UUID + "=\"" + groupUuid + "\"", null);
    }

    @Override
@@ -2924,6 +2975,8 @@ public class SubscriptionController extends ISub.Stub {
            throw new IllegalArgumentException("Invalid groupUuid");
        }

        // Makes sure calling package matches caller UID.
        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
        // 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)
@@ -2949,11 +3002,11 @@ public class SubscriptionController extends ISub.Stub {
            if (DBG) logdl("addSubscriptionsIntoGroup update DB result: " + result);

            if (result > 0) {
                updateGroupOwner(groupUuid, callingPackage);
                refreshCachedActiveSubscriptionInfoList();
                notifySubscriptionInfoChanged();
                MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid);
            }

        } finally {
            Binder.restoreCallingIdentity(identity);
        }
@@ -2981,12 +3034,15 @@ public class SubscriptionController extends ISub.Stub {
        if (subIdList == null || subIdList.length == 0) {
            return;
        }

        // Makes sure calling package matches caller UID.
        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
        // 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.
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                != PERMISSION_GRANTED && !checkCarrierPrivilegeOnSubList(
                subIdList, callingPackage)) {
                != PERMISSION_GRANTED && !(checkCarrierPrivilegeOnSubList(subIdList, callingPackage)
                && canPackageManageGroup(groupUuid, callingPackage))) {
            throw new SecurityException("removeSubscriptionsFromGroup needs MODIFY_PHONE_STATE or"
                    + " carrier privilege permission on all specified subscriptions");
        }
@@ -3004,14 +3060,17 @@ public class SubscriptionController extends ISub.Stub {
            }
            ContentValues value = new ContentValues();
            value.put(SubscriptionManager.GROUP_UUID, (String) null);
            value.put(SubscriptionManager.GROUP_OWNER, (String) null);
            int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI,
                    value, getSelectionForSubIdList(subIdList), null);

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

            if (result > 0) {
                updateGroupOwner(groupUuid, callingPackage);
                refreshCachedActiveSubscriptionInfoList();

                notifySubscriptionInfoChanged();
            }
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
+9 −5
Original line number Diff line number Diff line
@@ -858,19 +858,23 @@ public class SubscriptionInfoUpdater extends Handler {

        String groupUuidString =
                config.getString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
        ParcelUuid groupId = null;
        ParcelUuid groupUuid = null;
        if (!TextUtils.isEmpty(groupUuidString)) {
            try {
                // Update via a UUID Structure to ensure consistent formatting
                ParcelUuid groupUuid = ParcelUuid.fromString(groupUuidString);
                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.
                } else if (SubscriptionController.getInstance().canPackageManageGroup(groupUuid,
                        configPackageName)) {
                    cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString());
                    cv.put(SubscriptionManager.GROUP_OWNER, configPackageName);
                    if (DBG) logd("Group Added for" + currentSubId);
                } else {
                    loge("configPackageName " + configPackageName + " doesn't own grouUuid "
                            + groupUuid);
                }
            } catch (IllegalArgumentException e) {
                loge("Invalid Group UUID=" + groupUuidString);
@@ -880,7 +884,7 @@ public class SubscriptionInfoUpdater extends Handler {
                    .getUriForSubscriptionId(currentSubId), cv, null, null) > 0) {
            sc.refreshCachedActiveSubscriptionInfoList();
            sc.notifySubscriptionInfoChanged();
            MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupId);
            MultiSimSettingController.getInstance().onSubscriptionGroupChanged(groupUuid);
        }
    }

+2 −1
Original line number Diff line number Diff line
@@ -107,7 +107,8 @@ public class FakeTelephonyProvider extends MockContentProvider {
                    + SubscriptionManager.PROFILE_CLASS
                    + " INTEGER DEFAULT " + SubscriptionManager.PROFILE_CLASS_DEFAULT + ","
                    + SubscriptionManager.SUBSCRIPTION_TYPE + " INTEGER DEFAULT 0,"
                    + SubscriptionManager.WHITE_LISTED_APN_DATA + " INTEGER DEFAULT 0"
                    + SubscriptionManager.WHITE_LISTED_APN_DATA + " INTEGER DEFAULT 0,"
                    + SubscriptionManager.GROUP_OWNER + " TEXT"
                    + ");";
        }

+3 −3
Original line number Diff line number Diff line
@@ -72,19 +72,19 @@ public class MultiSimSettingControllerTest extends TelephonyTest {
            "T-mobile", 0, 255, "12345", 0, null, "310", "260",
            "156", false, null, null, -1, false, mGroupUuid1.toString(), false,
            TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT,
            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null);

    private SubscriptionInfo mSubInfo3 = new SubscriptionInfo(3, "subInfo3 IccId", -1, "T-mobile",
            "T-mobile", 0, 255, "12345", 0, null, "310", "260",
            "156", false, null, null, -1, false, mGroupUuid1.toString(), false,
            TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT,
            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null);

    private SubscriptionInfo mSubInfo4 = new SubscriptionInfo(4, "subInfo4 IccId", -1, "T-mobile",
            "T-mobile", 0, 255, "12345", 0, null, "310", "260",
            "156", false, null, null, -1, false, mGroupUuid1.toString(), false,
            TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT,
            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null);

    @Before
    public void setUp() throws Exception {
+50 −5
Original line number Diff line number Diff line
@@ -751,14 +751,51 @@ public class SubscriptionControllerTest extends TelephonyTest {
        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2);

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

        mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                new int[] {2}, groupId, mContext.getOpPackageName());
                new int[] {2}, groupId, "packageName1");
        List<SubscriptionInfo> infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupId, "packageName1");
        assertEquals(2, infoList.size());
        assertEquals(1, infoList.get(0).getSubscriptionId());
        assertEquals(2, infoList.get(1).getSubscriptionId());

        mSubscriptionControllerUT.removeSubscriptionsFromGroup(
                new int[] {2}, groupId, mContext.getOpPackageName());
                new int[] {2}, groupId, "packageName1");
        infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupId, "packageName1");
        assertEquals(1, infoList.size());
        assertEquals(1, infoList.get(0).getSubscriptionId());

        // Make sub 1 inactive.
        mSubscriptionControllerUT.clearSubInfoRecord(0);

        try {
            mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                    new int[] {2}, groupId, "packageName2");
            fail("addSubscriptionsIntoGroup should fail with wrong callingPackage name");
        } catch (SecurityException e) {
            // Expected result.
        }

        // Adding and removing subscription should still work for packageName1, as it's the group
        // owner who created the group earlier..
        mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                new int[] {2}, groupId, "packageName1");
        infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupId, "packageName1");
        assertEquals(2, infoList.size());
        assertEquals(1, infoList.get(0).getSubscriptionId());
        assertEquals(2, infoList.get(1).getSubscriptionId());

        mSubscriptionControllerUT.removeSubscriptionsFromGroup(
                new int[] {2}, groupId, "packageName1");
        infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupId, "packageName1");
        assertEquals(1, infoList.size());
        assertEquals(1, infoList.get(0).getSubscriptionId());
    }

    @Test
@@ -826,7 +863,7 @@ public class SubscriptionControllerTest extends TelephonyTest {
        assertTrue(TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, 1,
                mContext.getOpPackageName(), "getSubscriptionsInGroup"));

        int[] subIdList = new int[] {1, 2};
        int[] subIdList = new int[] {1};
        ParcelUuid groupUuid = mSubscriptionControllerUT.createSubscriptionGroup(
                subIdList, mContext.getOpPackageName());
        assertNotEquals(null, groupUuid);
@@ -835,8 +872,16 @@ public class SubscriptionControllerTest extends TelephonyTest {
        List<SubscriptionInfo> infoList = mSubscriptionControllerUT
                .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
        assertNotEquals(null, infoList);
        assertEquals(2, infoList.size());
        assertEquals(1, infoList.size());
        assertEquals(1, infoList.get(0).getSubscriptionId());

        subIdList = new int[] {2};

        mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                subIdList, groupUuid, mContext.getOpPackageName());
        infoList = mSubscriptionControllerUT
                .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
        assertEquals(2, infoList.size());
        assertEquals(2, infoList.get(1).getSubscriptionId());

        // Remove group of sub 1.
Loading