Appearance
08 PackageManagerService:安装、扫描与权限的档案馆
本页导读:一台 Android 上「装了什么、谁能装、装完能干什么」的终极答案都归档在 PackageManagerService(PMS)。本页从 APK 物理结构讲到扫描解析链、四大组件注册、运行时权限、安装会话(PackageInstaller)、dexopt 与 RRO overlay 机制。它是第 06 页所有组件调度的前置档案馆,也是 Android 11 之后被 Mainline 动刀最多的服务之一(第 12 页)。基线 Android 16(API 36)。
一、APK 解剖:PMS 眼里的包裹
| 部件 | 内容 | PMS 关注点 |
|---|---|---|
AndroidManifest.xml(二进制 AXML) | 组件、权限、feature、split 信息 | 解析的核心,产出 AndroidPackage |
classes*.dex | 字节码 | dexopt 对象(第七节) |
resources.arsc | 资源表 | 资源 id 与配置解析 |
lib/<abi>/*.so | native 库 | ABI 匹配、安装解压策略 |
META-INF / 签名块 | v1/v2/v3/v4 签名 | 身份与完整性校验 |
| split APK(config/feature/locale) | 动态交付切片 | 以 splitName 归组安装 |
assets/、根目录文件 | 业务资源 | PMS 不解释 |
签名版本速记:v1 是 JAR 签名(只护 entry 清单),v2/v3 护整个文件(APK Signing Block;v3 加密钥轮换),v4 是 Merkle 树支撑流式/增量安装(Android 11+)。验签失败在安装阶段直接拒,报 INSTALL_PARSE_FAILED_NO_CERTIFICATES 类错误码。
格式小知识:Manifest 进包时已被编译成 AXML 二进制(零字符串表开销、mmap 友好),PMS 解析走 Resources.parseXml 一族;resources.arsc 同理是二进制资源表——这就是为什么「反编译看 Manifest」永远比运行时解析慢,也解释了 PMS 解析吞吐为何能扛住数百包扫描。
二、扫描:开机时 PMS 在读什么
java
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java(示意骨架)
// 构造期:读 /data/system 下的持久化状态 → 比对分区包集合 → 需要时重扫描
// Android 11+ 解析链:ParsedPackageUtils/ParsingPackageUtils 产出 ParsedPackage
// 状态落盘:/data/system/packages.xml(及包列表缓存;文件集与格式以 AOSP 当前版本为准)要点:
- 扫描对象:
/system(/system_ext,/product,/vendor...)预置分区、/apex(APEX 内清单,第 12 页)、/data/app用户安装; - 首开全扫、后续开机读缓存快照(这也是首开慢的一大项,呼应第 01 页);
- 安装/卸载/替换会触发增量扫描:解析目标 APK 更新内存档案 + 重写状态文件;
- 解析产物是
AndroidPackage(实现类ParsedPackage),它替代了老PackageParser.Package,为 Mainline 化提供稳定中间表示(API 30 起解析链重写)。
扫描的工程细节还有两处:
- APEX 目录同样在扫描范围内,但模块内 APK 走
ApexManager专线注册(第 12 页),不进普通安装会话; - 多用户语义:包「安装」是设备级,「启用/停用/可见」按用户位图管理——
pm disable-user与卸载的区别正在这里,状态文件里每个用户有自己的启用记录。
三、四大组件注册与 Intent 解析
Manifest 解析出的 Activity/Service/Provider/Receiver 条目进 ComponentResolver(IntentResolver 家族),运行时按三类信息匹配:action + category + data(mimeType/scheme) 与权限门。
queryIntentActivities这类查询走的是同一套解析器,Android 11(API 30)引入包可见性:默认只能「看见」声明了<queries>/有交互关系的包,QUERY_ALL_PACKAGES需理由——第 06 页的解析从此带上隐私滤镜;- 组件级安全在解析处生效:
exported(Android 12 起 targetSdk31 组件必须显式声明)、permission属性、enforcePermission; - persistent 包、default home/IME 等「钦定包」由 PMS 特殊标记,影响第 06 页进程档次与开机编排。
Intent 匹配的内部次序值得了解:先按 action 建索引粗筛,再 category 全含校验(默认自动加 CATEGORY_DEFAULT),然后 data 做 scheme/mimeType 精确匹配与通配展开(mimeType 的 image/* 展开在解析注册时就完成),最后按优先级/顺序/历史统计排序。dumpsys package r -a <ACTION> 可以直接问解析器「谁能接这个 Intent」。
四、权限体系:三层漏斗
PMS(配合 PermissionManagerService,API 30 起独立为 Mainline 服务)按三条时间线发权限:
- 安装期:普通权限装即得;系统类权限看平台签名/
privileged分区与privapp-permissionsallowlist(/system/etc/permissions/*.xml、OEM allowlist); - 运行期:runtime 权限弹窗(
RequestPermissionsActivity,归属 permission controller Mainline 模块),授予状态按 uid 记录(Android 14 起部分授予语义ACCESS_FINE|COARSE三态); - 动作期:AppOpsService 再管一层「权限允许但行为要记帐」(定位后台模式、剪贴板读取、相册部分访问)。
补充三个工程级细节:一次性授权与「拒绝两次再拒」逻辑是 API 30 起;自动重置未使用权限(API 30+)会清运行时授权;权限组语义在 API 30 后被拆薄,UI 与授权粒度对齐到「权限」本身。
三件顺手工具:pm grant/revoke <pkg> <perm> 调试期直改授权;appops set 与 dumpsys appops 看动作层记帐;dumpsys package 里同一权限会同时出现 granted 位与 appops 模式,两层不一致时行为以 appops 为准——「授权了却拿不到定位」多半卡在动作层。
五、安装会话:PackageInstaller 的流水线
text
应用/商店/adb(adb install 也是走这套)
→ PackageInstaller.createSession(或 openSession)
→ 写入 apk/split(stage,可流式/增量,v4 签名支持逐块校验)
→ commit → PackageInstallerService 校验链:
验签 → 解析(第二节链)→ 版本/降级/签名一致性 → 磁盘配额
→ 安装决策(是否 staged:OTA/APEX 场景延后生效)
→ 提交事务(VoldStageQueueService 与 installd 协同):
落 /data/app、写 /data/system 状态、DexOptManager 排队 dexopt
→ 回调会话状态;完成后广播 PACKAGE_ADDED/REPLACED- 「install-flinger」是早期昵称,现对应
PackageInstallerService(services/core/java/com/android/server/pm/PackageInstallerService.java)+ 会话状态机; - staged session 同时是 APEX 升级通道(第 12 页),
update_engine把 payload 交给它暂存; - 卸载可带
DELETE_KEEP_DATA;「替换安装失败回滚」由会话事务保证,adb install -r就是 replace 语义。
会话的三个入口也要分清:adb install 走 PackageInstaller 会话(脚本化友好);pm install-create-session 是裸会话原语;cmd package install-existing 直接对已落盘 APK 发起安装事务(root/系统应用工具用)。自动化测试优先用官方 PackageInstaller API,行为最接近用户安装。
顺带记住磁盘账:安装需要 /data 余量(预留阈值随版本有变,AOSP 为准),INSTALL_FAILED_INSUFFICIENT_STORAGE 时先 df /data 再怀疑包本身。
六、dexopt:装完为什么要「优化中」
安装事务里 ART 编译任务被排入 DexOptHelper/后台 Job:
- 分级:verify(只校验)、speed-profile(AOT 热点,出厂预装默认)、speed(全量 AOT,安装时常见)、optimize 依赖 profile 指导;
- 执行者是
BackgroundDexOptService/install-time dexopt(Android 10 起安装期同步 dexopt 有预算上限,防止「装 200 个应用」卡死开机,以 AOSP 为准); - 编译器随 ART 在 Mainline APEX 里(第 12 页):
dex2oat产物在/data/oat、/data/dalvik-cache;profile 文件在/data/misc/profiles(ART 按运行热度持续回填,形成「越用越顺」的闭环); - 查看:
adb shell dumpsys package dexopt按包列出编译状态与 reason;reason 字段是「它为什么被编译」的审计线索(安装/升级/背景 profile 收集/bg-dexopt 周期任务)。
七、RRO overlay:不改目标包的资源换皮
Runtime Resource Overlay 允许在不改目标 APK、不重签名的前提下覆盖资源:
- overlay APK 声明
RRO targetPackage/targetId + <overlay priority>,放在/product/overlay、/vendor/overlay等扫描路径; OverlayManagerService维护启用集合,资源查找时按优先级链合成进目标包的Resource路径(对应用透明);- 典型用户:OEM 主题/品牌定制、AOSP 组件配置覆盖(framework-res 换配置);应用开发者拿不到启用权,这是平台/OEM 机制;
- 与「动态加载外部 APK 资源(
AssetManager.addAssetPath黑魔法)」的区别:RRO 是受控、可审计、按用户/配置生效的正规军。
生命周期一句话:开机扫描 overlay 目录→注册进 OverlayManagerService→按启用策略(含用户设置 Settings.Secure.overlay_devices 类键,具体以 AOSP 为准)合成进目标包的资源路径链;换肤/主题应用本质是在请求系统替你启用一组 RRO。
八、实战:dumpsys package 的三段式用法
bash
adb shell dumpsys package com.xxx.yyy # 档案全量:版本/权限/组件/split/签名
adb shell dumpsys package r # 按 Intent 正则试解析(r = resolver)
adb shell dumpsys package dexopt # 编译状态
adb shell pm list packages -f -3 # 第三方包列表(pm 子命令以 AOSP 为准)三段式之外,-3 看第三方、-s 看系统、-d 看被禁用,组合 pm 的 list 子命令基本覆盖日常盘点。
排障对照:
| 症状 | 高概率原因 | 线索 |
|---|---|---|
| INSTALL_FAILED_UPDATE_INCOMPATIBLE | 签名不一致(换 keystore) | dumpsys package 的 signatures 段比对 |
| INSTALL_FAILED_VERSION_DOWNGRADE | versionCode 回退 | 同上 |
| 装成功但组件 404 | split 未安装/可见性过滤 | pm path、<queries> |
| 权限弹窗不出现 | 未声明/被 allowlist 拒/组策略 | dumpsys package 的 granted/runtime 段 |
| 「解析软件包时发生错误」 | minSdk/ABI/签名块/增量依赖缺失 | PackageInstaller 错误码与 logcat |
| 卸载后数据残留 | DELETE_KEEP_DATA 语义 | /data/data 目录 + pm install -r 语义 |
最后一个高频坑:adb install 成功但应用行为像旧版——多用户/工作资料下安装只作用于当前用户可见性,或 split APK 只推了 base;pm path 数一下 split 条数即可定案。
九、模块化时代的 PMS 版图
Android 11 起 PMS 不是一座堡垒而是一片城区:
| 能力 | 现居处 | 模块形态 |
|---|---|---|
| 解析与包存储设置 | pkg 方向模块(AOSP 推进中,边界以其为准) | APEX / jar |
| 权限与 AppOps | PermissionManagerService | Mainline(permission 模块) |
| 权限请求 UI | Permission Controller | Mainline 应用 |
| 角色与默认应用 | RoleManager | Mainline(role 模块) |
| 安装会话 | 仍在 PMS(system_server) | 平台内 |
读 PMS 代码的现实提醒:同一功能可能「平台里留了壳、逻辑在模块里」,dumpsys package 与 dumpsys permission 要对着看;OEM 定制若只改平台壳不更模块,会出现版本错配类疑难杂症(第 12 页 VINTF 同族问题)。
十、命令行小抄
bash
pm path <pkg> # APK 落盘路径(split 会列多条)
pm dump <pkg> | head # 等价 dumpsys package 前段
pm compile <pkg> speed # 手动触发指定编译模式(以 am/cmd package 实现为准)
pm verify <session-id> # 会话预校验(不提交)
pm install-create-session # 裸会话原语,脚本化安装第一步
cmd overlay list # RRO 启用清单(OEM 设备常有裁剪)
cmd appops get <pkg> # 动作层记帐快照以上子命令在不同 AOSP 版本间有增删,遇到 Unknown command 先查 pm 的帮助输出(pm 无参运行会打印支持列表)。
十一、版本注记
- Android 6(API 23):运行时权限登场,PMS 开始「分阶段发权」。
- Android 5(API 21):ART 取代 Dalvik,dexopt 语义换代,为后来的 profile 编译体系奠基。
- Android 8~9(API 26~28):v2/v3 签名;
REQUEST_INSTALL_PACKAGES收紧;安装未知来源改为「按来源 App 授权」。 - Android 10(API 29):安装期 dexopt 预算;staged session 承接 APEX。
- Android 11(API 30):解析链重写(ParsedPackage)、包可见性、一次性/自动重置权限、PermissionManagerService 入 Mainline、增量安装落地。
- Android 12~14(API 31~34):exported 显式强制、部分授予、权限 UI 大改;
PackageManager查询 API 继续向可见性倾斜。 - Android 15~16(API 35~36):包状态存储继续向 pkg Mainline 模块迁移(
com.android.pkg方向,模块边界以 AOSP 为准);APK v4 与流式安装进一步常态化。
本页小结
本页小结:PMS 的四件事可以背下来——扫(分区与 data 的档案化)、解(Manifest 到组件表)、发(三层权限漏斗)、装(会话化事务 + dexopt)。RRO 是平台换皮的正道,不是应用的黑魔法。装不上的问题看错误码与验签,跑不起来的问题回到第 06 页的解析与可见性;权限“给了却不通”再下探 appops。
参考
- 运行时权限指南:developer.android.com/training/permissions/request-permissions
- PackageManager 参考:developer.android.com/reference/android/content/pm/PackageManager
- PackageManagerService 源码:cs.android.com/android/platform/frameworks/base/+/main/services/core/java/com/android/server/pm/PackageManagerService.java
- 包可见性说明:developer.android.com/guide/packages/package-visibility
- 应用签名官方说明:developer.android.com/studio/publish/app-signing