权限检查
本文承接 权限服务架构、权限类型 和 授予运行时权限。主题是 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
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
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
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
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
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 限制
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
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 结果。
adb shell dumpsys package <package.name>
adb shell pm check-permission <permission> <package.name> --user 0
adb shell appops get <package.name>8. 源码路线
PermissionManagerService.checkPermission:null、delegate 和门面边界。PermissionService.checkPermission:用户、filtered snapshot 和 package state。isPermissionGranted:fuller permission 与 instant app。checkUidPermission:UID 反查、system UID 和 PCC。PermissionFlags.isPermissionGranted:flags 汇总。PermissionCheckerService:attribution、AppOps 和 data delivery。
权限检查的主线是“先确认对象可见,再读取 appId/user/device flags,最后按包类型和数据访问场景补充限制”。包名检查、UID 检查、delegate、system UID 和 PermissionChecker 各自拥有不同输入与消费者;把它们混成一个 boolean,是排查权限问题时最常见的误区。
