2. 系统架构总览:PMS在SystemServer中的启动流程,与AMS、WMS等核心服务的关系
各位同学,今天我们来聊聊PMS在SystemServer里的启动流程。说白了,就是Android系统开机时,Package Manager Service是怎么被唤醒的。我个人习惯把SystemServer比作Android的“大脑中枢”,而PMS、AMS、WMS这些核心服务,就是大脑里不同的功能区。
2.1 SystemServer的启动:一切从这里开始
Android系统启动后,Zygote进程会fork出SystemServer进程。SystemServer的main方法,就是整个服务的入口。嗯,这里要注意,SystemServer的启动顺序是有讲究的,不是一股脑全启动。
// 简化后的SystemServer.main()
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
// 1. 准备主线程Looper
Looper.prepareMainLooper();
// 2. 加载系统库
System.loadLibrary("android_servers");
// 3. 创建系统上下文
createSystemContext();
// 4. 启动核心服务
startBootstrapServices(); // 引导服务
startCoreServices(); // 核心服务
startOtherServices(); // 其他服务
// 5. 进入消息循环
Looper.loop();
}
你看,启动过程分了三步走。引导服务、核心服务、其他服务。PMS属于哪一类?它属于引导服务,启动优先级非常高。为什么?因为AMS、WMS这些服务,都需要PMS提供应用信息才能正常工作。
2.2 PMS的启动流程:从startBootstrapServices开始
在startBootstrapServices方法里,PMS的启动大致是这样的:
private void startBootstrapServices() {
// 1. 先启动Installer服务(用于安装/卸载应用)
Installer installer = new Installer(context);
installer.start();
// 2. 启动DeviceIdentifiersPolicyService
// ... 省略其他引导服务
// 3. 启动PMS
mPackageManagerService = PackageManagerService.main(context, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
// 4. 将PMS注册到ServiceManager
ServiceManager.addService("package", mPackageManagerService);
// 5. 启动AMS(注意:AMS需要PMS已经就绪)
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
context, mSystemContext, mPackageManagerService);
}
这里有个关键点:PMS的main方法是静态的,它内部会创建PackageManagerService实例,并完成初始化。初始化过程中,PMS会扫描所有已安装的应用,解析AndroidManifest.xml,构建内部数据结构。
核心逻辑:PMS启动时,会扫描以下目录:
/system/framework— 系统框架包/system/app— 系统预装应用/vendor/app— 厂商预装应用/data/app— 用户安装的应用
我曾经在项目中遇到过一个问题:某款手机开机特别慢,一查发现是PMS扫描/data/app目录时,有个损坏的APK导致解析卡住了。后来我们在PMS里加了超时机制和异常处理,才解决了这个问题。
2.3 PMS与AMS的关系:你中有我,我中有你
AMS(ActivityManagerService)和PMS的关系,可以说是Android系统里最紧密的一对。AMS负责管理Activity的生命周期、进程调度、任务栈等。但AMS要启动一个Activity,它得知道这个Activity属于哪个包,这个包有没有安装,权限够不够——这些信息都得问PMS。
举个例子:
// AMS中启动Activity时,会调用PMS查询信息
public int startActivityLocked(...) {
// 1. 通过PMS获取目标Activity的信息
ActivityInfo ai = mPackageManagerService.getActivityInfo(
intent.getComponent(), 0, userId);
// 2. 检查权限
int permission = mPackageManagerService.checkPermission(
"android.permission.xxx", callingPid, callingUid);
// 3. 检查应用是否已安装
if (ai == null) {
throw new ActivityNotFoundException(...);
}
// 4. 继续后续流程...
}
说白了,AMS是“前台指挥官”,负责调度和展示;PMS是“后勤部长”,负责提供应用元数据和权限校验。两者缺一不可。
2.4 PMS与WMS的关系:窗口背后的包信息
WMS(WindowManagerService)管理窗口的创建、布局、动画等。WMS也需要PMS的信息。你想想看,当一个应用要弹出一个窗口,WMS需要知道这个窗口属于哪个包,这个包有没有SYSTEM_ALERT_WINDOW权限——这些都得问PMS。
| 服务 | 对PMS的依赖 | 典型场景 |
|---|---|---|
| AMS | 高 | 启动Activity、检查权限、查询应用信息 |
| WMS | 中 | 窗口权限校验、应用包名获取 |
| 其他服务 | 低到中 | 通知服务、内容提供者等 |
避坑指南:我曾经在调试一个悬浮窗权限问题时,发现WMS报错说“Permission denied for window type”。查了半天,原来是PMS里存储的权限状态和实际运行时不一致。后来我建议团队在PMS初始化完成后,主动通知WMS刷新权限缓存。这个改动虽然小,但解决了线上不少问题。
2.5 整体架构图:一张图看懂PMS在SystemServer中的位置
下面我用一张SVG图来展示PMS在SystemServer中的启动流程,以及它和AMS、WMS的关系。这张图我画了好几次才满意,希望能帮你建立整体认知。
2.6 启动顺序的坑:为什么PMS必须先于AMS启动?
你可能会问:为什么PMS必须在AMS之前启动?原因很简单——AMS在初始化时,需要读取已安装应用的列表,构建进程管理的基础数据。如果PMS还没准备好,AMS拿不到这些信息,系统就没法正常启动。
我记得有一次调试一个系统启动崩溃的问题,日志显示AMS在初始化时抛出了NullPointerException。追查下去,发现是因为PMS扫描过程中遇到了一个格式异常的APK,导致PMS初始化失败。AMS拿不到PackageManager的引用,直接崩溃了。后来我们在PMS和AMS之间加了一个状态同步机制:PMS初始化完成后,会通过回调通知AMS。这样即使PMS初始化慢一点,AMS也能优雅等待。
注意事项:千万不要在PMS初始化完成前,调用任何PMS的接口。否则轻则返回null,重则导致系统服务死锁。我在代码审查时,经常看到新手在系统服务启动阶段直接调用getPackageManager(),这是非常危险的做法。
2.7 小结:PMS是SystemServer的基石
总结一下今天的内容:
- PMS在SystemServer的
startBootstrapServices()阶段启动,优先级很高 - PMS启动时会扫描所有应用目录,解析APK信息
- AMS依赖PMS获取应用信息和权限校验
- WMS依赖PMS进行窗口权限校验
- 启动顺序有严格依赖,PMS必须先于AMS和WMS就绪
说白了,PMS就是Android系统的“户口本”。没有它,AMS不知道哪些应用可以运行,WMS不知道哪些窗口可以显示。理解了这一点,你就抓住了PMS在系统架构中的核心位置。