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

Commit b81c236a authored by Joonhun Shin's avatar Joonhun Shin Committed by Android (Google) Code Review
Browse files

Merge "Enforce map the telephony features with APIs in PhoneSubInfoController" into main

parents 6b91f606 11f130c6
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