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

Commit dbf17e0b authored by Hyosun Kim's avatar Hyosun Kim Committed by Android (Google) Code Review
Browse files

Merge "To read the group UUID, the calling app either needs carrier privileges...

Merge "To read the group UUID, the calling app either needs carrier privileges or the READ_PHONE_STATE permission and access to device identifiers." into tm-qpr-dev
parents 4a622474 73f76641
Loading
Loading
Loading
Loading
+39 −2
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -162,6 +165,15 @@ public class SubscriptionController extends ISub.Stub {
    protected TelephonyManager mTelephonyManager;
    protected UiccController mUiccController;

    /**
     * Apps targeting on Android T and beyond will get an empty list if there is no access to device
     * identifiers nor has carrier privileges when calling
     * SubscriptionManager#getSubscriptionsInGroup.
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    public static final long REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L;

    private AppOpsManager mAppOps;

    // Allows test mocks to avoid SELinux failures on invalidate calls.
@@ -3965,10 +3977,20 @@ public class SubscriptionController extends ISub.Stub {
     * Get subscriptionInfo list of subscriptions that are in the same group of given subId.
     * See {@link #createSubscriptionGroup(int[], String)} for more details.
     *
     * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE}
     * permission or had carrier privilege permission on the subscription.
     * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE}
     * or carrier privilege permission on the subscription.
     * {@link TelephonyManager#hasCarrierPrivileges(int)}
     *
     * <p>Starting with API level 33, the caller needs READ_PHONE_STATE and access to device
     * identifiers to get the list of subscriptions associated with a group UUID.
     * This method can be invoked if one of the following requirements is met:
     * <ul>
     *     <li>If the app has carrier privilege permission.
     *     {@link TelephonyManager#hasCarrierPrivileges()}
     *     <li>If the app has {@link android.Manifest.permission#READ_PHONE_STATE} and
     *     access to device identifiers.
     * </ul>
     *
     * @throws SecurityException if the caller doesn't meet the requirements
     *             outlined above.
     *
@@ -3995,6 +4017,21 @@ public class SubscriptionController extends ISub.Stub {
            Binder.restoreCallingIdentity(identity);
        }

        // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to
        // device identifiers, it will return an empty list.
        if (CompatChanges.isChangeEnabled(
                REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, Binder.getCallingUid())) {
            try {
                if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
                        callingPackage, callingFeatureId, "getSubscriptionsInGroup")) {
                    EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid());
                    return new ArrayList<>();
                }
            } catch (SecurityException e) {
                EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid());
                return new ArrayList<>();
            }
        }
        return subInfoList.stream().filter(info -> {
            if (!groupUuid.equals(info.getGroupUuid())) return false;
            int subId = info.getSubscriptionId();
+81 −14
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.internal.telephony;

import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION;

import static com.android.internal.telephony.SubscriptionController.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID;
import static com.android.internal.telephony.uicc.IccCardStatus.CardState.CARDSTATE_PRESENT;

import static org.junit.Assert.assertEquals;
@@ -33,7 +34,9 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -41,6 +44,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.Manifest;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
@@ -68,9 +72,14 @@ import com.android.internal.telephony.uicc.IccCardStatus;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccSlot;

import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.mockito.ArgumentCaptor;

import java.util.ArrayList;
@@ -108,6 +117,9 @@ public class SubscriptionControllerTest extends TelephonyTest {
    private static final String DISPLAY_NUMBER = "123456";
    private static final String DISPLAY_NAME = "testing_display_name";

    @Rule
    public TestRule mCompatChangeRule = new PlatformCompatChangeRule();

    @Before
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
@@ -1099,6 +1111,7 @@ public class SubscriptionControllerTest extends TelephonyTest {

    @Test
    @SmallTest
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testAddSubscriptionIntoGroupWithCarrierPrivilegePermission() throws Exception {
        testInsertSim();
        // Adding a second profile and mark as embedded.
@@ -1115,6 +1128,7 @@ public class SubscriptionControllerTest extends TelephonyTest {

        // Create group for sub 1.
        int[] subIdList = new int[] {1};
        doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList();
        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
        ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup(
                subIdList, "packageName1");
@@ -1150,6 +1164,7 @@ public class SubscriptionControllerTest extends TelephonyTest {

    @Test
    @SmallTest
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
        testInsertSim();
        // Adding a second profile and mark as embedded.
@@ -1166,6 +1181,7 @@ public class SubscriptionControllerTest extends TelephonyTest {

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

        doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList();
        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2);

@@ -1271,6 +1287,7 @@ public class SubscriptionControllerTest extends TelephonyTest {

    @Test
    @SmallTest
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testSetSubscriptionGroup() throws Exception {
        testInsertSim();
        // Adding a second profile and mark as embedded.
@@ -1293,6 +1310,7 @@ public class SubscriptionControllerTest extends TelephonyTest {
        assertNotEquals(null, groupUuid);

        // Sub 1 and sub 2 should be in same group.
        doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList();
        List<SubscriptionInfo> infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag());
        assertNotEquals(null, infoList);
@@ -1705,42 +1723,88 @@ public class SubscriptionControllerTest extends TelephonyTest {
    }

    @Test
    public void testGetSubscriptionsInGroupWithNoPermission() throws Exception {
        // If the calling package does not have the READ_PHONE_STATE permission or carrier
        // privileges then getSubscriptionsInGroup should throw a SecurityException when the
        // READ_PHONE_STATE permission check is performed.
    @DisableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testGetSubscriptionsInGroupWithReadPhoneState() throws Exception {
        // For backward compatibility test
        ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest();
        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
        setupReadPhoneNumbersTest();
        setIdentifierAccess(false);

        List<SubscriptionInfo> subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupUuid, mCallingPackage, mCallingFeature);

        assertTrue(subInfoList.size() > 0);
        for (SubscriptionInfo info : subInfoList) {
            assertEquals(UNAVAILABLE_ICCID, info.getIccId());
            assertEquals(UNAVAILABLE_ICCID, info.getCardString());
            assertEquals(UNAVAILABLE_NUMBER, info.getNumber());
        }
    }

    @Test
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testGetSubscriptionsInGroupWithoutAppropriatePermission() throws Exception {
        ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest();

        // no permission
        setNoPermission();
        try {
            mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage,
                    mCallingFeature);
            fail("getSubscriptionsInGroup should fail when invoked with no permissions");
        } catch (SecurityException expected) {
        }

        // only has the device identifiers permission
        setIdentifierAccess(true);
        try {
            mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage,
                    mCallingFeature);
            fail("getSubscriptionsInGroup should fail when invoked with no"
                    + "READ_PHONE_STATE permissions");
        } catch (SecurityException expected) {
        }

        // only has the READ_PHONE_STATE permission
        setIdentifierAccess(false);
        setReadPhoneState();
        List<SubscriptionInfo> subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupUuid, mCallingPackage, mCallingFeature);
        assertNotNull(subInfoList);
        assertTrue(subInfoList.isEmpty());
    }

    @Test
    public void testGetSubscriptionsInGroupWithReadPhoneState() throws Exception {
        // If the calling package only has the READ_PHONE_STATE permission then
        // getSubscriptionsInGroup should still return the list of SubscriptionInfo objects
        // but the ICC ID should not be available via getIccId or getCardString.
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testGetSubscriptionsInGroupWithReadDeviceIdentifier() throws Exception {
        ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest();
        setupReadPhoneNumbersTest();
        setIdentifierAccess(false);
        setNoPermission();
        setCarrierPrivileges(false);
        setIdentifierAccess(true);
        setReadPhoneState();

        List<SubscriptionInfo> subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
                groupUuid, mCallingPackage, mCallingFeature);

        assertTrue(subInfoList.size() > 0);
        for (SubscriptionInfo info : subInfoList) {
            assertEquals(UNAVAILABLE_ICCID, info.getIccId());
            assertEquals(UNAVAILABLE_ICCID, info.getCardString());
            assertEquals(UNAVAILABLE_NUMBER, info.getNumber());
            assertTrue(info.getIccId().length() > 0);
            assertTrue(info.getCardString().length() > 0);
        }
    }

    private void setNoPermission() {
        doThrow(new SecurityException()).when(mContext)
                .enforcePermission(anyString(), anyInt(), anyInt(), anyString());
    }

    private void setReadPhoneState() {
        doNothing().when(mContext).enforcePermission(
                eq(android.Manifest.permission.READ_PHONE_STATE), anyInt(), anyInt(), anyString());
    }

    @Test
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testGetSubscriptionInGroupWithPhoneNumberAccess() throws Exception {
        // If the calling package meets any of the requirements for the
        // LegacyPermissionManager#checkPhoneNumberAccess test then the number should be available
@@ -1758,6 +1822,7 @@ public class SubscriptionControllerTest extends TelephonyTest {
    }

    @Test
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testGetSubscriptionsInGroupWithCarrierPrivileges() throws Exception {
        // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier
        // privileges the ICC ID should be available in the SubscriptionInfo objects in the List.
@@ -1775,6 +1840,7 @@ public class SubscriptionControllerTest extends TelephonyTest {
    }

    @Test
    @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID})
    public void testGetSubscriptionsInGroupWithPrivilegedPermission() throws Exception {
        // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier
        // privileges the ICC ID should be available in the SubscriptionInfo objects in the List.
@@ -1796,6 +1862,7 @@ public class SubscriptionControllerTest extends TelephonyTest {
        ParcelUuid groupUuid = mSubscriptionControllerUT.createSubscriptionGroup(subIdList,
                mCallingPackage);
        assertNotNull(groupUuid);
        doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList();
        return groupUuid;
    }