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

Commit 90433141 authored by Hai Zhang's avatar Hai Zhang
Browse files

Add new permission flags implementation.

Bug: 182523293
Test: presubmit
Change-Id: Ia4328196e306c4e1de99fa62cef0eb295046e0d4
parent b78d7e46
Loading
Loading
Loading
Loading
+458 −8
Original line number Diff line number Diff line
@@ -16,18 +16,468 @@

package com.android.server.permission.access.permission

import android.app.AppOpsManager
import android.app.admin.DevicePolicyManager
import android.content.pm.PackageManager
import android.os.Build
import android.permission.PermissionManager
import com.android.server.permission.access.util.andInv
import com.android.server.permission.access.util.hasAnyBit
import com.android.server.permission.access.util.hasBits

/**
 * A set of internal permission flags that's better than the set of `FLAG_PERMISSION_*` constants on
 * [PackageManager].
 *
 * The old binary permission state is now tracked by multiple `*_GRANTED` and `*_REVOKED` flags, so
 * that:
 *
 * - With [INSTALL_GRANTED] and [INSTALL_REVOKED], we can now get rid of the old per-package
 *   `areInstallPermissionsFixed` attribute and correctly track it per-permission, finally fixing
 *   edge cases during module rollbacks.
 *
 * - With [LEGACY_GRANTED] and [IMPLICIT_GRANTED], we can now ensure that legacy permissions and
 *   implicit permissions split from non-runtime permissions are never revoked, without checking
 *   split permissions and package state everywhere slowly and in slightly different ways.
 *
 * - With [RESTRICTION_REVOKED], we can now get rid of the error-prone logic about revoking and
 *   potentially re-granting permissions upon restriction state changes.
 *
 * Permission grants due to protection level are now tracked by [PROTECTION_GRANTED], and permission
 * grants due to [PackageManager.grantRuntimePermission] are now tracked by [RUNTIME_GRANTED].
 *
 * The [PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED] and
 * [PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED] flags are now unified into [IMPLICIT], and
 * they can be differentiated by the presence of [LEGACY_GRANTED].
 *
 * The rest of the permission flags have a 1:1 mapping to the old `FLAG_PERMISSION_*` constants, and
 * don't have any effect on the binary permission state.
 */
object PermissionFlags {
    /**
     * Permission flag for a normal permission that is granted at package installation.
     */
    const val INSTALL_GRANTED = 1 shl 0

    /**
     * Permission flag for a normal permission that is revoked at package installation.
     *
     * Normally packages that have already been installed cannot be granted new normal permissions
     * until its next installation (update), so this flag helps track that the normal permission was
     * revoked upon its most recent installation.
     */
    const val INSTALL_REVOKED = 1 shl 1

    /**
     * Permission flag for a signature or internal permission that is granted based on the
     * permission's protection level, including its protection and protection flags.
     *
     * For example, this flag may be set when the permission is a signature permission and the
     * package is having a compatible signing certificate with the package defining the permission,
     * or when the permission is a privileged permission and the package is a privileged app with
     * its permission in the
     * [privileged permission allowlist](https://source.android.com/docs/core/permissions/perms-allowlist).
     */
    const val PROTECTION_GRANTED = 1 shl 2
    const val ROLE_GRANTED = 1 shl 3
    // For permissions that are granted in other ways,
    // ex: via an API or implicit permissions that inherit from granted install permissions
    const val OTHER_GRANTED = 1 shl 4
    // For the permissions that are implicit for the package
    const val IMPLICIT = 1 shl 5

    /**
     * Permission flag for a role or runtime permission that is or was granted by a role.
     *
     * @see PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE
     */
    const val ROLE = 1 shl 3

    /**
     * Permission flag for a development, role or runtime permission that is granted via
     * [PackageManager.grantRuntimePermission].
     */
    const val RUNTIME_GRANTED = 1 shl 4

    /**
     * Permission flag for a runtime permission whose state is set by the user.
     *
     * For example, this flag may be set when the permission is allowed by the user in the
     * request permission dialog, or managed in the permission settings.
     *
     * @see PackageManager.FLAG_PERMISSION_USER_SET
     */
    const val USER_SET = 1 shl 5

    /**
     * Permission flag for a runtime permission whose state is (revoked and) fixed by the user.
     *
     * For example, this flag may be set when the permission is denied twice by the user in the
     * request permission dialog.
     *
     * @see PackageManager.FLAG_PERMISSION_USER_FIXED
     */
    const val USER_FIXED = 1 shl 6

    /**
     * Permission flag for a runtime permission whose state is set and fixed by the device policy
     * via [DevicePolicyManager.setPermissionGrantState].
     *
     * @see PackageManager.FLAG_PERMISSION_POLICY_FIXED
     */
    const val POLICY_FIXED = 1 shl 7

