PermissionController 角色
本文承接 权限框架、权限服务架构、权限类型 和 授予运行时权限。角色权限不是另一套独立的 permission database:角色系统选出 holder 后,PermissionController 以受信 appId 调用权限服务授予或撤销带 PROTECTION_FLAG_ROLE 的权限。本文专门追踪这个“角色分配 → PermissionController → PermissionService → AccessState flags”边界,解释普通应用为何不能直接操作角色权限,以及角色变更如何影响运行时状态。
1. 角色与权限
1.1 两个 owner
| 对象 | owner | 保存内容 |
|---|---|---|
| 角色 holder | RoleManager/RoleController | 某 user 的角色到包名集合 |
| 角色权限状态 | PermissionService/AccessState | appId/user/permission flags |
| 角色 UI/策略 | PermissionController | 角色候选、默认应用、权限同步 |
角色 holder 变化不会直接修改 APK Manifest;PermissionController 依据角色定义计算应该授予的权限,再调用系统权限接口。角色和权限状态可以短暂处于更新过程中,最终由各自持久化机制提交。
2. Controller 身份
2.1 Known package
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
val permissionControllerPackageName =
packageManagerInternal.getKnownPackageNames(
KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
UserHandle.USER_SYSTEM,
).first()
val permissionControllerPackageState =
packageManagerInternal.getPackageStateInternal(
permissionControllerPackageName)PermissionService 不硬编码 PermissionController 包名,而从 KnownPackages.PACKAGE_PERMISSION_CONTROLLER 获取,再读取其 appId。OEM 可以替换包名,只要系统 known package 配置正确。
2.2 角色管理权限
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
val canManageRolePermission =
isRootOrSystemUid(callingUid) ||
UserHandle.getAppId(callingUid) ==
permissionControllerPackageState!!.appId能管理角色权限的调用者只有 root/system 或 PermissionController appId。普通应用即使持有 GRANT_RUNTIME_PERMISSIONS,也不能直接改变 role-managed permission;这是角色策略与普通权限管理的边界。
3. Role protection
3.1 Permission 属性
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/Permission.kt
inline val isRole: Boolean
get() = protectionFlags.hasBits(
PermissionInfo.PROTECTION_FLAG_ROLE)
inline val isRuntime: Boolean
get() = protection == PermissionInfo.PROTECTION_DANGEROUSrole 是 protection flag,不是新的基础 protection。一个角色权限通常同时是 runtime permission,因此必须同时满足 role caller 和 runtime/flags 的其他规则。
3.2 统一授予入口
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
when {
permission.isDevelopment -> Unit
permission.isRole -> {
if (!canManageRolePermission) {
if (reportError) {
throw SecurityException(
"Permission $permissionName is managed by role")
}
return
}
}
permission.isRuntime -> {
if (androidPackage.targetSdkVersion < Build.VERSION_CODES.M) {
return
}
}
else -> {
if (reportError) {
throw SecurityException(
"Permission $permissionName is not a changeable type")
}
return
}
}角色授予最终复用 setRuntimePermissionGranted。普通 runtime 权限只需通过 runtime 分支;role 权限先经过 canManageRolePermission,失败时抛 SecurityException 或在批量静默场景返回。
4. 角色授予
4.1 外部角色 API
RoleManager 的 addRoleHolderAsUser 是角色分配入口;它不直接写 permission flags,而是把角色变更交给 RoleManagerService,再由 RoleController/PermissionController 计算权限集合。角色的 userId 与权限授予的 userId 必须一致,否则会出现角色显示与权限状态不对应。
4.2 Controller 调用
// PermissionManagerService.java:角色管理最终调用的统一权限 API
public void grantRuntimePermission(String packageName,
String permissionName, String persistentDeviceId,
int userId) {
mPermissionManagerServiceImpl.grantRuntimePermission(
packageName, permissionName,
persistentDeviceId, userId);
}PermissionController 通过受保护的 system API/内部调用进入该方法。PermissionService 根据 caller appId 识别它是 PermissionController,而不是依赖调用者传入“我是角色管理器”的参数。
5. ROLE flags
5.1 状态来源
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
/** Permission granted by a role or was granted by a role. */
const val ROLE = 1 shl 3
/** Development, role or runtime permission granted explicitly. */
const val RUNTIME_GRANTED = 1 shl 4ROLE 记录授予来源,RUNTIME_GRANTED 记录当前 runtime grant 来源;二者可同时出现。角色移除时 PermissionController 清理 role 来源,但不能无条件覆盖用户独立授予或 policy fixed 状态。
5.2 角色与用户选择
角色授予和用户在 Settings 中手动 grant 是不同来源。角色 holder 被移除时,PermissionController 应撤销由 role 产生的 flags;如果用户另有独立 grant,最终状态需要保留相应 runtime/user flags。PermissionService 只执行 flags mutation 和权限约束,不负责推导哪个角色应该拥有哪个包。
6. 失败边界
6.1 普通 caller
普通应用直接调用 grant/revoke role permission 会在 PermissionService 抛 SecurityException("Permission ... is managed by role")。它不能通过 GRANT_RUNTIME_PERMISSIONS 伪装成 PermissionController。
6.2 Controller 缺失
PermissionService 初始化时必须能从 KnownPackages 找到 PermissionController PackageState。若 known package 配置缺失,角色权限管理能力无法正确判断;这不是普通应用可以通过权限声明修复的运行时错误。
6.3 user 不一致
角色属于某个 user,权限 flags 也按 user 存储。用 system user 的 PermissionController appId 为另一个用户直接写入,仍会经过 cross-user 权限和目标 user 检查,不能绕过多用户隔离。
7. 验证方法
7.1 角色授予
选择一个可用默认角色,记录 holder 变化和目标包 role permission flags。断言普通 permission check 变为 granted,但调用者是 PermissionController 才能完成 role permission 写入;角色移除后 role 来源清除。
7.2 普通 caller 拒绝
让普通测试应用声明并请求管理 role permission,调用 grant/revoke。预期 SecurityException,AccessState flags 不变;这验证 caller appId 而非 Manifest permission 决定角色管理资格。
7.3 用户隔离
在 user 0 和 user 10 分别设置不同 role holder,比较 getPermissionFlags。角色 permission 状态应按 user 独立变化,不应因为 system user 的角色变更自动授予另一个用户。
adb shell dumpsys role
adb shell dumpsys package <package.name> | grep -E 'permission|ROLE|granted'
adb shell pm check-permission <permission> <package.name> --user 08. 源码路线
RoleManager/RoleManagerService:阅读角色 holder 的 user-scoped API。KnownPackages.PACKAGE_PERMISSION_CONTROLLER:确认 PermissionController 身份来源。PermissionService的canManageRolePermission:理解 root/system/PermissionController appId 条件。setRuntimePermissionGrantedrole 分支:确认 role 与 runtime 类型的共同校验。PermissionFlags.ROLE/RUNTIME_GRANTED:区分授予来源。- PermissionController 的角色同步调用:继续追踪角色变化如何调用 grant/revoke。
角色系统不是让角色 holder绕过权限服务,而是让受信 PermissionController 通过同一权限 mutation API 设置 role 来源 flags。RoleManager 保存角色关系,PermissionController 计算权限集合,PermissionService 验证调用者和权限类型,AccessState 保存 user/appId 状态;四者分工决定了普通应用无法伪造角色授予,也保证角色变化与权限检查最终一致。
