安装权限处理
本文承接 安装后注册、Session 安装 和 安装回调。重点不是重新介绍 Android 权限保护级别,而是追踪安装提交时的权限参数如何从 SessionParams 进入 InstallPackageHelper,再传给 PermissionManagerServiceInternal.onPackageInstalled。读完后,读者应能区分“请求授予”和“实际授予”、理解更新时权限为何继承、定位受限权限 allowlist 和权限模型降级的失败边界。
1. 权限输入
1.1 三类输入
安装权限决策同时读取三类数据:APK Manifest 中的 requested permissions,session 传入的显式权限状态,以及安装标志携带的批量授予/受限权限 allowlist。InstallRequest 只是把这些输入带到 commit;真正的权限状态 owner 是 PermissionManagerService。
1.2 标志和状态
源码文件:frameworks/base/core/java/android/content/pm/PackageManager.java、frameworks/base/core/java/android/content/pm/PackageInstaller.java
public static final int INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS = 0x00000100;
public static final int INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS = 0x00400000;
public static final int PERMISSION_STATE_DEFAULT = 0;
public static final int PERMISSION_STATE_GRANTED = 1;
public static final int PERMISSION_STATE_DENIED = 2;PERMISSION_STATE_* 是 session 对单个权限的请求,不是绕过保护级别的强制写入。INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS 让安装器请求把 Manifest 中所有权限交给权限服务处理;allowlist 标志则把 requested permissions 作为受限权限白名单候选。具体常量值以 Android 17 的 PackageManager.java 为准,不能沿用旧版本数字。
2. 参数载体
2.1 参数对象
源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
final class PackageInstalledParams {
public static final PackageInstalledParams DEFAULT = new Builder().build();
private final ArrayMap<String, Integer> mPermissionStates;
private final List<String> mAllowlistedRestrictedPermissions;
private final int mAutoRevokePermissionsMode;
PackageInstalledParams(ArrayMap<String, Integer> permissionStates,
List<String> allowlistedRestrictedPermissions,
int autoRevokePermissionsMode) {
mPermissionStates = permissionStates;
mAllowlistedRestrictedPermissions = allowlistedRestrictedPermissions;
mAutoRevokePermissionsMode = autoRevokePermissionsMode;
}
}这是安装流程与权限服务之间的窄接口。它不携带 APK 路径、session id 或调用 UID;这些信息已经在更早的校验阶段完成。使用 DEFAULT 的安装表示没有额外权限状态请求,权限服务仍会按包声明、签名和既有用户状态执行默认逻辑。
2.2 Builder 写入
final class Builder {
private ArrayMap<String, Integer> mPermissionStates;
private List<String> mAllowlistedRestrictedPermissions;
private int mAutoRevokePermissionsMode = MODE_DEFAULT;
Builder setPermissionStates(ArrayMap<String, Integer> states) {
mPermissionStates = states;
return this;
}
Builder setAllowlistedRestrictedPermissions(List<String> permissions) {
mAllowlistedRestrictedPermissions = permissions;
return this;
}
Builder setAutoRevokePermissionsMode(int mode) {
mAutoRevokePermissionsMode = mode;
return this;
}
PackageInstalledParams build() {
return new PackageInstalledParams(mPermissionStates,
mAllowlistedRestrictedPermissions,
mAutoRevokePermissionsMode);
}
}Builder 的 owner 是安装线程,构建完成后参数供权限服务读取。它不会自己检查权限是否存在、是否属于 restricted 或是否可授予;这些判断必须由 PermissionManagerService 结合当前包和用户完成。
3. Commit 构建
3.1 批量授予分支
源码文件:frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
final PermissionManagerServiceInternal.PackageInstalledParams.Builder builder =
new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
final boolean grantRequestedPermissions =
(installRequest.getInstallFlags()
& PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0;
if (grantRequestedPermissions) {
final ArrayMap<String, Integer> states = new ArrayMap<>();
for (String permissionName : pkg.getRequestedPermissions()) {
states.put(permissionName,
PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED);
}
builder.setPermissionStates(states);
} else {
final ArrayMap<String, Integer> states = installRequest.getPermissionStates();
if (states != null) {
builder.setPermissionStates(states);
}
}批量标志优先于 session 的逐权限 map:设置了批量授予时,InstallPackageHelper 会为所有 requested permissions 构造 GRANTED 请求;未设置时才传递 session 的显式状态。这里仍然只是输入,PermissionManagerService 可以因保护级别、签名、用户限制或权限不存在而拒绝实际授予。
3.2 受限权限
final boolean allowlistAllRestricted =
(installRequest.getInstallFlags()
& PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
final List<String> allowlisted = allowlistAllRestricted
? new ArrayList<>(pkg.getRequestedPermissions())
: installRequest.getAllowlistedRestrictedPermissions();
if (allowlisted != null) {
builder.setAllowlistedRestrictedPermissions(allowlisted);
}
builder.setAutoRevokePermissionsMode(
installRequest.getAutoRevokePermissionsMode());allowlist 标志把整个 requested list 交给权限服务作为候选;没有该标志时,只传安装器明确列出的 allowlist。该列表不会自动把普通权限变成 granted,也不会替代 privileged permission XML 的系统白名单。
4. 权限服务消费
4.1 内部接口
源码文件:frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
/**
* Callback when a package has been installed for a user.
*/
void onPackageInstalled(@NonNull AndroidPackage pkg,
int previousAppId,
@NonNull PackageInstalledParams params,
@UserIdInt int userId);previousAppId 只在包离开 shared UID 等场景提供旧 app id;普通安装使用 Process.INVALID_UID。userId 决定本次权限状态写入哪个用户,USER_ALL 由权限服务展开到所有适用用户。接口调用发生在包设置提交后,因此权限服务可以读取新的 AndroidPackage 和 PackageSetting。
4.2 调用顺序
源码文件:frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
mPm.mPermissionManager.onPackageInstalled(
pkg, installRequest.getPreviousAppId(),
permissionParamsBuilder.build(), UserHandle.USER_ALL);调用方是 InstallPackageHelper,消费者是 PermissionManagerService。前者负责把安装上下文翻译成权限参数,后者负责撤销已删除声明、继承可保留的旧 grant、授予 install 权限并更新 per-user 状态。调用返回不代表用户运行时权限 UI 已经弹出;它只完成安装阶段的权限初始化。
5. 首次安装与更新
5.1 首次安装
首次安装没有旧包权限状态可继承。权限服务依据 requested permissions、保护级别、签名和安装器传入的显式状态创建新的 uid permission state。normal/install 权限可能在安装阶段授予,dangerous 权限通常仍由运行时授权流程决定。
5.2 更新安装
更新安装传入旧包对象和 previousAppId,权限服务可以识别同一包的旧状态。Manifest 删除的权限会被撤销;仍存在且兼容的 grant 可以保留;新增 dangerous 权限不会因为更新自动绕过用户授权。更新时的权限继承因此依赖包名、签名、旧 app id 和用户状态,而不是仅比较 APK versionCode。
5.3 权限模型降级
安装前检查会拒绝把已支持运行时权限模型的包降级到旧 target SDK。错误码是 INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,失败发生在权限状态写入之前;因此不要把该错误和“某个 runtime permission 没有自动授予”混为一谈。
6. 失败边界
6.1 请求不可授予
PERMISSION_STATE_GRANTED 只是请求。权限不存在、声明方不匹配、签名不满足、restricted 权限没有 allowlist 或用户策略禁止时,PermissionManagerService 会拒绝或调整最终状态。安装可以成功完成,但某个权限保持 denied/default;调用方必须读取最终权限状态,而不能只检查 session 参数。
6.2 安装失败
如果 parse、签名、reconcile 或 commit 失败,InstallPackageHelper 不会把未提交的权限参数当成持久状态。失败清理回收 code path、App ID 和临时设置;已存在的旧包权限状态仍由旧 PackageSetting 持有。
7. 验证方法
7.1 显式状态
创建 session,对同一个 APK 分别设置 CAMERA 为 GRANTED、DENIED 和 DEFAULT,再 commit。安装完成后用 pm check-permission 或 dumpsys package 查看用户状态。关键断言是参数状态会进入权限服务,但最终结果仍受保护级别和用户策略约束;这个实验不能证明普通应用能授予 signature 权限。
7.2 更新继承
先安装请求一个 dangerous 权限的 v1,再更新到仍声明该权限的 v2,并删除另一个权限。断言仍声明且兼容的状态可能保留,已删除权限被撤销,新权限不会自动获得运行时授权。该实验覆盖更新路径,不覆盖 privileged allowlist。
7.3 受限权限
在具备相应安装权限的测试环境中,分别使用和不使用 INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS 安装声明 restricted permission 的 APK。比较 dumpsys package 的最终 flags 和 permission state,确认 allowlist 是输入条件而非无条件 grant。权限不足时预期安装器在参数检查或权限服务阶段失败。
8. 源码路线
PackageInstaller.SessionParams.setPermissionState:确认调用方如何表达逐权限请求。InstallRequest:查看 permission states、allowlisted permissions 和 auto-revoke mode 的携带方式。InstallPackageHelper提交段:跟踪批量授予与 allowlist 分支。PermissionManagerServiceInternal.PackageInstalledParams:理解安装器与权限服务的窄接口。PermissionManagerService.onPackageInstalled:跟踪声明校验、旧状态继承和 per-user 写入。- 权限模型降级检查:区分安装失败和权限最终为 denied。
安装权限处理的主线是“安装器提供请求,InstallPackageHelper 组织参数,PermissionManagerService 决定最终状态”。把这三层分开,才能解释为什么设置了 GRANTED 仍可能被拒绝,也能准确定位更新、受限权限和权限模型降级问题发生在哪个阶段。
