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

Commit 11f130c6 authored by joonhunshin's avatar joonhunshin
Browse files

Enforce map the telephony features with APIs in

PhoneSubInfoController

If the required telephony feature is not defined, throw
UnsupportedOperationException

Bug: 297989574
Test: atest PhoneSubInfoControllerTest
Change-Id: If4c2fd05edae981d593cb1fc7c937fccf34f880a
parent 22345890
Loading
Loading
Loading
Loading
+126 −7
Original line number Diff line number Diff line
@@ -20,10 +20,12 @@ package com.android.internal.telephony;

import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.telephony.TelephonyManager.ENABLE_FEATURE_MAPPING;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -39,6 +41,8 @@ import android.telephony.TelephonyFrameworkInitializer;
import android.text.TextUtils;
import android.util.EventLog;

import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.flags.FeatureFlagsImpl;
import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.uicc.IsimRecords;
@@ -58,8 +62,14 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private final Context mContext;
    private AppOpsManager mAppOps;
    private FeatureFlags mFeatureFlags;
    private PackageManager mPackageManager;

    public PhoneSubInfoController(Context context) {
        this(context, new FeatureFlagsImpl());
    }

    public PhoneSubInfoController(Context context, FeatureFlags featureFlags) {
        ServiceRegisterer phoneSubServiceRegisterer = TelephonyFrameworkInitializer
                .getTelephonyServiceManager()
                .getPhoneSubServiceRegisterer();
@@ -68,6 +78,8 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
        }
        mAppOps = context.getSystemService(AppOpsManager.class);
        mContext = context;
        mPackageManager = context.getPackageManager();
        mFeatureFlags = featureFlags;
    }

    @Deprecated
@@ -89,7 +101,13 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {

    public String getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId) {
        return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
                callingFeatureId, "getNai", (phone)-> phone.getNai());
                callingFeatureId, "getNai", (phone)-> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
                            "getNaiForSubscriber");

                    return phone.getNai();
                });
    }

    public String getImeiForSubscriber(int subId, String callingPackage,
@@ -102,7 +120,13 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
                                                              String callingPackage) {
        return callPhoneMethodForSubIdWithPrivilegedCheck(subId,
                "getCarrierInfoForImsiEncryption",
                (phone)-> phone.getCarrierInfoForImsiEncryption(keyType, true));
                (phone)-> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
                            "getCarrierInfoForImsiEncryption");

                    return phone.getCarrierInfoForImsiEncryption(keyType, true);
                });
    }

    public void setCarrierInfoForImsiEncryption(int subId, String callingPackage,
@@ -126,6 +150,10 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
        callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage,
                "resetCarrierKeysForImsiEncryption",
                (phone)-> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
                            "resetCarrierKeysForImsiEncryption");

                    phone.resetCarrierKeysForImsiEncryption();
                    return null;
                });
@@ -166,12 +194,22 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
        }
        if (isActive) {
            return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
                    callingFeatureId, message, (phone) -> phone.getSubscriberId());
                    callingFeatureId, message, (phone) -> {
                        enforceTelephonyFeatureWithException(callingPackage,
                                PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
                                "getSubscriberIdForSubscriber");

                        return phone.getSubscriberId();
                    });
        } else {
            if (!TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(
                    mContext, subId, callingPackage, callingFeatureId, message)) {
                return null;
            }

            enforceTelephonyFeatureWithException(callingPackage,
                    PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getSubscriberIdForSubscriber");

            identity = Binder.clearCallingIdentity();
            try {
                SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance()
@@ -202,7 +240,13 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public String getIccSerialNumberForSubscriber(int subId, String callingPackage,
            String callingFeatureId) {
        return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
                callingFeatureId, "getIccSerialNumber", (phone) -> phone.getIccSerialNumber());
                callingFeatureId, "getIccSerialNumber", (phone) -> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
                            "getIccSerialNumberForSubscriber");

                    return phone.getIccSerialNumber();
                });
    }

    public String getLine1Number(String callingPackage, String callingFeatureId) {
@@ -216,7 +260,13 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
            String callingFeatureId) {
        return callPhoneMethodForSubIdWithReadPhoneNumberCheck(
                subId, callingPackage, callingFeatureId, "getLine1Number",
                (phone)-> phone.getLine1Number());
                (phone)-> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
                            "getLine1NumberForSubscriber");

                    return phone.getLine1Number();
                });
    }

    public String getLine1AlphaTag(String callingPackage, String callingFeatureId) {
@@ -251,6 +301,10 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
            String callingFeatureId) {
        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
                "getVoiceMailNumber", (phone)-> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_CALLING,
                            "getVoiceMailNumberForSubscriber");

                    String number = PhoneNumberUtils.extractNetworkPortion(
                            phone.getVoiceMailNumber());
                    if (VDBG) log("VM: getVoiceMailNUmber: " + number);
