权限授予:从安装期到运行时
权限授予:从安装期到运行时
上一章我们看了签名。这一章回答:应用声明的权限什么时候被授予,normal、dangerous、 signature 权限有什么区别,运行时弹窗背后的检查链是什么?
Manifest 中的权限声明只是申请。最终结果由权限保护级别、签名关系、用户授权状态及 AppOps 等运行时策略共同决定,而且危险权限的运行时权限状态按 Android 用户分别保存。
声明权限不等于已经获准访问
| 常见误解 | 正确理解 |
|---|---|
| 所有权限都是运行时弹窗 | normal 与 signature 权限在安装期授予,只有 dangerous 才弹窗 |
| 权限存在 APK 里 | 权限由系统数据库管理,授予状态持久化在 /data/system/ |
| 检查权限就是查一个布尔值 | 权限检查会走 permission 树、用户态授予、AppOps、角色等多层 |
核心结论
- 权限分三类授予时机:normal/install-time 安装期授予,dangerous 运行时授予, signature 按签名匹配授予。
- 权限定义与授予状态由 PermissionManagerService 管理,并持久化到用户目录下的 runtime-permissions.xml。
- 运行时检查链:应用 API → 权限检查服务 → 授予状态 + AppOps + 角色策略。
- 权限声明来自 Manifest,权限能否授予还受权限树(permission tree)与系统策略约束。
- 权限与签名联动:signature 级权限只授予持有相同签名的应用。
授权与检查主链
逐步解释:
- 声明:Manifest 里声明需要的权限。
- 安装期:normal 与 signature 权限按规则直接授予,dangerous 等待运行期。
- 运行期申请:应用请求 dangerous 权限,系统弹窗由用户决定。
- 持久化:授予状态写入用户目录的 runtime-permissions.xml。
- 调用期检查:系统 API 每次调用都要走权限判定,并叠加 AppOps 与角色策略。
为什么“权限树”重要
系统应用可以声明自己的权限(permission tree 的 root),第三方应用必须显式申请这些权限 才能使用对应 API。权限检查不是“有名字就通过”,而是先找权限定义,再查授予状态。 这就是为什么“权限没定义”和“权限没授予”是两类不同问题。
源码证据
阅读目标:确认权限管理服务与检查入口。
正文指针:PermissionManagerService.java 的授予与检查; PackageManagerService.java 中安装期的权限授予调用;PermissionInfo.java 定义。
// PermissionManagerService.java(伪代码,行号以 r75 为准)
boolean checkPermission(String permission, String packageName, int userId) {
// 查权限定义与用户授予状态
}
void grantRuntimePermission(String packageName, String permissionName, int userId) { ... }这段代码证明: 授予与检查都以“包名 + 权限 + 用户”为维度;运行期状态按用户隔离, 多用户下同一应用在不同用户可能有不同授予结果。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell pm list permissions
adb shell pm grant <包名> android.permission.CAMERA
adb shell pm revoke <包名> android.permission.CAMERA
adb shell dumpsys package <包名> | grep -A20 "runtime permissions"pm list permissions 看权限定义;pm grant/revoke 手动调整授予状态; dumpsys package 的 runtime permissions 段落看当前授予。权限问题排查顺序: 先确认权限被定义,再确认被授予,再看 AppOps 与角色策略是否拦截。
常见误区
- “所有权限都弹窗”:只有 dangerous 运行时弹窗。
- “权限状态存在 APK 里”:存在系统数据库并持久化到 xml。
- “授权了就能用”:还要过 AppOps、角色与权限策略。
- “签名级权限任何应用都能申请”:只有同签名应用能获得。
延伸问题
- 角色(role)如何与权限授予联动(如默认短信应用)?
- AppOps 与权限的检查顺序是怎样的?
- 多用户下权限授予如何隔离?
- 权限升级(appop 升级为 runtime permission)的兼容逻辑是什么?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
PermissionManagerService.java | checkPermission() / grantRuntimePermission() | 授予与检查 |
PermissionInfo.java | 权限定义 | 类型与保护级别 |
PackageManagerService.java | 安装期授予调用 | 默认授予逻辑 |
runtime-permissions.xml | 用户目录 | 授予状态持久化 |
公共路径:frameworks/base/services/core/java/com/android/server/pm/permission/ 与 frameworks/base/core/java/android/content/pm/。行号以 r75 检索为准。
包与用户身份如何映射到文件目录,见 应用数据与存储。