| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| 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 |
| |
| /** |
| * 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() |
| |
| /** |
| * 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 permission flags about permission exemption. |
| */ |
| const val MASK_EXEMPT = INSTALLER_EXEMPT or SYSTEM_EXEMPT or UPGRADE_EXEMPT |
| |
| /** |
| * 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 |
| } |
| } |