运行时权限

在 Android 6.0 及更高版本中,Android 应用权限模型旨在使权限更易于用户理解、更实用且更安全。该模型将需要危险权限(请参阅受影响的权限)的 Android 应用从安装时权限模型移至运行时权限模型:

  • 安装时权限

    Android 5.1 及更低版本)用户在安装或更新应用时向应用授予危险权限。设备制造商和运营商可以在不通知用户的情况下,预安装已预先获取权限的应用。

  • 运行时权限

    (Android 6.0 至 9) 用户在应用运行时向应用授予危险权限。何时申请权限(例如,在应用启动时或用户使用特定功能时)取决于应用,但用户可同意/拒绝向应用授予特定权限组中的权限。OEM/运营商可以预安装应用,但除非通过例外流程,否则无法预先获取权限。(请参阅创建例外情况。)

    (Android 10) 用户可以更深入地了解情况,并控制哪些应用具有运动状态识别 (AR) 运行时权限。运行时权限对话框会提示用户选择是始终允许、在使用时允许还是拒绝权限。操作系统在升级到 Android 10 后,已授予应用的权限将会保留,但用户可以在设置中更改权限。

运行时权限可防止应用在未经用户同意的情况下获取对私密数据的访问权限,还可以针对应用所请求或已被授予的权限为用户提供额外背景信息和详细信息。运行时模型鼓励开发者帮助用户了解应用请求权限的原因,并提供更高的透明度,以便用户更好地决定是同意还是拒绝授予权限。

受影响的权限

Android 6.0 及更高版本要求危险权限必须使用运行时权限模式。危险权限是具有更高风险的权限(例如 READ_CALENDAR),此类权限允许请求授权的应用访问用户私密数据或获取设备控制权(这可对用户造成不利影响)。如需查看危险权限列表,请运行以下命令:

adb shell pm list permissions -g -d

Android 6.0 及更高版本不会更改常规权限的行为。这些都是非危险权限,包括常规权限、系统权限和签名权限。常规权限是具有较低风险的权限(例如 SET_WALLPAPER),此类权限允许请求授权的应用访问隔离的应用级功能,对其他应用、系统或用户的风险非常小。在 Android 5.1 及更低版本中,系统在安装应用时,自动向请求授权的应用授予常规权限,并且不会提示用户进行批准。如需详细了解权限,请参阅 <permission> 元素文档。

Android 10 中的硬性限制和软性限制

除了可能具有危险性之外,权限要么受硬性限制,要么受软性限制。无论是哪种情况,必须将受限权限列入许可名单。未列入许可名单的硬性限制的行为与未列入许可名单的软性限制的行为有所不同:

  • 硬性限制)无法向应用授予未列入许可名单的权限。
  • 软性限制)未列入许可名单的应用会根据它们请求的特定权限进行操作。所请求权限的公开文档中描述了相应的行为。

安装应用时,安装程序(例如 Google Play 商店)可能会选择不将应用的受限权限列入许可名单。权限受平台限制,只有当应用满足各个平台政策的特殊条件时,才可授予权限。例如,受到硬性限制的权限类型包括短信和通话记录权限。

在安装期间及以下情况下,可以执行列入许可名单操作:

  • 在从 Android 9 升级到 Android 10 期间,应用已安装。
  • 预授予权限或预安装应用。
  • 已定义的角色在将权限列入许可名单时需要某个权限。
  • 安装程序(例如 Google Play 商店)将权限标记为已列入许可名单。

用户无法手动将权限列入许可名单。

要求

运行时权限模型适用于所有应用,包括预安装应用和在设置过程中提供给设备的应用。应用的软件要求包括:

  • 在搭载 Android 6.0 及更高版本的所有设备上,运行时权限模式必须保持一致。此一致性可通过 Android 兼容性测试套件 (CTS) 测试来保证。
  • 应用必须提示用户在运行时授予应用权限。如需了解详情,请参阅更新应用。在少数例外情况下,可向默认应用和处理程序授予权限。这些默认应用和处理程序将提供设备预期操作所必需的基本设备功能。(例如,设备中用于处理 ACTION_CALL 的默认拨号程序应用可以获得电话的访问权限。)如需了解详情,请参阅创建例外情况
  • 拥有危险权限的预加载应用必须以 API 级别 23 为目标并保持运行时权限模式。也就是说,应用安装期间界面流程不得偏离 PermissionController 的 AOSP 实现,且用户可以撤消预安装应用的危险权限等。
  • 无头应用必须使用 activity 来请求权限,或与其他拥有必要权限的应用共享 UID。如需了解详情,请参阅无头应用

权限迁移

更新到 Android 6.0 或更高版本后,授予 Android 5.x 应用的权限仍然有效,但用户可以随时撤消此类权限。

在从 Android 9 更新到 Android 10 的过程中,所有硬性限制权限都会列入许可名单。如需详细了解如何实现前台/后台拆分权限,请参阅 Android 10 隐私权变更(从在后台请求访问位置信息开始)。

