11、WindowManagerService 启动与初始化:WMS 的创建时机、systemReady() 回调、DisplayContent 与 DisplayManager 的关联
各位同学,今天我们来聊聊 WMS 的启动与初始化。说实话,这部分内容在源码里藏得挺深,很多同学看了好几遍源码,还是搞不清 WMS 到底是在什么时候创建的。我当年刚接触 Android 系统时,也在这个地方绕了很久。
WMS 的启动,说白了就是 SystemServer 进程里的一连串调用。它不像 Activity 那样有个显眼的 onCreate,而是悄无声息地嵌在系统启动流程中。嗯,这里我们要抓住三个关键点:创建时机、systemReady 回调、以及 DisplayContent 与 DisplayManager 的关联。
11.1 WMS 的创建时机
WMS 是在 SystemServer 的 startOtherServices() 方法中被创建的。你想想看,SystemServer 启动了几十个服务,WMS 只是其中之一。但它的位置很特殊——它依赖于 InputManagerService、PowerManagerService 等服务的就绪。
我习惯把 WMS 的创建过程分为三个阶段:
- 实例化阶段:在 SystemServer 中调用
WindowManagerService.main() - 初始化阶段:在 WMS 构造函数中完成内部数据结构的初始化
- 就绪阶段:通过
systemReady()回调完成最终准备
来看一段核心代码,这是 WMS 的创建入口:
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
// ... 前面一堆服务的启动
// 创建 WMS 实例
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
// 注册到 ServiceManager
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
// ... 后续服务的启动
}
这里有个细节要注意:WindowManagerService.main() 是一个静态方法,它内部会 new 一个 WMS 实例。我在项目中遇到过一个问题,就是 WMS 创建时如果 InputManager 还没准备好,会导致空指针。后来看了源码才发现,WMS 构造函数里会主动检查 InputManager 的状态。
关键点:WMS 的创建不是一步到位的。构造函数里只做了基础初始化,真正的「启动」要等到 systemReady() 被调用。
11.2 systemReady() 回调
systemReady() 是 WMS 初始化的第二幕。它是在 SystemServer 的 systemReady() 阶段被调用的。说白了,这时候系统的大部分服务都已经就绪了,WMS 可以开始做一些「需要依赖其他服务」的事情了。
WMS 的 systemReady() 主要做了以下几件事:
- 初始化 DisplayContent 集合
- 与 DisplayManagerService 建立关联
- 恢复之前保存的窗口状态(如果有)
- 启动窗口动画系统
我曾经踩过一个坑:在 systemReady() 之前尝试获取 Display 信息,结果返回的是 null。这是因为 DisplayManagerService 还没完成初始化,Display 的信息还没注册到系统中。所以,如果你在开发系统应用时,一定要等到 systemReady() 之后再去操作 Display。
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public void systemReady() {
// 确保 DisplayManager 已经就绪
mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
// 初始化 DisplayContent
mRoot.createDisplayContent(mDisplayManager);
// 恢复窗口状态
restoreWindowState();
// 启动动画
mAnimator.systemReady();
}
个人经验:systemReady() 是 WMS 初始化的分水岭。在这之前,WMS 只能做「独立」的初始化工作;在这之后,WMS 才能与 DisplayManager、InputManager 等兄弟服务协同工作。
11.3 DisplayContent 与 DisplayManager 的关联
这部分是 WMS 初始化的核心。DisplayContent 是什么?它代表了一个逻辑显示屏。在 Android 系统中,一个设备可能有多个显示屏(比如手机屏幕 + 电视投屏),每个显示屏对应一个 DisplayContent。
DisplayManager 则是管理所有物理显示器的系统服务。WMS 需要从 DisplayManager 那里获取显示器的信息,然后创建对应的 DisplayContent。
我画了一张图,帮你理清它们之间的关系:
从图中你可以看到,WMS 的初始化是一个链式过程。SystemServer 创建 WMS 后,WMS 在 systemReady() 中与 DisplayManager 交互,获取显示器信息,然后创建 DisplayContent,最后注册到 RootWindowContainer 中统一管理。
这里有个重要的数据结构——RootWindowContainer。它是所有 DisplayContent 的容器,也是 WMS 管理窗口的顶层入口。我习惯把它理解为「窗口世界的上帝」,所有窗口的添加、删除、布局都要经过它。
避坑指南:我曾经在 systemReady() 之前尝试通过 WMS 获取 Display 信息,结果返回的是空列表。这是因为 DisplayContent 的创建依赖于 DisplayManager 的就绪状态。所以,如果你在开发系统级功能时,一定要等到 systemReady() 回调之后再去操作 Display 相关的 API。
11.4 总结
WMS 的启动与初始化,说白了就是三个步骤:
| 阶段 | 触发时机 | 核心工作 |
|---|---|---|
| 创建 | SystemServer.startOtherServices() | 实例化 WMS,注册到 ServiceManager |
| 就绪 | SystemServer.systemReady() | 初始化 DisplayContent,关联 DisplayManager |
| 运行 | 系统启动完成 | 处理窗口操作,管理显示区域 |
嗯,这里要注意的是,WMS 的初始化不是一蹴而就的。它像是一个「延迟初始化」的过程——先创建骨架,再填充血肉。这种设计在 Android 系统中很常见,目的是为了减少启动时间,同时避免服务间的循环依赖。
我个人觉得,理解 WMS 的初始化流程,是掌握整个窗口系统的钥匙。你想想看,如果连 WMS 什么时候创建、什么时候就绪都搞不清楚,后面分析窗口添加、布局、动画这些流程时,肯定会一头雾水。
核心要点:WMS 的初始化分为两个阶段——构造函数中的基础初始化和 systemReady() 中的完整初始化。DisplayContent 的创建是连接 WMS 与 DisplayManager 的关键桥梁。
公众号:蓝海资料掘金营,微信deep3321