@@ -266,7 +320,13 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage,
            String callingFeatureId) {
        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
                "getVoiceMailAlphaTag", (phone)-> phone.getVoiceMailAlphaTag());
                "getVoiceMailAlphaTag", (phone)-> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_CALLING,
                            "getVoiceMailAlphaTagForSubscriber");

                    return phone.getVoiceMailAlphaTag();
                });
    }

    /**
@@ -381,6 +441,9 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public String getIsimDomain(int subId) {
        return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimDomain",
                (phone) -> {
                    enforceTelephonyFeatureWithException(getCurrentPackageName(),
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getIsimDomain");

                    IsimRecords isim = phone.getIsimRecords();
                    if (isim != null) {
                        return isim.getIsimDomain();
@@ -422,6 +485,10 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
        if (TelephonyPermissions.
                checkCallingOrSelfReadPrivilegedPhoneStatePermissionOrReadPhoneNumber(
                mContext, subId, callingPackage, callingFeatureId, "getImsPublicUserIdentities")) {

            enforceTelephonyFeatureWithException(callingPackage,
                    PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getImsPublicUserIdentities");

            Phone phone = getPhone(subId);
            assert phone != null;
            IsimRecords isimRecords = phone.getIsimRecords();
@@ -447,6 +514,9 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public String getIsimIst(int subId) throws RemoteException {
        return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getIsimIst",
                (phone) -> {
                    enforceTelephonyFeatureWithException(getCurrentPackageName(),
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getIsimIst");

                    IsimRecords isim = phone.getIsimRecords();
                    if (isim != null) {
                        return isim.getIsimIst();
@@ -478,6 +548,9 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public String getSimServiceTable(int subId, int appType) throws RemoteException {
        return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSimServiceTable",
                (phone) -> {
                    enforceTelephonyFeatureWithException(getCurrentPackageName(),
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getSimServiceTable");

                    UiccPort uiccPort = phone.getUiccPort();
                    if (uiccPort == null || uiccPort.getUiccProfile() == null) {
                        loge("getSimServiceTable(): uiccPort or uiccProfile is null");
@@ -498,6 +571,9 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public String getIccSimChallengeResponse(int subId, int appType, int authType, String data,
            String callingPackage, String callingFeatureId) throws RemoteException {
        CallPhoneMethodHelper<String> toExecute = (phone)-> {
            enforceTelephonyFeatureWithException(callingPackage,
                    PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getIccSimChallengeResponse");

            UiccPort uiccPort = phone.getUiccPort();
            if (uiccPort == null) {
                loge("getIccSimChallengeResponse() uiccPort is null");
@@ -531,7 +607,13 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage,
            String callingFeatureId) {
        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
                "getGroupIdLevel1", (phone)-> phone.getGroupIdLevel1());
                "getGroupIdLevel1", (phone)-> {
                    enforceTelephonyFeatureWithException(callingPackage,
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
                            "getGroupIdLevel1ForSubscriber");

                    return phone.getGroupIdLevel1();
                });
    }

    /** Below are utility methods that abstracts the flow that many public methods use:
@@ -667,6 +749,9 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
    public Uri getSmscIdentity(int subId, int appType) throws RemoteException {
        Uri smscIdentityUri = callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSmscIdentity",
                (phone) -> {
                    enforceTelephonyFeatureWithException(getCurrentPackageName(),
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getSmscIdentity");

                    try {
                        String smscIdentity = null;
                        UiccPort uiccPort = phone.getUiccPort();
@@ -690,6 +775,40 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
        return smscIdentityUri;
    }

    /**
     * Get the current calling package name.
     * @return the current calling package name
     */
    @Nullable
    private String getCurrentPackageName() {
        if (mPackageManager == null) return null;
        String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid());
        return (callingUids == null) ? null : callingUids[0];
    }

    /**
     * Make sure the device has required telephony feature
     *
     * @throws UnsupportedOperationException if the device does not have required telephony feature
     */
    private void enforceTelephonyFeatureWithException(@Nullable String callingPackage,
            @NonNull String telephonyFeature, @NonNull String methodName) {
        if (callingPackage == null || mPackageManager == null) {
            return;
        }

        if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
                || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
                Binder.getCallingUserHandle())) {
            return;
        }

        if (!mPackageManager.hasSystemFeature(telephonyFeature)) {
            throw new UnsupportedOperationException(
                    methodName + " is unsupported without " + telephonyFeature);
        }
    }

    private void log(String s) {
        Rlog.d(TAG, s);
    }