    /**
     * Permission flag for a runtime permission that is (pregranted and) fixed by the system.
     *
     * For example, this flag may be set in
     * [com.android.server.pm.permission.DefaultPermissionGrantPolicy].
     *
     * @see PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
     */
    const val SYSTEM_FIXED = 1 shl 8

    /**
     * Permission flag for a runtime permission that is or was pregranted by the system.
     *
     * For example, this flag may be set in
     * [com.android.server.pm.permission.DefaultPermissionGrantPolicy].
     *
     * @see PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
     */
    const val PREGRANT = 1 shl 9

    /**
     * Permission flag for a runtime permission that is granted because the package targets a legacy
     * SDK version before [Build.VERSION_CODES.M] and doesn't support runtime permissions.
     *
     * As long as this flag is set, the permission should always be considered granted, although
     * [APP_OP_REVOKED] may cause the app op for the runtime permission to be revoked. Once the
     * package targets a higher SDK version so that it started supporting runtime permissions, this
     * flag should be removed and the remaining flags should take effect.
     *
     * @see PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
     * @see PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
     */
    const val LEGACY_GRANTED = 1 shl 10

    /**
     * Permission flag for a runtime permission that is granted because the package targets a lower
     * SDK version and the permission is implicit to it as a
     * [split permission][PermissionManager.SplitPermissionInfo] from other non-runtime permissions.
     *
     * As long as this flag is set, the permission should always be considered granted, although
     * [APP_OP_REVOKED] may cause the app op for the runtime permission to be revoked. Once the
     * package targets a higher SDK version so that the permission is no longer implicit to it, this
     * flag should be removed and the remaining flags should take effect.
     *
     * @see PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
     * @see PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
     */
    const val IMPLICIT_GRANTED = 1 shl 11

    /**
     * Permission flag for a runtime permission that is granted because the package targets a legacy
     * SDK version before [Build.VERSION_CODES.M] and doesn't support runtime permissions, so that
     * it needs to be reviewed by the user; or granted because the package targets a lower SDK
     * version and the permission is implicit to it as a
     * [split permission][PermissionManager.SplitPermissionInfo] from other non-runtime permissions,
     * so that it needs to be revoked when it's no longer implicit.
     *
     * @see PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
     * @see PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
     */
    const val IMPLICIT = 1 shl 12

    /**
     * Permission flag for a runtime permission that is user-sensitive when it's granted.
     *
     * This flag is informational and managed by PermissionController.
     *
     * @see PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
     */
    const val USER_SENSITIVE_WHEN_GRANTED = 1 shl 13

    /**
     * Permission flag for a runtime permission that is user-sensitive when it's revoked.
     *
     * This flag is informational and managed by PermissionController.
     *
     * @see PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED
     */
    const val USER_SENSITIVE_WHEN_REVOKED = 1 shl 14

    /**
     * Permission flag for a restricted runtime permission that is exempt by the package's
     * installer.
     *
     * For example, this flag may be set when the installer applied the exemption as part of the
     * [session parameters](https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(java.util.Set%3Cjava.lang.String%3E)).
     *
     * The permission will be restricted when none of the exempt flags is set.
     *
     * @see PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
     */
    const val INSTALLER_EXEMPT = 1 shl 15

    /**
     * Permission flag for a restricted runtime permission that is exempt by the system.
     *
     * For example, this flag may be set when the package is a system app.
     *
     * The permission will be restricted when none of the exempt flags is set.
     *
     * @see PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
     */
    const val SYSTEM_EXEMPT = 1 shl 16

    /**
     * Permission flag for a restricted runtime permission that is exempt due to system upgrade.
     *
     * For example, this flag may be set when the package was installed before the system was
     * upgraded to [Build.VERSION_CODES.Q], when restricted permissions were introduced.
     *
     * The permission will be restricted when none of the exempt flags is set.
     *
     * @see PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
     */
    const val UPGRADE_EXEMPT = 1 shl 17

    /**
     * Permission flag for a restricted runtime permission that is revoked due to being hard
     * restricted.
     *
     * @see PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION
     */
    const val RESTRICTION_REVOKED = 1 shl 18

    /**
     * Permission flag for a restricted runtime permission that is soft restricted.
     *
     * @see PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION
     */
    const val SOFT_RESTRICTED = 1 shl 19

    /**
     * Permission flag for a runtime permission whose app op is revoked.
     *
     * For example, this flag may be set when the runtime permission is legacy or implicit but still
     * "revoked" by the user in permission settings, or when the app op mode for the runtime
     * permission is set to revoked via [AppOpsManager.setUidMode].
     *
     * @see PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
     */
    const val APP_OP_REVOKED = 1 shl 20

