Skip to content

权限检查

追踪 Android 17 checkPermission 与 checkUidPermission 的快照、flags、instant app 和系统 UID 路径。

基于android-17.0.0_r1
AndroidPermissionServicecheckPermissionAppOps源码阅读

权限检查 ​

本文承接 权限服务架构、权限类型 和 授予运行时权限。主题是 Android 17 的权限读取:包名检查与 UID 检查为何不是一条路径,delegate 如何插入,AccessState flags 如何汇总成 granted/denied,instant app 和 system UID 为何有额外分支,以及 PermissionChecker 为什么不能用普通 checkPermission 代替。

1. 两个入口 ​

1.1 包名检查 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java

java
public int checkPermission(String packageName,
        String permissionName, String persistentDeviceId,
        int userId) {
    if (packageName == null || permissionName == null) {
        return PackageManager.PERMISSION_DENIED;
    }
    final CheckPermissionDelegate delegate;
    synchronized (mLock) {
        delegate = mCheckPermissionDelegate;
    }
    if (delegate == null) {
        return mPermissionManagerServiceImpl.checkPermission(
                packageName, permissionName,
                persistentDeviceId, userId);
    }
    return delegate.checkPermission(
            packageName, permissionName,
            persistentDeviceId, userId,
            mPermissionManagerServiceImpl::checkPermission);
}

Java 门面负责 null 兼容和可选 delegate,真实状态读取下沉到 PermissionService。

1.2 UID 检查 ​

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

kotlin
override fun checkUidPermission(
    uid: Int, permissionName: String, deviceId: String
): Int {
    val userId = UserHandle.getUserId(uid)
    if (!userManagerInternal.exists(userId)) {
        return PackageManager.PERMISSION_DENIED
    }
    val androidPackage = packageManagerInternal.getPackage(uid)
    if (androidPackage != null) {
        val packageState = packageManagerInternal
            .getPackageStateInternal(androidPackage.packageName)
            ?: return PackageManager.PERMISSION_DENIED
        val granted = service.getState {
            isPermissionGranted(packageState, userId,
                permissionName, deviceId)
        }
        return if (granted) PackageManager.PERMISSION_GRANTED
        else PackageManager.PERMISSION_DENIED
    }
    return if (isSystemUidPermissionGranted(uid, permissionName))
        PackageManager.PERMISSION_GRANTED
    else PackageManager.PERMISSION_DENIED
}

UID 检查先从 UID 反查 package;反查不到才进入 system UID 静态权限集合。getPackage(uid) 还承担 package visibility 和 instant shared UID 约束。

2. 包名检查 ​

2.1 用户与快照 ​

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

kotlin
override fun checkPermission(
    packageName: String,
    permissionName: String,
    deviceId: String,
    userId: Int,
): Int {
    if (!userManagerInternal.exists(userId)) {
        return PackageManager.PERMISSION_DENIED
    }
    val packageState = packageManagerLocal
        .withFilteredSnapshot(Binder.getCallingUid(), userId)
        .use { it.getPackageState(packageName) }
        ?: return PackageManager.PERMISSION_DENIED
    val granted = service.getState {
        isPermissionGranted(packageState, userId,
            permissionName, deviceId)
    }
    return if (granted) PackageManager.PERMISSION_GRANTED
    else PackageManager.PERMISSION_DENIED
}

检查使用 caller UID 过滤的 PackageManagerLocal snapshot;不可见包与不存在包统一 denied。

2.2 包类型 ​

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

kotlin
private fun GetStateScope.isPermissionGranted(
    packageState: PackageState,
    userId: Int,
    permissionName: String,
    deviceId: String,
): Boolean {
    val appId = packageState.appId
    val instant = packageState
        .getUserStateOrDefault(userId).isInstantApp
    if (isSinglePermissionGranted(appId, userId, instant,
            permissionName, deviceId)) return true
    val fuller = FULLER_PERMISSIONS[permissionName]
    return fuller != null && isSinglePermissionGranted(
        appId, userId, instant, fuller, deviceId)
}

private fun GetStateScope.isSinglePermissionGranted(
    appId: Int, userId: Int, instant: Boolean,
    permissionName: String, deviceId: String,
): Boolean {
    val flags = getPermissionFlagsWithPolicy(
        appId, userId, permissionName, deviceId)
    if (!PermissionFlags.isPermissionGranted(flags)) return false
    if (instant) {
        val permission = with(policy) {
            getPermissions()[permissionName]
        } ?: return false
        if (!permission.isInstant) return false
    }
    return true
}

fuller permission 只在直接检查失败时作为包含关系回退;instant app 还必须满足 permission 的 instant protection flag。

3. UID 分支 ​

3.1 system UID ​

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

