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

Commit ffd92af9 authored by Michael Groover's avatar Michael Groover Committed by Android (Google) Code Review
Browse files

Merge "Refactor device ID access SystemAPI to PermissionManager" into rvc-dev

parents 659bf328 56a84b26
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -861,7 +861,6 @@ package android.app.admin {
    method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
    method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
    method public boolean hasDeviceIdentifierAccess(@NonNull String, int, int);
    method public boolean isDeviceManaged();
    method public boolean isDeviceManaged();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
@@ -8815,6 +8814,7 @@ package android.permission {
  }
  }
  public final class PermissionManager {
  public final class PermissionManager {
    method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int);
    method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
    method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
    method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
    method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
    method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
    method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
+0 −1
Original line number Original line Diff line number Diff line
@@ -7071,7 +7071,6 @@ public class DevicePolicyManager {
     *
     *
     * @hide
     * @hide
     */
     */
    @SystemApi
    public boolean hasDeviceIdentifierAccess(@NonNull String packageName, int pid, int uid) {
    public boolean hasDeviceIdentifierAccess(@NonNull String packageName, int pid, int uid) {
        throwIfParentInstance("hasDeviceIdentifierAccess");
        throwIfParentInstance("hasDeviceIdentifierAccess");
        if (packageName == null) {
        if (packageName == null) {
+2 −0
Original line number Original line Diff line number Diff line
@@ -54,6 +54,8 @@ interface IPermissionManager {


    int checkUidPermission(String permName, int uid);
    int checkUidPermission(String permName, int uid);


    int checkDeviceIdentifierAccess(String packageName, String callingFeatureId, String message, int pid, int uid);

    void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
    void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);


    void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
    void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
+42 −2
Original line number Original line Diff line number Diff line
@@ -40,6 +40,7 @@ import android.os.UserHandle;
import android.util.Slog;
import android.util.Slog;


import com.android.internal.annotations.Immutable;
import com.android.internal.annotations.Immutable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.CollectionUtils;


import java.util.ArrayList;
import java.util.ArrayList;
@@ -84,10 +85,25 @@ public final class PermissionManager {
     */
     */
    public PermissionManager(@NonNull Context context, IPackageManager packageManager)
    public PermissionManager(@NonNull Context context, IPackageManager packageManager)
            throws ServiceManager.ServiceNotFoundException {
            throws ServiceManager.ServiceNotFoundException {
        this(context, packageManager, IPermissionManager.Stub.asInterface(
                ServiceManager.getServiceOrThrow("permissionmgr")));
    }

    /**
     * Creates a new instance with the provided instantiation of the IPermissionManager.
     *
     * @param context           the current context in which to operate
     * @param packageManager    package manager service to be used for package related permission
     *                          requests
     * @param permissionManager injectable permission manager service
     * @hide
     */
    @VisibleForTesting
    public PermissionManager(@NonNull Context context, IPackageManager packageManager,
            IPermissionManager permissionManager) {
        mContext = context;
        mContext = context;
        mPackageManager = packageManager;
        mPackageManager = packageManager;
        mPermissionManager = IPermissionManager.Stub.asInterface(
        mPermissionManager = permissionManager;
                ServiceManager.getServiceOrThrow("permissionmgr"));
    }
    }


    /**
    /**
@@ -486,6 +502,30 @@ public final class PermissionManager {
        }
        }
    }
    }


    /**
     * Checks whether the package with the given pid/uid can read device identifiers.
     *
     * @param packageName      the name of the package to be checked for identifier access
     * @param message          the message to be used for logging during identifier access
     *                         verification
     * @param callingFeatureId the feature in the package
     * @param pid              the process id of the package to be checked
     * @param uid              the uid of the package to be checked
     * @return {@link PackageManager#PERMISSION_GRANTED} if the package is allowed identifier
     * access, {@link PackageManager#PERMISSION_DENIED} otherwise
     * @hide
     */
    @SystemApi
    public int checkDeviceIdentifierAccess(@Nullable String packageName, @Nullable String message,
            @Nullable String callingFeatureId, int pid, int uid) {
        try {
            return mPermissionManager.checkDeviceIdentifierAccess(packageName, message,
                    callingFeatureId, pid, uid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /* @hide */
    /* @hide */
    private static int checkPermissionUncached(@Nullable String permission, int pid, int uid) {
    private static int checkPermissionUncached(@Nullable String permission, int pid, int uid) {
        final IActivityManager am = ActivityManager.getService();
        final IActivityManager am = ActivityManager.getService();
+158 −3
Original line number Original line Diff line number Diff line
@@ -59,6 +59,7 @@ import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
import android.app.IActivityManager;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.EnabledAfter;
@@ -113,6 +114,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseBooleanArray;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -243,6 +245,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final PermissionSettings mSettings;
    private final PermissionSettings mSettings;


    /** Injector that can be used to facilitate testing. */
    private final Injector mInjector;

    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private ArraySet<String> mPrivappPermissionsViolations;
    private ArraySet<String> mPrivappPermissionsViolations;


@@ -352,10 +357,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {


    PermissionManagerService(Context context,
    PermissionManagerService(Context context,
            @NonNull Object externalLock) {
            @NonNull Object externalLock) {
        this(context, externalLock, new Injector(context));
    }

    @VisibleForTesting
    PermissionManagerService(Context context, @NonNull Object externalLock,
            @NonNull Injector injector) {
        mInjector = injector;
        // The package info cache is the cache for package and permission information.
        // The package info cache is the cache for package and permission information.
        PackageManager.invalidatePackageInfoCache();
        mInjector.invalidatePackageInfoCache();
        PermissionManager.disablePermissionCache();
        mInjector.disablePermissionCache();
        PermissionManager.disablePackageNamePermissionCache();
        mInjector.disablePackageNamePermissionCache();


        mContext = context;
        mContext = context;
        mLock = externalLock;
        mLock = externalLock;
@@ -951,6 +963,59 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        }
        }
    }
    }


    @Override
    public int checkDeviceIdentifierAccess(@Nullable String packageName, @Nullable String message,
            @Nullable String callingFeatureId, int pid, int uid) {
        // If the check is being requested by an app then only allow the app to query its own
        // access status.
        int callingUid = mInjector.getCallingUid();
        int callingPid = mInjector.getCallingPid();
        if (UserHandle.getAppId(callingUid) >= Process.FIRST_APPLICATION_UID && (callingUid != uid
                || callingPid != pid)) {
            String response = String.format(
                    "Calling uid %d, pid %d cannot check device identifier access for package %s "
                            + "(uid=%d, pid=%d)",
                    callingUid, callingPid, packageName, uid, pid);
            Log.w(TAG, response);
            throw new SecurityException(response);
        }
        // Allow system and root access to the device identifiers.
        final int appId = UserHandle.getAppId(uid);
        if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
        if (mInjector.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
                uid) == PackageManager.PERMISSION_GRANTED) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // If the calling package is not null then perform the appop and device / profile owner
        // check.
        if (packageName != null) {
            // Allow access to a package that has been granted the READ_DEVICE_IDENTIFIERS appop.
            long token = mInjector.clearCallingIdentity();
            AppOpsManager appOpsManager = (AppOpsManager) mInjector.getSystemService(
                    Context.APP_OPS_SERVICE);
            try {
                if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid,
                        packageName, callingFeatureId, message) == AppOpsManager.MODE_ALLOWED) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            } finally {
                mInjector.restoreCallingIdentity(token);
            }
            // Check if the calling packages meets the device / profile owner requirements for
            // identifier access.
            DevicePolicyManager devicePolicyManager =
                    (DevicePolicyManager) mInjector.getSystemService(Context.DEVICE_POLICY_SERVICE);
            if (devicePolicyManager != null && devicePolicyManager.hasDeviceIdentifierAccess(
                    packageName, pid, uid)) {
                return PackageManager.PERMISSION_GRANTED;
            }
        }
        return PackageManager.PERMISSION_DENIED;
    }

    @Override
    @Override
    public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
    public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
        mContext.enforceCallingOrSelfPermission(
        mContext.enforceCallingOrSelfPermission(
@@ -4797,4 +4862,94 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            }
            }
        }
        }
    }
    }

    /**
     * Allows injection of services and method responses to facilitate testing.
     *
     * <p>Test classes can create a mock of this class and pass it to the PermissionManagerService
     * constructor to control behavior of services and external methods during execution.
     * @hide
     */
    @VisibleForTesting
    public static class Injector {
        private final Context mContext;

        /**
         * Public constructor that accepts a {@code context} within which to operate.
         */
        public Injector(@NonNull Context context) {
            mContext = context;
        }

        /**
         * Returns the UID of the calling package.
         */
        public int getCallingUid() {
            return Binder.getCallingUid();
        }

        /**
         * Returns the process ID of the calling package.
         */
        public int getCallingPid() {
            return Binder.getCallingPid();
        }

        /**
         * Invalidates the package info cache.
         */
        public void invalidatePackageInfoCache() {
            PackageManager.invalidatePackageInfoCache();
        }

        /**
         * Disables the permission cache.
         */
        public void disablePermissionCache() {
            PermissionManager.disablePermissionCache();
        }

        /**
         * Disables the package name permission cache.
         */
        public void disablePackageNamePermissionCache() {
            PermissionManager.disablePackageNamePermissionCache();
        }

        /**
         * Checks if the package running under the specified {@code pid} and {@code uid} has been
         * granted the provided {@code permission}.
         *
         * @return {@link PackageManager#PERMISSION_GRANTED} if the package has been granted the
         * permission, {@link PackageManager#PERMISSION_DENIED} otherwise
         */
        public int checkPermission(@NonNull String permission, int pid, int uid) {
            return mContext.checkPermission(permission, pid, uid);
        }

        /**
         * Clears the calling identity to allow subsequent calls to be treated as coming from this
         * package.
         *
         * @return a token that can be used to restore the calling identity
         */
        public long clearCallingIdentity() {
            return Binder.clearCallingIdentity();
        }

        /**
         * Restores the calling identity to that of the calling package based on the provided
         * {@code token}.
         */
        public void restoreCallingIdentity(long token) {
            Binder.restoreCallingIdentity(token);
        }

        /**
         * Returns the system service with the provided {@code name}.
         */
        public Object getSystemService(@NonNull String name) {
            return mContext.getSystemService(name);
        }
    }
}
}
Loading