    /**
     * Permission flag for a runtime permission that is granted as one-time.
     *
     * For example, this flag may be set when the user selected "Only this time" in the request
     * permission dialog.
     *
     * This flag, along with other user decisions when it is set, should never be persisted, and
     * should be removed once the permission is revoked.
     *
     * @see PackageManager.FLAG_PERMISSION_ONE_TIME
     */
    const val ONE_TIME = 1 shl 21

    /**
     * Permission flag for a runtime permission that was revoked due to app hibernation.
     *
     * This flag is informational and added by PermissionController, and should be removed once the
     * permission is granted again.
     *
     * @see PackageManager.FLAG_PERMISSION_AUTO_REVOKED
     */
    const val HIBERNATION = 1 shl 22

    /**
     * Permission flag for a runtime permission that is selected by the user.
     *
     * For example, this flag may be set when one of the coarse/fine location accuracies is
     * selected by the user.
     *
     * This flag is informational and managed by PermissionController.
     *
     * @see PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY
     */
    const val USER_SELECTED = 1 shl 23

    /**
     * Mask for all permission flags.
     */
    const val MASK_ALL = 0.inv()
    const val MASK_GRANTED = INSTALL_GRANTED or PROTECTION_GRANTED or OTHER_GRANTED or ROLE_GRANTED
    const val MASK_RUNTIME = OTHER_GRANTED or IMPLICIT

    /**
     * Mask for all permission flags that may be applied to a runtime permission.
     */
    const val MASK_RUNTIME = ROLE or RUNTIME_GRANTED or USER_SET or USER_FIXED or POLICY_FIXED or
        SYSTEM_FIXED or PREGRANT or LEGACY_GRANTED or IMPLICIT_GRANTED or IMPLICIT or
        USER_SENSITIVE_WHEN_GRANTED or USER_SENSITIVE_WHEN_REVOKED or INSTALLER_EXEMPT or
        SYSTEM_EXEMPT or UPGRADE_EXEMPT or RESTRICTION_REVOKED or SOFT_RESTRICTED or
        APP_OP_REVOKED or ONE_TIME or HIBERNATION or USER_SELECTED

    /**
     * Mask for all API permission flags about permission restriction.
     */
    private const val API_MASK_RESTRICTION =
        PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT or
            PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT or
            PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT or
            PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION

    /**
     * Mask for all permission flags about permission restriction.
     */
    private const val MASK_RESTRICTION = INSTALLER_EXEMPT or SYSTEM_EXEMPT or
        UPGRADE_EXEMPT or RESTRICTION_REVOKED or SOFT_RESTRICTED

    fun isPermissionGranted(policyFlags: Int): Boolean {
        if (policyFlags.hasBits(INSTALL_GRANTED)) {
            return true
        }
        if (policyFlags.hasBits(INSTALL_REVOKED)) {
            return false
        }
        if (policyFlags.hasBits(PROTECTION_GRANTED)) {
            return true
        }
        if (policyFlags.hasBits(LEGACY_GRANTED) || policyFlags.hasBits(IMPLICIT_GRANTED)) {
            return true
        }
        if (policyFlags.hasBits(RESTRICTION_REVOKED)) {
            return false
        }
        return policyFlags.hasBits(RUNTIME_GRANTED)
    }

    fun isAppOpGranted(policyFlags: Int): Boolean =
        isPermissionGranted(policyFlags) && !policyFlags.hasBits(APP_OP_REVOKED)

    fun isReviewRequired(policyFlags: Int): Boolean =
        policyFlags.hasBits(LEGACY_GRANTED) && policyFlags.hasBits(IMPLICIT)