+58 −17
Original line number Diff line number Diff line
@@ -23,8 +23,10 @@ import static android.telephony.TelephonyManager.APPTYPE_USIM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
@@ -33,14 +35,15 @@ import static org.mockito.Mockito.mock;

import android.app.AppOpsManager;
import android.app.PropertyInvalidatedCache;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;

import androidx.test.filters.SmallTest;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.internal.telephony.uicc.IsimUiccRecords;
import com.android.internal.telephony.uicc.SIMRecords;
@@ -48,10 +51,14 @@ import com.android.internal.telephony.uicc.UiccCardApplication;
import com.android.internal.telephony.uicc.UiccPort;
import com.android.internal.telephony.uicc.UiccProfile;

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

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

import java.util.List;
@@ -63,6 +70,9 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {
    private static final String PSI_SMSC_TEL2 = "tel:+91987654321";
    private static final String PSI_SMSC_SIP2 = "sip:+19876543210@dcf.pc.operetor2.com;user=phone";

    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

    private PhoneSubInfoController mPhoneSubInfoControllerUT;
    private AppOpsManager mAppOsMgr;
    private PackageManager mPm;
@@ -92,7 +102,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {
        mPm = mContext.getPackageManager();

        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, mSecondPhone});
        mPhoneSubInfoControllerUT = new PhoneSubInfoController(mContext);
        mPhoneSubInfoControllerUT = new PhoneSubInfoController(mContext, mFeatureFlags);

        setupMocksForTelephonyPermissions();
        // TelephonyPermissions will query the READ_DEVICE_IDENTIFIERS op from AppOpManager to
@@ -105,6 +115,12 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {

        // Bypass calling package check.
        doReturn(Binder.getCallingUid()).when(mPm).getPackageUid(eq(TAG), anyInt());

        // In order not to affect the existing implementation, define a telephony features
        // and disabled enforce_telephony_feature_mapping_for_public_apis feature flag
        doReturn(false).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
        doReturn(true).when(mPm).hasSystemFeature(anyString());
        doReturn(new String[] {TAG}).when(mPm).getPackagesForUid(anyInt());
    }

    @After
@@ -211,6 +227,31 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {
                mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG, FEATURE_ID));
    }

    @Test
    @SmallTest
    @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
    public void testGetNai_EnabledEnforceTelephonyFeatureMappingForPublicApis() {
        // FeatureFlags enabled, System has required feature
        doReturn(true).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
        doReturn(true).when(mPm).hasSystemFeature(
                eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
        doReturn("bbb@example.com").when(mSecondPhone).getNai();

        // Enabled FeatureFlags and ENABLE_FEATURE_MAPPING, telephony features are defined
        try {
            assertEquals("bbb@example.com",
                    mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG, FEATURE_ID));
        } catch (UnsupportedOperationException e) {
            fail("Not expect exception " + e.getMessage());
        }

        // Telephony features is not defined, expect UnsupportedOperationException.
        doReturn(false).when(mPm).hasSystemFeature(
                eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
        assertThrows(UnsupportedOperationException.class,
                () -> mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG, FEATURE_ID));
    }

    @Test
    @SmallTest
    public void testGetNaiWithOutPermission() {
@@ -1087,7 +1128,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {

        doReturn(refSst).when(mSimRecords).getSimServiceTable();

        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt());
        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(0, 0);
        assertEquals(refSst, resultSst);
    }

@@ -1101,7 +1142,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {

        doReturn(refSst).when(mSimRecords).getSimServiceTable();

        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt());
        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(0, 0);
        assertEquals(refSst, resultSst);
    }

@@ -1115,7 +1156,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {

        doReturn(refSst).when(mSimRecords).getSimServiceTable();

            String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt());
        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(0, 0);
        assertEquals(null, resultSst);
    }

@@ -1129,7 +1170,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {

        doReturn(refSst).when(mSimRecords).getSimServiceTable();

        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt());
        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(0, 0);
        assertEquals(null, resultSst);
    }

@@ -1143,7 +1184,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {

        doReturn(refSst).when(mSimRecords).getSimServiceTable();

        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt());
        String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(0, 0);
        assertEquals(null, resultSst);
    }

@@ -1159,7 +1200,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {

        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
        try {
            mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt());
            mPhoneSubInfoControllerUT.getSimServiceTable(0, 0);
            Assert.fail("expected Security Exception Thrown");
        } catch (Exception ex) {
            assertTrue(ex instanceof SecurityException);
@@ -1167,7 +1208,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest {
        }

        mContextFixture.addCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE);
        assertEquals(refSst, mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt()));
        assertEquals(refSst, mPhoneSubInfoControllerUT.getSimServiceTable(0, 0));
    }

    @Test