Skip to content

PermissionController 角色

解释 Android 17 角色权限的 PermissionController 身份校验、授予路径和 ROLE flags。

基于android-17.0.0_r1
AndroidPermissionControllerRoleManagerPermissionService源码阅读

PermissionController 角色 ​

本文承接 权限框架、权限服务架构、权限类型 和 授予运行时权限。角色权限不是另一套独立的 permission database:角色系统选出 holder 后,PermissionController 以受信 appId 调用权限服务授予或撤销带 PROTECTION_FLAG_ROLE 的权限。本文专门追踪这个“角色分配 → PermissionController → PermissionService → AccessState flags”边界,解释普通应用为何不能直接操作角色权限,以及角色变更如何影响运行时状态。

1. 角色与权限 ​

1.1 两个 owner ​

对象owner保存内容
角色 holderRoleManager/RoleController某 user 的角色到包名集合
角色权限状态PermissionService/AccessStateappId/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

kotlin
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

kotlin
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

kotlin
inline val isRole: Boolean
    get() = protectionFlags.hasBits(
        PermissionInfo.PROTECTION_FLAG_ROLE)

inline val isRuntime: Boolean
    get() = protection == PermissionInfo.PROTECTION_DANGEROUS

role 是 protection flag,不是新的基础 protection。一个角色权限通常同时是 runtime permission,因此必须同时满足 role caller 和 runtime/flags 的其他规则。

3.2 统一授予入口 ​

源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt

kotlin
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 调用 ​

java
// 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

kotlin
/** 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 4

ROLE 记录授予来源,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 的角色变更自动授予另一个用户。

bash
adb shell dumpsys role
adb shell dumpsys package <package.name> | grep -E 'permission|ROLE|granted'
adb shell pm check-permission <permission> <package.name> --user 0

8. 源码路线 ​

  1. RoleManager/RoleManagerService:阅读角色 holder 的 user-scoped API。
  2. KnownPackages.PACKAGE_PERMISSION_CONTROLLER:确认 PermissionController 身份来源。
  3. PermissionService 的 canManageRolePermission:理解 root/system/PermissionController appId 条件。
  4. setRuntimePermissionGranted role 分支:确认 role 与 runtime 类型的共同校验。
  5. PermissionFlags.ROLE/RUNTIME_GRANTED:区分授予来源。
  6. PermissionController 的角色同步调用:继续追踪角色变化如何调用 grant/revoke。

角色系统不是让角色 holder绕过权限服务,而是让受信 PermissionController 通过同一权限 mutation API 设置 role 来源 flags。RoleManager 保存角色关系,PermissionController 计算权限集合,PermissionService 验证调用者和权限类型,AccessState 保存 user/appId 状态;四者分工决定了普通应用无法伪造角色授予,也保证角色变化与权限检查最终一致。