    fun toApiFlags(policyFlags: Int): Int {
        var apiFlags = 0
        if (policyFlags.hasBits(USER_SET)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_SET
        }
        if (policyFlags.hasBits(USER_FIXED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_FIXED
        }
        if (policyFlags.hasBits(POLICY_FIXED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_POLICY_FIXED
        }
        if (policyFlags.hasBits(SYSTEM_FIXED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
        }
        if (policyFlags.hasBits(PREGRANT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
        }
        if (policyFlags.hasBits(IMPLICIT)) {
            apiFlags = apiFlags or if (policyFlags.hasBits(LEGACY_GRANTED)) {
                PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
            } else {
                PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
            }
        }
        if (policyFlags.hasBits(USER_SENSITIVE_WHEN_GRANTED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
        }
        if (policyFlags.hasBits(USER_SENSITIVE_WHEN_REVOKED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED
        }
        if (policyFlags.hasBits(INSTALLER_EXEMPT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
        }
        if (policyFlags.hasBits(SYSTEM_EXEMPT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
        }
        if (policyFlags.hasBits(UPGRADE_EXEMPT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
        }
        if (policyFlags.hasBits(RESTRICTION_REVOKED) || policyFlags.hasBits(SOFT_RESTRICTED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION
        }
        if (policyFlags.hasBits(ROLE)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE
        }
        if (policyFlags.hasBits(APP_OP_REVOKED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
        }
        if (policyFlags.hasBits(ONE_TIME)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_ONE_TIME
        }
        if (policyFlags.hasBits(HIBERNATION)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_AUTO_REVOKED
        }
        if (policyFlags.hasBits(USER_SELECTED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY
        }
        return apiFlags
    }

    fun setRuntimePermissionGranted(policyFlags: Int, isGranted: Boolean): Int =
        if (isGranted) policyFlags or RUNTIME_GRANTED else policyFlags andInv RUNTIME_GRANTED

    fun updatePolicyFlags(policyFlags: Int, apiFlagMask: Int, apiFlagValues: Int): Int {
        check(!apiFlagMask.hasAnyBit(API_MASK_RESTRICTION)) {
            "Permission flags about permission restriction can only be directly mutated by the" +
                " policy"
        }
        val oldApiFlags = toApiFlags(policyFlags)
        val newApiFlags = (oldApiFlags andInv apiFlagMask) or (apiFlagValues and apiFlagMask)
        return toPolicyFlags(policyFlags, newApiFlags)
    }

    private fun toPolicyFlags(oldPolicyFlags: Int, apiFlags: Int): Int {
        var policyFlags = 0
        policyFlags = policyFlags or (oldPolicyFlags and INSTALL_GRANTED)
        policyFlags = policyFlags or (oldPolicyFlags and INSTALL_REVOKED)
        policyFlags = policyFlags or (oldPolicyFlags and PROTECTION_GRANTED)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE)) {
            policyFlags = policyFlags or ROLE
        }
        policyFlags = policyFlags or (oldPolicyFlags and RUNTIME_GRANTED)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_SET)) {
            policyFlags = policyFlags or USER_SET
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_FIXED)) {
            policyFlags = policyFlags or USER_FIXED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_POLICY_FIXED)) {
            policyFlags = policyFlags or POLICY_FIXED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) {
            policyFlags = policyFlags or SYSTEM_FIXED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT)) {
            policyFlags = policyFlags or PREGRANT
        }
        policyFlags = policyFlags or (oldPolicyFlags and LEGACY_GRANTED)
        policyFlags = policyFlags or (oldPolicyFlags and IMPLICIT_GRANTED)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) ||
            apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)) {
            policyFlags = policyFlags or IMPLICIT
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)) {
            policyFlags = policyFlags or USER_SENSITIVE_WHEN_GRANTED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED)) {
            policyFlags = policyFlags or USER_SENSITIVE_WHEN_REVOKED
        }
        // FLAG_PERMISSION_APPLY_RESTRICTION can be either REVOKED_BY_RESTRICTION when the
        // permission is hard restricted, or SOFT_RESTRICTED when the permission is soft restricted.
        // However since we should never allow indirect mutation of restriction state, we can just
        // get the flags about restriction from the old policy flags.
        policyFlags = policyFlags or (oldPolicyFlags and MASK_RESTRICTION)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)) {
            policyFlags = policyFlags or APP_OP_REVOKED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_ONE_TIME)) {
            policyFlags = policyFlags or ONE_TIME
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_AUTO_REVOKED)) {
            policyFlags = policyFlags or HIBERNATION
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY)) {
            policyFlags = policyFlags or USER_SELECTED
        }
        return policyFlags
    }
}
+12 −2
Original line number Diff line number Diff line
@@ -232,7 +232,12 @@ class PermissionService(
    }

    override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
        TODO("Not yet implemented")
        // TODO: Implement permission checks.
        val appId = 0
        val flags = service.getState {
            with(policy) { getPermissionFlags(appId, userId, permissionName) }
        }
        return PermissionFlags.toApiFlags(flags)
    }

    override fun isPermissionRevokedByPolicy(
@@ -244,7 +249,12 @@ class PermissionService(
    }

    override fun isPermissionsReviewRequired(packageName: String, userId: Int): Boolean {
        TODO("Not yet implemented")
        val packageState = packageManagerLocal.withUnfilteredSnapshot()
            .use { it.packageStates[packageName] } ?: return false
        val permissionFlags = service.getState {
            with(policy) { getUidPermissionFlags(packageState.appId, userId) }
        } ?: return false
        return permissionFlags.anyIndexed { _, _, flags -> PermissionFlags.isReviewRequired(flags) }
    }

    override fun shouldShowRequestPermissionRationale(
+11 −8

File changed.

Preview size limit exceeded, changes collapsed.