PackageManagerService(PKMS)是 Android 系统中负责应用包管理的核心服务。从 APK 的扫描解析、安装卸载,到权限管理、组件解析、共享 UID 管理,PKMS 是整个应用生态的底座。本文基于 Android 11 AOSP 源码,深入分析 PKMS 的启动流程、APK 扫描管线、安装流程、权限模型和关键数据结构。
一、PKMS 的体系定位
PKMS 运行在 system_server 进程中,是引导服务(Bootstrap Service)之一,在 SystemServer 的 startBootstrapServices 阶段被创建,早于 AMS 和 WMS。
SystemServer.startBootstrapServices() |
AOSP 核心路径:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/Settings.javaframeworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
二、PKMS 启动流程与扫描管线
2.1 SystemServer 中启动 PKMS
// frameworks/base/services/java/com/android/server/SystemServer.java |
2.2 PKMS 构造函数——扫描管线
PKMS 的构造函数是理解 APK 扫描的核心入口。在 Android 11 中,扫描流程大致分为以下几个阶段:
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java |
2.3 scanDirTracedLI——目录扫描
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java |
ParallelPackageParser 的设计:解析阶段并行(多个 APK 同时解析 AndroidManifest),但注册阶段串行(按顺序调用 scanPackageChildLI)。这是因为注册阶段涉及 Settings 的写操作(插入/更新 PackageSetting),必须保证线程安全。
2.4 PackageParser2——APK 解析器
Android 11 用 PackageParser2 替代了 PackageParser,核心改进是使用了 TypedKeyValue 和增量解析特性:
// frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java |
2.5 scanPackageChildLI——深度扫描与登记
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java |
三、APK 安装流程
3.1 安装入口:PackageInstaller Session
APK 安装可以通过多种方式触发:PackageInstaller(系统安装器 UI)、adb install、Google Play 等。所有方式最终都通过 PackageInstallerService 的 Session 机制实现。
// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java |
3.2 安装的执行阶段
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java |
3.3 dexopt 触发
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java |
四、Settings 与 packages.xml
4.1 Settings 类
Settings 是 PKMS 的持久化配置管理类,管理所有已安装包的状态信息:
// frameworks/base/services/core/java/com/android/server/pm/Settings.java |
4.2 packages.xml 内容示例
packages.xml 位于 /data/system/packages.xml:
<package name="com.example.app" codePath="/data/app/com.example.app-xxx" |
五、权限管理
5.1 权限类型
| 权限级别 | 说明 | 授予方式 |
|---|---|---|
| NORMAL | 低风险权限 | 安装时自动授予 |
| DANGEROUS | 涉及隐私/安全 | 运行时请求用户授权 |
| SIGNATURE | 系统级权限 | 签名匹配自动授予 |
| SIGNATURE_OR_SYSTEM | 系统或同签名应用 | 签名匹配自动授予 |
5.2 权限授予逻辑
// frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java |
六、组件解析(Component Resolution)
当应用通过 PackageManager.queryIntentActivities() 查询能处理某个 Intent 的 Activity 时,PKMS 通过 ComponentResolver 高效地进行组件匹配。
// frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java |
根 IntentResolver 的匹配逻辑:
- 匹配 Action(如果 Intent 指定了 action)
- 匹配 Category(所有 category 都要匹配——“ALL” 语义)
- 匹配 Data(URI scheme、host、path、mimeType)
- 按优先级排序(priority 值和 preferred activity 记录)
七、核心面试题
Q1:PKMS 如何实现应用间共享 UID?它的安全风险是什么?
PKMS 通过 SharedUserSetting 管理共享 UID。当多个 APK 声明相同的 android:sharedUserId 且使用相同的签名时,它们会被分配到相同的 Linux UID,从而可以相互访问对方的文件。风险:如果一个共享 UID 的应用存在安全漏洞,同 UID 的所有应用的数据都可能被利用。Android 11+ 进一步收紧了 sharedUserId 的使用。
Q2:PKMS 中的 packages.xml 和 packages.list 分别存储什么信息?
packages.xml 存储所有已安装应用的完整元数据:包名、代码路径、native 库路径、签名证书、授予的权限、SharedUserId 信息等。packages.list 以简洁格式存储包名和 UID 映射关系:<pkgName> <uid> <dataDir>,供 installd 和 lmkd 快速查询。
Q3:Android 11 中 PermissionManagerService 为什么从 PKMS 中独立出来?
(1) 权限检查是高频操作,独立成单独服务后可以更好地优化;(2) 分离权限管理代码使得代码边界更清晰,便于安全审计;(3) 为未来的权限模型演进(如 Scoped Storage、One-Time Permissions、App Hibernation)提供更灵活的基础。
Q4:ParallelPackageParser 如何保证解析效率的同时又保证注册的安全?
解析阶段并行(多个线程同时解析 APK 的 AndroidManifest.xml — CPU 密集型),但注册阶段串行(通过 parallelPackageParser.take() 按序获取结果并调用 scanPackageChildLI)。这样解析效率由多核并行加速,而注册的 Settings 写操作保持单线程安全,避免了锁竞争。
Q5:PKMS 如何处理 APK 更新的签名校验?
PKMS 在 scanPackageChildLI 中调用 mSettings.isSignatureMatch() 比较新旧 APK 的签名。更新要求新签名与已安装的签名一致(除非是系统应用升级且系统签名允许覆盖)。对于使用 sharedUserId 的应用,新签名还必须与 sharedUser 中其他应用的签名一致。签名校验使用公钥比较,不是简单的证书指纹比较。
6.5 Split APK 与 App Bundle 的处理
Google Play 的 App Bundle 将 APK 拆分为 base module 和多个 feature module。PKMS 需要处理 split APK 的安装:
// PackageManagerService.java |
每个 split APK 有自己的 AndroidManifest.xml,但其 package 属性必须与 base APK 一致。PKMS 在扫描时合并所有 split 的组件声明到同一个 Package 对象中。
6.6 Instant Apps 的支持
Android Instant Apps 允许用户在不安装完整 APK 的情况下试用应用:
// PackageManagerService.java |
PKMS 通过 isInstantApp(packageName, userId) 判断是否为 Instant App,并在权限授权、组件查询时施加限制。
6.7 APK 签名方案演进
Android 支持三种签名方案:
| 方案 | 引入版本 | 签名方式 | 特点 |
|---|---|---|---|
| V1 (JAR) | Android 1.0 | 对 APK 内每个文件签名 | 最兼容,但验证慢 |
| V2 (APK Signature) | Android 7.0 | 对整个 APK 签名 | 验证快,保护 APK 完整性 |
| V3 (APK Signature) | Android 9.0 | 支持签名密钥轮换 | 允许更换签名密钥而不丢失更新能力 |
PKMS 在安装时验证签名方案:
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java |
6.8 PKMS 的性能优化策略
8.1 Settings 的读写优化
packages.xml 的读写是 PKMS 启动中的主要耗时操作之一(尤其是在安装了数百个应用后)。优化策略:
- 增量写入:
Settings.writeLPr()不是每次都全量覆写。正常情况下使用writePendingPackagesLPw()只写入有变更的包。 - 异步写入:写入操作在
mPmsBgHandler(后台线程)上执行,不阻塞主线程。 - 二进制缓存:Android 11 引入
packages.xml.bin(二进制格式的缓存),在下一次启动时优先从 bin 读取,解析速度比 XML 快 3-5 倍。
8.2 ComponentResolver 的查询优化
ComponentResolver 使用多层索引加速 Intent 匹配:
// ComponentResolver.java 内部数据结构 |
查询结果缓存:PackageManager.queryIntentActivities() 的结果会缓存一段时间(通过 PackageManagerService.snapshot() 机制)。
8.3 Storage 空间管理
PKMS 监控 /data 分区空间:
// PackageManagerService.java |
AOSP 核心路径参考:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/Settings.javaframeworks/base/services/core/java/com/android/server/pm/ComponentResolver.javaframeworks/base/services/core/java/com/android/server/pm/PackageInstallerService.javaframeworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.javaframeworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
参考总结
PKMS 是 Android 系统中代码量最大(约 3 万行+)的系统服务之一。它承载了包管理、权限、组件解析三大职责。理解 PKMS 不仅是面试的需要,更是深入理解 Android 应用生命周期、安全模型和组件交互的基础。
关键设计理念:
- 分阶段扫描:先解析(并行)再注册(串行),在速度和正确性间平衡
- 持久化优先:所有包信息先写入 packages.xml 再通知其他服务——确保崩溃恢复时数据完整
- 权限分离:Android 11 将权限管理从 PKMS 分离,体现了单一职责原则
- 兼容性包袱:PKMS 必须支持从 Android 1.0 至今的所有签名方案(V1-V3)和安装模式,这是它代码量大的原因之一