kotlin
private fun isSystemUidPermissionGranted(
    uid: Int, permissionName: String
): Boolean {
    val permissions = systemConfig.systemPermissions[uid]
        ?: return false
    if (permissionName in permissions) return true
    val fuller = FULLER_PERMISSIONS[permissionName]
    return fuller != null && fuller in permissions
}

没有可见 AndroidPackage 的 system UID 使用 SystemConfig 静态权限集合;它不是普通 appId/user AccessState grant。

3.2 PCC 限制 ​

kotlin
if (enablePccFrameworkSupport &&
    Process.isPrivateComputeCoreUid(uid)
) {
    val permission = service.getState {
        with(policy) { getPermissions()[permissionName] }
    }
    if (permission?.isAllowedInPrivateComputeCore != true) {
        logPccDenied(permissionName, uid)
        return PackageManager.PERMISSION_DENIED
    }
}

Private Compute Core UID 需要 permission definition 明确允许;主应用 grant 不会自动让 PCC 身份通过。

4. Delegate 与缓存 ​

mCheckPermissionDelegate 在 mLock 下读取,实际 delegate 在锁外执行,可以直接返回自定义结果或调用 super implementation。它影响检查结果,不修改 AccessState。

PermissionManagerService 构造时会失效 package info cache,并关闭 package-name permission cache;checkPermission cache 仍保留。AccessState mutation 会通知相关 cache。排查旧结果时要区分 PackageManager 查询缓存、permission check cache 和 AppOps/资源服务缓存。

5. 数据检查 ​

5.1 数据访问检查 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java

java
public int checkPermission(String permission,
        AttributionSourceState sourceState,
        String message, boolean forDataDelivery,
        boolean startDataDelivery,
        boolean fromDatasource, int attributedOp) {
    final int result = checkPermission(
            mContext, mPermissionManagerServiceInternal,
            permission, new AttributionSource(sourceState),
            message, forDataDelivery, startDataDelivery,
            fromDatasource, attributedOp);
    if (startDataDelivery
            && result != PermissionChecker.PERMISSION_GRANTED
            && result != PermissionChecker.PERMISSION_SOFT_DENIED) {
        finishDataDelivery(...);
    }
    return result;
}

PermissionChecker 还处理 attribution chain、AppOps 和数据访问 start/finish;链中途失败时回收已经开始的 AppOp。

5.2 不能互替 ​

普通 check 只回答 permission flags;真实相机、位置或麦克风 API 还需要 AppOps、前台状态、attribution 和设备策略。checkPermission 返回 granted 不能替代 PermissionChecker 的数据访问结果。

6. 结果解释 ​

6.1 granted 条件 ​

普通包名检查要求用户存在、包对 caller 可见、AccessState flags 表示 granted,并通过 instant app 限制。UID 检查还要求 UID 能解析到可见 package,或命中 system UID 静态权限。

6.2 denied 来源 ​

denied 可能来自用户不存在、包不可见、flags 没有 grant、instant app 不允许、PCC allowlist 缺失、SystemConfig 无 system UID 条目,或 PermissionChecker 后续 AppOps 拒绝。单个返回整数不能说明根因。

7. 验证方法 ​

7.1 包名与 UID ​

对普通包、shared UID 包和不可见包分别调用 package-name 与 UID 检查,确认 filtered snapshot 和 UID 反查路径差异。

7.2 包类型 ​

授予 fuller permission 后检查较窄 permission,确认包含关系不新增 flags;将包变成 instant app,检查不带 instant flag 的权限即使有 grant 也 denied。

7.3 delegate ​

安装测试 delegate,让它对特定 package/permission 返回自定义值;移除 delegate 后结果恢复 AccessState 实际值,证明它是检查层拦截。

7.4 AppOps ​

保持 permission granted,分别将关联 AppOp 设为 allowed、ignored、errored,比较普通 check 与 PermissionChecker/真实 API 结果。

bash
adb shell dumpsys package <package.name>
adb shell pm check-permission <permission> <package.name> --user 0
adb shell appops get <package.name>

8. 源码路线 ​

  1. PermissionManagerService.checkPermission:null、delegate 和门面边界。
  2. PermissionService.checkPermission:用户、filtered snapshot 和 package state。
  3. isPermissionGranted:fuller permission 与 instant app。
  4. checkUidPermission:UID 反查、system UID 和 PCC。
  5. PermissionFlags.isPermissionGranted:flags 汇总。
  6. PermissionCheckerService:attribution、AppOps 和 data delivery。

权限检查的主线是“先确认对象可见,再读取 appId/user/device flags,最后按包类型和数据访问场景补充限制”。包名检查、UID 检查、delegate、system UID 和 PermissionChecker 各自拥有不同输入与消费者;把它们混成一个 boolean,是排查权限问题时最常见的误区。