22. 权限策略与角色:RoleManager、PermissionPolicyManager 如何影响 PMS 决策
权限管理,说白了就是 Android 系统里最核心的“看门狗”逻辑。PMS(PackageManagerService)负责安装、卸载、查询包信息,但真正决定“这个 App 能不能用这个权限”的,其实是另外两个角色:RoleManager 和 PermissionPolicyManager。嗯,今天我们就来聊聊它们是怎么“左右” PMS 决策的。
22.1 先搞清楚:PMS 不是一个人在战斗
很多同学以为 PMS 是权限的最终裁决者。其实不是。PMS 更像是一个“执行者”,它负责存储权限状态、提供查询接口,但真正的策略判断,往往要问过 PermissionPolicyManager 和 RoleManager。
我个人的理解是:
PMS 是“数据库”,PermissionPolicyManager 是“策略引擎”,RoleManager 是“角色分配器”。
举个例子:
当系统要判断某个 App 是否拥有 LOCATION 权限时,PMS 会先查自己的数据库,看看有没有授权记录。但 PermissionPolicyManager 可能会说:“等一下,这个 App 是后台启动的,按策略应该拒绝。” 这时候 PMS 就得听它的。
22.2 RoleManager:角色即权限的“快捷方式”
RoleManager 是 Android 10 引入的,说白了就是给某些“系统角色”预定义了一组权限。比如:
- 角色:短信默认应用 → 自动获得
SMS权限 - 角色:拨号默认应用 → 自动获得
PHONE权限 - 角色:无障碍服务 → 自动获得
BIND_ACCESSIBILITY_SERVICE权限
你想想看,如果没有 RoleManager,每个默认应用都得单独申请权限,用户还得手动确认,多麻烦。RoleManager 就是帮 PMS 做了一层“角色到权限”的映射。
我记得在 Android 11 的一个项目中,客户要求自定义一个“设备管理角色”。当时我直接调了 RoleManager.addRoleHolderAsUser(),然后 PMS 那边就自动给这个角色绑定的 App 授予了 DEVICE_ADMIN 权限。嗯,省了不少事。
22.2.1 RoleManager 如何影响 PMS?
流程其实很简单:
- App 被设置为某个角色(比如默认浏览器)。
- RoleManager 通知 PMS:“这个 App 现在是浏览器角色了,请授予它
INTERNET和QUERY_ALL_PACKAGES权限。” - PMS 收到通知后,调用
grantRuntimePermission()进行授权。
反过来,如果角色被移除,RoleManager 也会通知 PMS 撤销对应的权限。
roles.xml 中声明权限列表,结果角色分配了,但权限没授予。后来查了源码才发现,RoleManager 只负责“通知”,真正的授权逻辑还是在 PMS 里。所以一定要确保角色定义和权限列表匹配。
22.3 PermissionPolicyManager:策略的“守门员”
PermissionPolicyManager 是 Android 11 之后才独立出来的一个组件。它的职责很明确:在 PMS 做出最终决定之前,进行策略检查。
举个例子:
Android 12 引入了“权限使用记录”功能。当 App 在后台请求位置权限时,PermissionPolicyManager 会检查:
- 这个 App 是否在前台?
- 用户是否开启了“仅在使用中允许”?
- 系统是否处于省电模式?
如果策略不通过,PermissionPolicyManager 会直接返回“拒绝”,PMS 连数据库都不会改。
22.3.1 策略检查的典型场景
| 场景 | PermissionPolicyManager 行为 | 对 PMS 的影响 |
|---|---|---|
| 后台请求位置权限 | 检查是否满足“后台位置权限”策略 | 若策略拒绝,PMS 返回 PERMISSION_DENIED |
| 请求权限时用户拒绝“不再询问” | 标记该权限为“软拒绝” | PMS 下次直接返回拒绝,不再弹窗 |
| 系统处于“严格模式” | 拦截所有非必要权限请求 | PMS 直接跳过授权流程 |
说白了,PermissionPolicyManager 就是 PMS 的“前置过滤器”。它不存储权限状态,但它决定 PMS 能不能执行授权操作。
permission_policy.xml),来改变 PMS 的行为。我曾经在某个定制项目中,因为策略文件写错了,导致所有 App 都无法获取 STORAGE 权限。排查了两天才发现是策略里把 STORAGE 归类到了“敏感权限”组,而敏感权限组被整体禁用了。
22.4 三者协作的完整流程
为了让你更直观地理解,我画了一张流程图。嗯,这张图我反复改了好几版,力求清晰。
从图中你可以看到:
App 请求权限 → PMS 先问 PermissionPolicyManager → 策略通过后,再问 RoleManager 是否需要角色映射 → 最后 PMS 执行授权或拒绝。
如果策略拒绝,PMS 连数据库都不会查,直接返回。这就是为什么有时候你明明在 Settings 里看到权限是“允许”,但 App 还是拿不到——因为策略层把它拦了。
22.5 实际项目中的坑与经验
我遇到过最典型的一个问题是:RoleManager 和 PermissionPolicyManager 的优先级冲突。
当时有个 App 被设置为“默认相机角色”,按道理应该自动获得 CAMERA 权限。但 PermissionPolicyManager 里有一条策略:禁止所有 App 在后台使用相机。结果这个 App 在后台启动时,PMS 先问了 PermissionPolicyManager,策略拒绝,RoleManager 的映射根本没机会执行。
解决方案?嗯,我们最后在 PermissionPolicyManager 的策略里加了一个例外:对于“默认相机角色”的 App,忽略后台相机限制。说白了,就是让策略层知道“这个 App 是特殊的”。
checkPermission() 方法会先调用 PermissionPolicyManager.onCheckPermission(),然后再查角色。所以策略的优先级高于角色。
22.6 小结
RoleManager 和 PermissionPolicyManager 不是 PMS 的替代品,而是它的“左右手”。一个负责角色到权限的自动映射,一个负责策略层面的拦截。两者共同决定了 PMS 的最终输出。
你想想看,如果没有它们,PMS 就得自己处理所有逻辑,那代码得多臃肿。Android 团队把它们拆出来,说白了就是为了让权限管理更灵活、更可配置。
嗯,今天就聊到这里。下一章我们继续深入 PMS 的内部机制,看看它到底是怎么存储和查询权限状态的。
公众号:蓝海资料掘金营,微信deep3321