集成

对于 Android 6.0 及更高版本,在集成应用运行时权限模型时,必须更新预安装应用,使其与新模型兼容。您也可以为负责核心功能的默认处理程序/提供程序等应用定义例外情况,定义自定义权限,以及自定义 PermissionController 中使用的主题。

更新应用

系统映像中的应用和预安装的应用不会自动被预先授予权限。我们建议您与预安装应用的开发者(OEM、运营商和第三方)合作,根据开发者指南对应用进行必要的修改。具体来说,您必须保证对预安装的应用进行修改,以避免用户在撤消权限时造成应用的崩溃和其他问题。

预加载应用

在 Android 9 及更低版本中,使用危险权限的预加载应用必须以 API 级别 23 或更高级别为目标,并保持 Android 6.0 及更高版本的 AOSP 权限模式。例如,应用安装期间界面流程不得偏离 PermissionController 的 AOSP 实现。用户甚至可以撤消预安装应用的危险权限。

在 Android 6.0 到 Android 9.0 中,有些权限会在安装流程中授予。不过,从 Android 10 开始,安装流程(由 Package Installer 应用执行)与权限授予(在 Permission Controller 应用中执行)将是不同的功能。

无头应用

只有 Activity 可以请求权限。服务无法直接请求权限。

  • 在 Android 5.1 及更低版本中,无头应用无需使用 activity 即可在安装或预安装时请求权限。
  • 在 Android 6.0 及更高版本中,无头应用必须使用以下方法之一来请求权限:
    • 添加 activity 以请求权限(这是推荐方法)。
    • 与具有必要权限的其他应用共享 UID。仅当您需要将多个 APK 视作单个应用进行处理时,才推荐使用此方法。

这样做是为了避免突兀的权限请求让用户迷惑。

自定义 PackageInstaller 界面

如有需要,您可以通过更新 PackageInstaller 所用的默认设备主题背景(Theme.DeviceDefault.SettingsTheme.DeviceDefault.Light.Dialog.NoActionBar),自定义权限界面主题背景。但是,由于一致性对应用开发者来说至关重要,您不可以自定义权限界面出现时的位置、定位和规则。

要包含其他语言的字符串,请将此类字符串提交给 AOSP。

创建例外情况

通过使用 PackageManager 中的 DefaultPermissionGrantPolicy.java 类,您可以向负责操作系统核心功能的默认处理程序或提供程序应用进行预授权。示例:

ACTION_CALL (Dialer) Default
Phone, Contacts, SMS, Microphone
SMS_DELIVER_ACTION (SMS/MMS) Default
Phone, Contacts, SMS

定义自定义权限

您可以将自定义权限和组定义为常规或危险级别,并将 OEM/运营商特有的权限添加到现有权限组中,就像在 Android 5.x 和更低版本中那样操作。

在 Android 6.0 及更高版本中,如果您添加了新的危险权限,该权限的处理方式必须与其他危险权限的处理方式相同(在应用运行时请求权限,且用户可以撤消权限)。具体而言:

  • 您可以向当前组添加新权限,但不可以修改危险权限和危险权限组的 AOSP 映射(换句话说,您不能从组中移除权限,再将该权限分配给其他组)。
  • 您可以向安装在设备上的应用添加新的权限组,但不能向 Android 平台清单中添加新的权限组。

测试权限

Android 含有兼容性测试套件 (CTS) 测试,可验证各个权限是否映射到正确的组中。Android 6.0 及更高版本中的 CTS 兼容性要求必须通过此类测试。

撤消权限

在 Android 13 及更高版本中,您可以使用 Context.revokeSelfPermissionsOnKill() 撤消自己已获得的运行时权限。撤消会异步执行,且在不影响干扰用户体验的情况下被触发。触发撤消之后,调用 UID 中运行的所有进程都将终止。

请务必注意,撤消单个权限可能不会反映在设置界面中,此界面按组处理权限。通常,只要权限组中至少一项权限被授予,该权限组就会显示为已授予。如果确保用户能够确认设置中的撤消操作对您而言很重要,请务必撤消权限组中的所有权限。如需了解特定组中包含哪些权限,您可以使用 PackageManager.getGroupOfPlatformPermissionPackageManager.getPlatformPermissionsForGroup

当系统撤消所请求的权限后,如果系统相应前台权限已被撤销,则相应后台权限也会被撤销。

只要进程仍位于前台,就不会触发撤消操作。您也可以通过手动终止当前 uid 中运行的所有进程(例如使用 System.exit())立即触发撤消操作。不过,建议您让系统决定何时触发此操作。

权限撤消生效后,您可以再次请求权限,系统会提示用户批准或拒绝该请求。您无法请求用户之前已拒绝授予的权限。虽然我们鼓励您撤消当前拥有但不再需要的权限,但请谨慎为之,确保撤消操作生效之后再通知用户。