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

Commit 725c5406 authored by Shuo Qian's avatar Shuo Qian Committed by Gerrit Code Review
Browse files

Merge "Cleanup ITelephony in TelephonyPermissions with new System API. This...

Merge "Cleanup ITelephony in TelephonyPermissions with new System API. This method is used by Telephony Module for permission checking."
parents 259781e8 1e28948a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9215,6 +9215,7 @@ package android.telephony {
    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
    method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
    method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
+3 −2
Original line number Diff line number Diff line
@@ -1293,7 +1293,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
        // only CarrierService with carrier privilege rule should have the permission
        int[] subIds = Arrays.stream(SubscriptionManager.from(mContext)
                    .getActiveSubscriptionIdList(false))
                    .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray();
                    .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext,
                            i)).toArray();
        if (ArrayUtils.isEmpty(subIds)) {
            loge("notifyCarrierNetworkChange without carrier privilege");
            // the active subId does not have carrier privilege.
@@ -2301,7 +2302,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
            return;
        }

        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
                SubscriptionManager.getDefaultSubscriptionId(), method);
    }

+36 −116
Original line number Diff line number Diff line
@@ -27,8 +27,6 @@ import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -41,7 +39,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

/** Utility class for Telephony permission enforcement. */
public final class TelephonyPermissions {
@@ -49,9 +46,6 @@ public final class TelephonyPermissions {

    private static final boolean DBG = false;

    private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
            ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));

    /**
     * Whether to disable the new device identifier access restrictions.
     */
