权限组
本文承接 权限定义与声明、权限类型 和 运行时权限请求。权限组不是只服务 UI 的分类表:Manifest 组会进入 AndroidPackage.permissionGroups,包加入时由 AppIdPermissionPolicy 注册到 AccessState,组 owner 或 runtime group 变化还会影响已有 permission flags。
1. 数据模型
1.1 组和权限
ParsedPermissionGroup 保存名称、label、icon、请求文案资源和 priority;PermissionInfo.group 只保存 permission 指向的组名。组没有整体 grant 位,组内 permission 仍按 appId、用户和设备保存 flags。
2. 注册路径
2.1 包加入
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
override fun MutateStateScope.onPackageAdded(
packageState: PackageState
) {
val changed = MutableIndexedSet<String>()
adoptPermissions(packageState, changed)
addPermissionGroups(packageState)
addPermissions(packageState, changed)
trimPermissions(packageState.packageName, changed)
trimPermissionStates(packageState.appId)
changed.forEachIndexed { _, name ->
evaluatePermissionStateForAllPackages(name, null)
}
evaluateAllPermissionStatesForPackage(packageState, packageState)
}组注册、permission 注册、旧定义裁剪和 appId 重评估在同一 AccessState mutation 中完成;一个包的组变化可能影响其他包的 runtime 评估。
2.2 组写入
private fun MutateStateScope.addPermissionGroups(
packageState: PackageState
) {
val allUsersInstant = packageState.userStates.allIndexed {
_, _, state -> state.isInstantApp
}
if (allUsersInstant) {
Slog.w(LOG_TAG, "Ignoring permission groups declared by instant app")
return
}
packageState.androidPackage!!.permissionGroups
.forEachIndexed { _, parsedGroup ->
val info = PackageInfoUtils.generatePermissionGroupInfo(
parsedGroup, PackageManager.GET_META_DATA.toLong())!!
newState.mutateSystemState()
.mutatePermissionGroups()[info.name] = info
}
}只有所有用户都是 instant app 时才忽略组;普通包不能覆盖已有 owner,system 包可覆盖非 system owner,但不能覆盖另一个 system owner。
3. 定义变化
3.1 组名关联
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/Permission.kt
data class Permission(
val permissionInfo: PermissionInfo,
val isReconciled: Boolean,
val type: Int,
val appId: Int,
) {
inline val groupName: String?
get() = permissionInfo.group
}permission 通过字符串关联组,不持有对象引用;组 owner 变化时可以按 name 重新解析。
3.2 定义变化
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
val groupChanged = newPermissionInfo.isRuntime &&
newPermissionInfo.group != oldPermission.groupName
val protectionChanged =
(newPermissionInfo.isRuntime && !oldPermission.isRuntime) ||
(newPermissionInfo.isInternal && !oldPermission.isInternal)
if (groupChanged || protectionChanged) {
newState.externalState.userIds.forEachIndexed { _, userId ->
newState.externalState.appIdPackageNames
.forEachIndexed { _, appId, _ ->
setPermissionFlags(appId, userId, permissionName, 0)
}
}
}runtime permission 改组或 protection 变化时,所有 appId/user 旧 flags 清零后重算,避免组自动授予扩散旧语义。
4. 查询与消费
4.1 查询 API
源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
public ParceledListSlice<PermissionGroupInfo>
getAllPermissionGroups(int flags) {
return new ParceledListSlice<>(
mPermissionManagerServiceImpl.getAllPermissionGroups(flags));
}
public PermissionGroupInfo getPermissionGroupInfo(
String groupName, int flags) {
return mPermissionManagerServiceImpl
.getPermissionGroupInfo(groupName, flags);
}Binder 门面包装查询结果;PermissionController 使用 group name、label、description、priority 组织 UI,但点击后仍逐 permission 调用 grant/revoke。
4.2 包移除
onPackageRemoved 先 trim 不再声明的 group/permission,再按 appId 重新评估 shared UID 中剩余包。组删除不会自动删除仍被其他包声明的 permission。
5. 验证方法
5.1 重复与 instant
两个普通包声明同名 group,后者应被忽略;system 包可接管非 system owner。所有用户均为 instant app 时组不应进入查询结果;存在 full-app 用户时可注册。
5.2 组变化
更新 runtime permission 的 group,检查所有用户/appId 的 flags 被清零并重新评估;删除 group 定义后,其他包仍声明的 permission 不应消失。
adb shell pm list permissions -f -g
adb shell dumpsys package <package.name>6. 源码路线
ParsedPermissionGroup:解析字段和资源元数据。AppIdPermissionPolicy.onPackageAdded:注册与重评估。addPermissionGroups:instant app 和 owner 冲突。Permission.groupName:组与 permission 的字符串关联。- group/protection change:flags 清零原因。
trimPermissions/onPackageRemoved:卸载和 shared UID 裁剪。getAllPermissionGroups/getPermissionGroupInfo:查询和 UI 消费。
权限组只定义关联和展示,不拥有整体授权。Android 17 把组 definition、permission protection、appId/user flags 和 UI 查询分开管理;组可以影响展示与评估,却不能绕过每个 permission 的签名、fixed、restricted、role 和 AppOps 规则。
