PMS 启动与扫描:开机如何重建包清单
2026/8/9大约 4 分钟PMS 专题Android 14PMS包扫描PackageManager
PMS 启动与扫描:开机如何重建包清单
上一章建立了包生命周期主链。这一章进入第一段,回答:SystemServer 何时创建 PMS, 开机扫描哪些目录,packages.xml 怎么被加载?
PMS 启动不是单纯反序列化 packages.xml。它要读取既有设置,再扫描 system、product、 vendor、data 等分区中的包,用磁盘现状和持久化状态共同重建内存包表。
启动时要同时核对磁盘与持久化状态
| 常见误解 | 正确理解 |
|---|---|
| 开机后 PMS 直接读 packages.xml 就完事 | 它先扫描所有 APK 目录,用解析结果重建包表,xml 只是辅助恢复状态 |
| 所有包都在 /data/app | 系统包分布在 system、product、vendor、odm 等只读分区 |
| 扫描一次就好 | 每次开机都要扫描;安装/更新也会触发增量扫描 |
核心结论
- PMS 在 SystemServer 的引导服务阶段创建,早于 AMS/WMS 对包的查询需求。
- 扫描目录分两类:只读系统分区(system/framework、system/app、system/priv-app、 product、vendor、odm)与可写用户分区(/data/app)。
- 每个 APK 被解析成 Package 对象,组件、权限、签名信息进入内存表。
- 扫描结果持久化到
/data/system/packages.xml、packages.list等文件。 - 后续开机以“扫描 + 恢复状态”两步完成,而不是直接反序列化 xml。
启动与扫描主链
逐步解释:
- 创建 PMS:SystemServer 调用 PMS 构造函数,PMS 开始准备扫描器与目录清单。
- 扫描系统分区:遍历 framework、system、priv-app、product、vendor、odm 下的 APK。
- 扫描用户分区:遍历
/data/app下已安装的应用。 - 恢复状态:读取
packages.xml恢复用户数据、禁用状态、上次安装元数据。 - 就绪:包表与组件表就绪后,其他服务才能按包名查询与启动组件。
为什么要“扫描优先于读 xml”
APK 本身携带权威信息:组件、权限、签名都以 APK 内容为准。xml 只是缓存上次的用户态决策 (如权限授予、禁用状态)。如果直接读 xml 而不扫描,APK 更新、签名变化、文件损坏都无法 被发现。所以每次开机都以扫描结果重建内存模型,再叠加 xml 里的用户态状态。
源码证据
阅读目标:确认扫描入口与目录集合。
正文指针:PackageManagerService.java 构造函数与 scanDirTracedLI(); SystemServer.java 中 PMS 的创建位置。
// PackageManagerService.java(伪代码,行号以 r75 为准)
PackageManagerService(Context context, ...) {
// 构造扫描器,准备各分区目录
}
void scanDirTracedLI(File scanDir, ...) {
// 遍历目录下 APK,逐个解析并登记
}这段代码证明: 扫描发生在 PMS 构造阶段;scanDirTracedLI() 是“按目录扫描”的统一 入口,系统分区与 /data/app 都走同一条扫描逻辑。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell pm list packages
adb shell ls -l /data/app/ 2>/dev/null || adb shell su 0 ls -l /data/app/
adb shell dumpsys packagepm list packages 确认扫描结果;/data/app 查看用户包目录;dumpsys package 看内存 中的包表。开机后某应用“找不到”,优先确认它是否出现在扫描结果里,再排查是解析失败还是 目录/权限问题。
常见误区
- “PMS 启动就是读 packages.xml”:扫描为主,xml 只是恢复状态。
- “所有包都在 /data/app”:系统包分布在多个只读分区。
- “扫描只发生在开机”:安装、更新、分区挂载变化都会触发扫描。
- “扫描失败只是日志”:解析失败的 APK 不会进入包表,表现为“找不到应用”。
延伸问题
- framework-res.apk 等系统包在扫描中承担什么角色?
- 首次开机与后续开机的扫描开销为什么不同?
- 动态分区(system/vendor/product 合并)对扫描目录有什么影响?
- 扫描时如何保证并发与一致性(PMS 锁)?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
SystemServer.java | PMS 创建调用 | 引导阶段创建服务 |
PackageManagerService.java | 构造函数 / scanDirTracedLI() | 准备与扫描 |
packages.xml | /data/system/ | 用户态状态持久化 |
PackageManagerShellCommand.java | pm list packages | 命令行查询入口 |
公共路径:frameworks/base/services/core/java/com/android/server/pm/。行号以 r75 检索为准。
单个 APK 如何生成包与组件描述,见 APK 解析。