22. 权限策略与角色:RoleManager、PermissionPolicyManager 如何影响 PMS 决策

权限管理,说白了就是 Android 系统里最核心的“看门狗”逻辑。PMS(PackageManagerService)负责安装、卸载、查询包信息,但真正决定“这个 App 能不能用这个权限”的,其实是另外两个角色:RoleManagerPermissionPolicyManager。嗯,今天我们就来聊聊它们是怎么“左右” PMS 决策的。

22.1 先搞清楚:PMS 不是一个人在战斗

很多同学以为 PMS 是权限的最终裁决者。其实不是。PMS 更像是一个“执行者”,它负责存储权限状态、提供查询接口,但真正的策略判断,往往要问过 PermissionPolicyManager 和 RoleManager。

我个人的理解是:
PMS 是“数据库”,PermissionPolicyManager 是“策略引擎”,RoleManager 是“角色分配器”。

举个例子:
当系统要判断某个 App 是否拥有 LOCATION 权限时,PMS 会先查自己的数据库,看看有没有授权记录。但 PermissionPolicyManager 可能会说:“等一下,这个 App 是后台启动的,按策略应该拒绝。” 这时候 PMS 就得听它的。

核心结论: PMS 的决策流程中,PermissionPolicyManager 负责“策略拦截”,RoleManager 负责“角色映射”。两者共同影响 PMS 的 grant/revoke 结果。

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?

流程其实很简单:

  1. App 被设置为某个角色(比如默认浏览器)。
  2. RoleManager 通知 PMS:“这个 App 现在是浏览器角色了,请授予它 INTERNETQUERY_ALL_PACKAGES 权限。”
  3. 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 能不能执行授权操作。

注意: PermissionPolicyManager 的策略是“可配置的”。厂商可以自定义策略文件(比如 permission_policy.xml),来改变 PMS 的行为。我曾经在某个定制项目中,因为策略文件写错了,导致所有 App 都无法获取 STORAGE 权限。排查了两天才发现是策略里把 STORAGE 归类到了“敏感权限”组,而敏感权限组被整体禁用了。

22.4 三者协作的完整流程

为了让你更直观地理解,我画了一张流程图。嗯,这张图我反复改了好几版,力求清晰。

App 请求权限 PMS 接收请求 PermissionPolicyManager 策略检查 通过 拒绝 拒绝 RoleManager 角色映射检查 PMS 最终授权/拒绝 图例: App/PMS 策略检查 角色映射 最终决策

从图中你可以看到:
App 请求权限 → PMS 先问 PermissionPolicyManager → 策略通过后,再问 RoleManager 是否需要角色映射 → 最后 PMS 执行授权或拒绝。

如果策略拒绝,PMS 连数据库都不会查,直接返回。这就是为什么有时候你明明在 Settings 里看到权限是“允许”,但 App 还是拿不到——因为策略层把它拦了。

22.5 实际项目中的坑与经验

我遇到过最典型的一个问题是:RoleManager 和 PermissionPolicyManager 的优先级冲突

当时有个 App 被设置为“默认相机角色”,按道理应该自动获得 CAMERA 权限。但 PermissionPolicyManager 里有一条策略:禁止所有 App 在后台使用相机。结果这个 App 在后台启动时,PMS 先问了 PermissionPolicyManager,策略拒绝,RoleManager 的映射根本没机会执行。

解决方案?嗯,我们最后在 PermissionPolicyManager 的策略里加了一个例外:对于“默认相机角色”的 App,忽略后台相机限制。说白了,就是让策略层知道“这个 App 是特殊的”。

个人建议: 如果你在定制系统,一定要先理清 RoleManager 和 PermissionPolicyManager 的调用顺序。PMS 的源码里,checkPermission() 方法会先调用 PermissionPolicyManager.onCheckPermission(),然后再查角色。所以策略的优先级高于角色。

22.6 小结

RoleManager 和 PermissionPolicyManager 不是 PMS 的替代品,而是它的“左右手”。一个负责角色到权限的自动映射,一个负责策略层面的拦截。两者共同决定了 PMS 的最终输出。

你想想看,如果没有它们,PMS 就得自己处理所有逻辑,那代码得多臃肿。Android 团队把它们拆出来,说白了就是为了让权限管理更灵活、更可配置。

嗯,今天就聊到这里。下一章我们继续深入 PMS 的内部机制,看看它到底是怎么存储和查询权限状态的。


公众号:蓝海资料掘金营,微信deep3321