2. Android系统架构与PackageManager定位
要理解PackageManagerService(下文简称PMS)在Android系统中的位置,必须先建立一张“系统分层地图”。Android并不是一个单体进程,而是由内核、原生库、运行时、系统服务框架和应用层共同构成的纵向栈式架构。PMS恰好位于系统服务框架层,是应用包世界的“户籍管理者”和“准入裁判”。
一、系统服务分层:PMS站在哪一层
Android系统自上而下大致可分为五层,每一层承担不同职责,并通过明确的接口向下依赖、向上暴露能力:
- 应用层(App Layer):普通APK、系统应用、Launcher、Settings等,通过Context API调用系统能力。
- 应用框架层(Java API Framework):ActivityManager、PackageManager、WindowManager等Java服务接口,是应用开发者直接接触的API。
- 系统服务层(System Services):运行在system_server进程中的核心服务,包括AMS、PMS、WMS、IMS等,是系统真正的“大脑”。
- 原生库与运行时(Native Libraries & ART):libc、binder、skia、ART虚拟机等,为上层提供底层能力。
- Linux内核层(Kernel):进程调度、内存管理、Binder驱动、文件系统等。
PMS属于系统服务层,但它与内核层的Binder驱动、原生库层的libbinder、框架层的PackageManager API都有直接或间接的交互。它既不是纯Java服务,也不是纯Native服务,而是“Java服务 + Native支撑”的典型代表。
二、Binder通信:PMS如何被跨进程访问
PMS运行在system_server进程中,而应用进程、其他系统服务进程都需要访问它。这种跨进程访问依赖Binder机制。Binder通信的核心角色包括:
- Binder驱动:位于内核层,负责进程间数据传递和线程调度。
- ServiceManager:Native层服务注册中心,PMS通过它注册为“package”服务。
- Binder代理(Proxy):客户端持有的远程接口,调用时自动打包参数并发送到服务端。
- Binder实体(Stub):服务端实现,接收请求并执行实际逻辑。
应用调用getPackageManager()时,实际拿到的是ApplicationPackageManager,它内部持有一个IPackageManager的Binder代理。当应用调用getPackageInfo()时,请求会经过Binder驱动,最终到达system_server中的PMS实体,由PMS完成查询并返回结果。
// 应用侧调用链示意
Context.getPackageManager()
→ ApplicationPackageManager
→ IPackageManager.Stub.Proxy
→ Binder驱动
→ system_server中的PMS
→ PackageManagerService.getPackageInfo()
→ 返回PackageInfo
三、PackageManagerService在系统启动中的角色
PMS并不是在系统启动完成后才“按需创建”的,而是在system_server启动阶段就被初始化。它的启动过程大致分为以下几个关键阶段:
- SystemServer启动:Zygote孵化出system_server进程,进入SystemServer.main()。
- 启动Bootstrap服务:包括ActivityManagerService、PowerManagerService等。
- 启动Core服务:PMS在此阶段被创建,开始扫描系统目录。
- 扫描已安装包:PMS遍历/system/framework、/system/priv-app、/data/app等目录,解析AndroidManifest.xml。
- 建立包索引:生成PackageSetting、SharedUserSetting、权限映射等内部数据结构。
- 注册Binder服务:PMS将自身注册到ServiceManager,服务名为“package”。
- 进入就绪状态:PMS完成扫描后,其他服务和应用才能正常查询包信息。
如果PMS启动失败或扫描异常,系统可能卡在开机动画,甚至无法进入Launcher。因此PMS是系统启动的关键路径服务之一。
四、PMS与其他核心服务的关系
PMS并非孤立存在,它与多个系统服务存在强耦合关系。下表列出主要协作对象及其交互内容:
| 协作服务 | 交互内容 | 典型场景 |
|---|---|---|
| ActivityManagerService | 获取应用组件信息、权限校验 | 启动Activity时校验包是否存在 |
| WindowManagerService | 获取应用主题、屏幕适配信息 | 窗口创建时读取应用配置 |
| PermissionManagerService | 权限定义、权限授予状态 | 运行时权限申请与校验 |
| Installd | APK安装、 dex优化、目录创建 | 应用安装与卸载 |
| ServiceManager | Binder服务注册与查询 | 客户端获取PMS代理 |
五、核心原理:PMS的“数据中枢”定位
PMS维护着整个系统中所有已安装包的元数据,包括包名、版本号、签名、权限、组件列表、安装位置、UID等。这些数据在系统启动时被扫描并缓存,后续查询大多走内存索引,只有安装、卸载、更新等操作才会触发磁盘写入和重新扫描。
从数据流角度看,PMS是“磁盘 → 内存 → Binder接口”的三级结构:
- 磁盘层:APK文件、packages.xml、packages.list等持久化数据。
- 内存层:PackageSetting、PackageParser.Package、ArrayMap索引等运行时结构。
- 接口层:IPackageManager定义的AIDL接口,供跨进程调用。
六、案例场景:应用启动时的PMS参与
以点击Launcher图标启动一个应用为例,PMS在其中的参与如下:
- Launcher通过PackageManager查询已安装应用列表,PMS返回ResolveInfo。
- 用户点击图标,Launcher调用startActivity,请求进入AMS。
- AMS向PMS查询该Intent对应的Activity信息,确认组件存在且导出属性合法。
- AMS检查权限,必要时通过PMS获取权限定义。
- AMS创建进程,最终加载APK并启动Activity。
可以看到,PMS并不直接启动应用,但它为AMS提供了“这个包能不能启动、由谁启动、需要什么权限”的决策依据。
七、常见误区与复盘
复盘来看,掌握PMS定位的关键在于三点:第一,明确它在系统分层中的位置;第二,理解Binder如何把客户端请求送到PMS;第三,清楚它在系统启动中的初始化时序。这三点构成了后续所有PMS定制工作的基础坐标系。