@@ -137,49 +131,6 @@ public final class TelephonyPermissions {
    public static boolean checkReadPhoneState(
            Context context, int subId, int pid, int uid, String callingPackage,
            @Nullable  String callingFeatureId, String message) {
        return checkReadPhoneState(
                context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId,
                message);
    }

    /**
     * Check whether the calling packages has carrier privileges for the passing subscription.
     * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
     */
    public static boolean checkCarrierPrivilegeForSubId(int subId) {
        if (SubscriptionManager.isValidSubscriptionId(subId)
                && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid())
                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
            return true;
        }
        return false;
    }

    /**
     * Check whether the app with the given pid/uid can read phone state.
     *
     * <p>This method behaves in one of the following ways:
     * <ul>
     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
     *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
     *       apps which support runtime permissions, if the caller does not currently have any of
     *       these permissions.
     *   <li>return false: if the caller lacks all of these permissions and doesn't support runtime
     *       permissions. This implies that the user revoked the ability to read phone state
     *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
     *       so we return false to indicate that the calling function should return dummy data.
     * </ul>
     *
     * <p>Note: for simplicity, this method always returns false for callers using legacy
     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
     * devices.
     */
    @VisibleForTesting
    public static boolean checkReadPhoneState(
            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
            String callingPackage, @Nullable String callingFeatureId, String message) {
        try {
            context.enforcePermission(
                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -194,7 +145,7 @@ public final class TelephonyPermissions {
                // If we don't have the runtime permission, but do have carrier privileges, that
                // suffices for reading phone state.
                if (SubscriptionManager.isValidSubscriptionId(subId)) {
                    enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
                    enforceCarrierPrivilege(context, subId, uid, message);
                    return true;
                }
                throw phoneStateException;
@@ -209,23 +160,16 @@ public final class TelephonyPermissions {
    }

    /**
     * Check whether the app with the given pid/uid can read phone state, or has carrier
     * privileges on any active subscription.
     *
     * <p>If the app does not have carrier privilege, this method will return {@code false} instead
     * of throwing a SecurityException. Therefore, the callers cannot tell the difference
     * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
     * which declare the static permission but had access revoked via AppOps. Apps in the former
     * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
     * use only if the behavior in both scenarios is meant to be identical.
     *
     * @return {@code true} if the app can read phone state or has carrier privilege;
     *         {@code false} otherwise.
     * Check whether the calling packages has carrier privileges for the passing subscription.
     * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
     */
    public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
            String callingPackage, @Nullable String callingFeatureId, String message) {
        return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid,
                    callingPackage, callingFeatureId, message);
    public static boolean checkCarrierPrivilegeForSubId(Context context, int subId) {
        if (SubscriptionManager.isValidSubscriptionId(subId)
                && getCarrierPrivilegeStatus(context, subId, Binder.getCallingUid())
                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
            return true;
        }
        return false;
    }

    /**
@@ -242,9 +186,7 @@ public final class TelephonyPermissions {
     * @return {@code true} if the app can read phone state or has carrier privilege;
     *         {@code false} otherwise.
     */
    @VisibleForTesting
    public static boolean checkReadPhoneStateOnAnyActiveSub(
            Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid,
    public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
            String callingPackage, @Nullable String callingFeatureId, String message) {
        try {
            context.enforcePermission(
@@ -259,7 +201,7 @@ public final class TelephonyPermissions {
            } catch (SecurityException phoneStateException) {
                // If we don't have the runtime permission, but do have carrier privileges, that
                // suffices for reading phone state.
                return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid);
                return checkCarrierPrivilegeForAnySubId(context, uid);
            }
        }

@@ -374,12 +316,11 @@ public final class TelephonyPermissions {
        }

        // If the calling package has carrier privileges for specified sub, then allow access.
        if (checkCarrierPrivilegeForSubId(subId)) return true;
        if (checkCarrierPrivilegeForSubId(context, subId)) return true;

        // If the calling package has carrier privileges for any subscription
        // and allowCarrierPrivilegeOnAnySub is set true, then allow access.
        if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(
                context, TELEPHONY_SUPPLIER, uid)) {
        if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) {
            return true;
        }

@@ -471,7 +412,7 @@ public final class TelephonyPermissions {
                    uid) == PackageManager.PERMISSION_GRANTED) {
                return false;
            }
            if (checkCarrierPrivilegeForSubId(subId)) {
            if (checkCarrierPrivilegeForSubId(context, subId)) {
                return false;
            }
        }
@@ -487,26 +428,12 @@ public final class TelephonyPermissions {
    public static boolean checkReadCallLog(
            Context context, int subId, int pid, int uid, String callingPackage,
            @Nullable String callingPackageName) {
        return checkReadCallLog(
                context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName);
    }

    /**
     * Check whether the app with the given pid/uid can read the call log.
     * @return {@code true} if the specified app has the read call log permission and AppOpp granted
     *      to it, {@code false} otherwise.
     */
    @VisibleForTesting
    public static boolean checkReadCallLog(
            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
            String callingPackage, @Nullable String callingFeatureId) {

        if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
                != PERMISSION_GRANTED) {
            // If we don't have the runtime permission, but do have carrier privileges, that
            // suffices for being able to see the call phone numbers.
            if (SubscriptionManager.isValidSubscriptionId(subId)) {
                enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
                enforceCarrierPrivilege(context, subId, uid, "readCallLog");
                return true;
            }
            return false;
@@ -529,7 +456,7 @@ public final class TelephonyPermissions {
            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
            String message) {
        return checkReadPhoneNumber(
                context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
                context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
                callingPackage, callingFeatureId, message);
    }

@@ -541,7 +468,7 @@ public final class TelephonyPermissions {
     */
    @VisibleForTesting
    public static boolean checkReadPhoneNumber(
            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
            Context context, int subId, int pid, int uid,
            String callingPackage, @Nullable String callingFeatureId, String message) {
        // Default SMS app can always read it.
        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
@@ -556,7 +483,7 @@ public final class TelephonyPermissions {
        // First, check if we can read the phone state.
        try {
            return checkReadPhoneState(
                    context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId,
                    context, subId, pid, uid, callingPackage, callingFeatureId,
                    message);
        } catch (SecurityException readPhoneStateSecurityException) {
        }
@@ -598,7 +525,7 @@ public final class TelephonyPermissions {
        }

        if (DBG) Log.d(LOG_TAG, "No modify permission, check carrier privilege next.");
        enforceCallingOrSelfCarrierPrivilege(subId, message);
        enforceCallingOrSelfCarrierPrivilege(context, subId, message);
    }

    /**
@@ -618,7 +545,7 @@ public final class TelephonyPermissions {
            Log.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
        }

        enforceCallingOrSelfCarrierPrivilege(subId, message);
        enforceCallingOrSelfCarrierPrivilege(context, subId, message);
    }

    /**
@@ -639,7 +566,7 @@ public final class TelephonyPermissions {
                    + "check carrier privilege next.");
        }

        enforceCallingOrSelfCarrierPrivilege(subId, message);
        enforceCallingOrSelfCarrierPrivilege(context, subId, message);
    }

    /**
@@ -647,21 +574,18 @@ public final class TelephonyPermissions {
     *
     * @throws SecurityException if the caller does not have the required privileges
     */
    public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) {
    public static void enforceCallingOrSelfCarrierPrivilege(
            Context context, int subId, String message) {
        // NOTE: It's critical that we explicitly pass the calling UID here rather than call
        // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from
        // the phone process. When called from another process, it will check whether that process
        // has carrier privileges instead.
        enforceCarrierPrivilege(subId, Binder.getCallingUid(), message);
    }

    private static void enforceCarrierPrivilege(int subId, int uid, String message) {
        enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
        enforceCarrierPrivilege(context, subId, Binder.getCallingUid(), message);
    }

    private static void enforceCarrierPrivilege(
            Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) {
        if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid)
            Context context, int subId, int uid, String message) {
        if (getCarrierPrivilegeStatus(context, subId, uid)
                != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
            if (DBG) Log.e(LOG_TAG, "No Carrier Privilege.");
            throw new SecurityException(message);
@@ -669,13 +593,12 @@ public final class TelephonyPermissions {
    }

    /** Returns whether the provided uid has carrier privileges for any active subscription ID. */
    private static boolean checkCarrierPrivilegeForAnySubId(
            Context context, Supplier<ITelephony> telephonySupplier, int uid) {
    private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) {
        SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
        for (int activeSubId : activeSubIds) {
            if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
            if (getCarrierPrivilegeStatus(context, activeSubId, uid)
                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                return true;
            }
@@ -683,18 +606,15 @@ public final class TelephonyPermissions {
        return false;
    }

    private static int getCarrierPrivilegeStatus(
            Supplier<ITelephony> telephonySupplier, int subId, int uid) {
        ITelephony telephony = telephonySupplier.get();
    private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) {
        final long identity = Binder.clearCallingIdentity();
        try {
            if (telephony != null) {
                return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
            }
        } catch (RemoteException e) {
            // Fallback below.
            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
                Context.TELEPHONY_SERVICE);
            return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
        Log.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    }

    /**
+26 −0
Original line number Diff line number Diff line
@@ -11749,6 +11749,32 @@ public class TelephonyManager {
        return new Pair<Integer, Integer>(-1, -1);
    }

    /**
     * Get the calling application status about carrier privileges for the subscription created
     * in TelephonyManager. Used by Telephony Module for permission checking.
     *
     * @param uid Uid to check.
     * @return any value of {@link #CARRIER_PRIVILEGE_STATUS_HAS_ACCESS},
     *         {@link #CARRIER_PRIVILEGE_STATUS_NO_ACCESS},
     *         {@link #CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED}, or
     *         {@link #CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES}
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
    public int getCarrierPrivilegeStatus(int uid) {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                return telephony.getCarrierPrivilegeStatusForUid(getSubId(), uid);
            }
        } catch (RemoteException ex) {
            Log.e(TAG, "getCarrierPrivilegeStatus RemoteException", ex);
        }
        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    }

    /**
     * Returns a list of APNs set as overrides by the device policy manager via
     * {@link #addDevicePolicyOverrideApn}.