用通俗易懂的故事和代码来拆解这篇关于 WMS(WindowManagerService)诞生 的文章,让小白也能轻松理解 Android 窗口管理的核心是如何启动的。
📖 故事背景:安卓世界的"窗口管理局"
想象一下,Android 系统就像一座繁华的城市:
- App(应用):是城市里的各种店铺、公司(比如微信、抖音)。
- 屏幕(Display):是城市里的公告板、广告牌、店铺橱窗,用来展示信息。
- 用户操作(触摸、按键):是市民在橱窗前点击、滑动。
为了让这些"店铺"的"橱窗"(App 的界面)有序展示、响应市民操作、播放炫酷的动画,城市需要一个强大的管理机构------窗口管理局(WMS)。
这篇文章讲的就是这个"窗口管理局"(WMS)是如何在 Android 系统启动时被"招聘"并"上岗"的。
🏗️ 第一章:招聘启事 - WMS 的职责
WMS 可不是普通部门,它身兼数职(对应文章开头概述):
- 窗口管理(核心):决定哪个 App 的"橱窗"能显示、显示多大、叠在谁上面(层级)。就像安排店铺橱窗的位置和大小。
- 窗口动画:当从一个 App 切换到另一个 App 时,负责播放酷炫的过渡动画(比如滑动、淡入淡出)。就像橱窗切换时的动态效果。
- 输入中转站 :用户触摸屏幕(点击橱窗),事件会先交给
InputManagerService (IMS)
处理。IMS 需要知道用户点的是哪个"橱窗",这个信息就靠 WMS 提供!WMS 知道所有"橱窗"的位置和层级。WMS 持有 IMS 的引用。 - Surface 管理 :真正的"橱窗玻璃"叫
Surface
,App 在上面画画(绘制界面)。WMS 负责给每个需要显示的"橱窗"分配这块"玻璃"。
代码体现职责:文章开头列出了 WMS 的核心职责,这是理解它为何重要的基础。
🚀 第二章:总部启动 - SystemServer 的召唤
Android 系统启动时,有一个核心进程叫 system_server
(想象成城市的管理总部)。总部会启动所有关键系统服务(工商局 AMS、电力局 PMS、窗口管理局 WMS 等)。
总部启动服务的代码 (SystemServer.run()
) 分三步走:
scss
java
Copy
// frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
// ... 加载库、创建服务管理器 ...
startBootstrapServices(); // 1. 启动最基础的服务 (如工商AMS, 电力局PMS)
startCoreServices(); // 2. 启动核心服务 (如电池局)
startOtherServices(); // 3. 启动其他重要服务 (窗口管理局WMS就在这里
}
- 关键点 :WMS 属于
startOtherServices()
这一批,不是最最基础的,但非常重要!
🛠️ 第三章:招聘 WMS 局长 - startOtherServices()
故事进入高潮:在 startOtherServices()
方法里,WMS 被正式"招聘"上岗。
scss
java
Copy
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
// ... 启动其他70多个服务 ...
// 1️⃣ 创建"安保主管" (Watchdog - 看门狗)
final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService); // 安保主管开始巡逻
// 2️⃣ 创建"事件处理局" (InputManagerService - IMS)
inputManager = new InputManagerService(context); // 负责处理触摸事件
// 3️⃣ ⭐⭐⭐ 重磅!招聘"窗口管理局"局长 (WMS) ⭐⭐⭐
wm = WindowManagerService.main(
context, // 城市环境
inputManager, // 需要和"事件处理局"紧密合作
..., // 其他参数 (如是否首次启动)
new PhoneWindowManager() // 具体的窗口管理策略制定者
);
// 4️⃣ 登记注册,让全城都知道去哪找窗口管理局
ServiceManager.addService(Context.WINDOW_SERVICE, wm); // 注册 WMS
ServiceManager.addService(Context.INPUT_SERVICE, inputManager); // 注册 IMS
// 5️⃣ 告诉 WMS:"屏幕准备好了,可以开始管理了!"
wm.displayReady(); // 初始化显示信息
// 6️⃣ 告诉 WMS:"整个城市系统都准备好了,你可以正式全面工作了!"
wm.systemReady(); // 系统初始化完成通知
}
-
关键点:
WindowManagerService.main(...)
是创建 WMS 实例的核心入口。- WMS 和 IMS (
InputManagerService
) 是同时创建并紧密关联的(WMS 需要 IMS 处理事件,IMS 需要 WMS 知道窗口位置)。 - 创建后立即向
ServiceManager
(城市黄页)注册服务名 (Context.WINDOW_SERVICE
),这样 App 或其他系统服务(如 AMS)就能通过这个名字找到 WMS。 displayReady()
和systemReady()
是 WMS 生命周期的关键步骤,通知它硬件(屏幕)和软件(系统)都已就绪。
🔧 第四章:局长的诞生细节 - WMS.main()
的玄机
WindowManagerService.main()
方法看似简单,但暗藏跨线程创建的巧妙设计:
ruby
java
Copy
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public static WindowManagerService main(...) {
// 1️⃣ 找一个叫"android.display"的专家来处理显示相关任务(低延迟线程)
DisplayThread.getHandler().runWithScissors(() -> {
// 2️⃣ ⭐ 真正的 WMS 局长在这里诞生!⭐
sInstance = new WindowManagerService(context, im, ...);
}, 0);
return sInstance;
}
-
为什么用
runWithScissors
?-
SystemServer.run()
运行在system_server
线程(总部主办公楼)。 -
创建 WMS 是个复杂且需要低延迟的操作(涉及显示硬件),不能拖慢总部启动。
-
DisplayThread
是一个专门处理显示相关快速操作的单例前台线程(想象成城市里的"显示设备科",反应超快)。 -
runWithScissors(Runnable r, 0)
的意思是:- 把创建 WMS 的任务
r
丢给DisplayThread
("显示设备科")去执行。 0
表示system_server
线程(总部主办公楼)必须等待 ,直到DisplayThread
完成 WMS 创建任务 (r.run()
)。- 这保证了 WMS 创建完成前,
system_server
线程不会继续往下执行startOtherServices()
的其他部分。
- 把创建 WMS 的任务
-
通俗比喻 :总部 (
system_server
) 要招 WMS 局长,但局长需要特殊技能(处理显示,低延迟)。总部自己不擅长这个,就把招聘任务委托给专业的"显示设备科" (DisplayThread
) 去面试和任命。总部必须等"显示设备科"完成任命 (sInstance = new WMS(...)
) 并拿到任命书 (return sInstance
),才能继续处理其他事务。runWithScissors
里的0
就是总部说:"我就在这等着,你办完立刻告诉我!"
🏢 第五章:局长办公室的布置 - WMS 的构造函数
WMS 局长 (sInstance = new WindowManagerService(...)
) 上任后,开始布置办公室(初始化关键成员):
scss
java
Copy
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private WindowManagerService(...) {
// 1️⃣ 保存重要合作伙伴的联系方式
mInputManager = inputManager; // 持有"事件处理局"IMS 的引用 (关键合作
mActivityManager = ActivityManager.getService(); // 持有"警察局"AMS 的引用 (管理App进程)
// 2️⃣ 了解管辖的"公告牌/橱窗位置"(屏幕)
mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
mDisplays = mDisplayManager.getDisplays(); // 获取所有物理/虚拟屏幕
for (Display display : mDisplays) {
createDisplayContentLocked(display); // 为每块屏幕创建管理对象 (DisplayContent)
}
// 3️⃣ 组建"动画特效组"
mAnimator = new WindowAnimator(this); // 负责管理所有窗口动画
// 4️⃣ ⭐ 聘请"窗口策略顾问" (PhoneWindowManager - PWM) ⭐
initPolicy(); // 内部会调用 PWM.init()
// 5️⃣ 主动接受"安保主管" (Watchdog) 的监督
Watchdog.getInstance().addMonitor(this); // 防止WMS自己"死锁"导致系统崩溃
}
-
关键点:
-
持有 IMS 和 AMS 引用:WMS 需要和事件处理、应用管理紧密协作。
-
管理屏幕 (
DisplayContent
):为每块屏幕(主屏、副屏、虚拟屏)创建核心管理对象,记录该屏幕上的所有窗口信息。 -
动画引擎 (
WindowAnimator
):负责执行窗口切换等动画效果。 -
策略顾问 (
initPolicy()
->PhoneWindowManager
) :这是 WMS 工作的大脑之一!PhoneWindowManager (PWM)
定义了具体的窗口行为规则:- 按键(Home键、Back键、电源键)如何影响窗口?
- 如何布局状态栏、导航栏?
- 多窗口模式(分屏、画中画)如何实现?
initPolicy()
内部会调用PWM.init()
,并且这个调用也切换到了专门的android.ui
线程 (UI策略科),同样使用runWithScissors
确保完成初始化。这再次体现了关键任务需要专门线程处理。
-
接受监督 (
Watchdog
) :WMS 太重要了!如果它卡死(死锁),Watchdog
这个"安保主管"会检测到并重启整个system_server
(相当于城市总部重启),防止系统完全卡死。
-
🧵 第六章:线程协作图 - 谁在什么线程干活?
文章强调了三个关键线程的协作关系,这是理解 WMS 启动流程复杂性的核心:
-
system_server
线程 (总部主办公楼):- 执行
SystemServer.run()
->startOtherServices()
。 - 调用
WMS.main()
。 - 在
runWithScissors(..., 0)
处等待DisplayThread
完成 WMS 创建。 - WMS 创建完成后,继续执行
wm.displayReady()
和wm.systemReady()
。
- 执行
-
android.display
线程 (显示设备科):- 由
DisplayThread.getHandler()
管理。 - 执行
WMS.main()
里runWithScissors
中的Runnable
:sInstance = new WindowManagerService(...)
。 - 在 WMS 构造函数中,执行到
initPolicy()
时,它又使用UiThread.getHandler().runWithScissors(...)
等待android.ui
线程完成PWM.init()
。
- 由
-
android.ui
线程 (UI策略科):- 由
UiThread.getHandler()
管理。 - 执行
initPolicy()
里runWithScissors
中的Runnable
:mPolicy.init(...)
(即PhoneWindowManager.init()
)。
- 由
通俗流程:
- 总部 (
system_server
) 让"显示设备科" (android.display
) 去招 WMS 局长。 - "显示设备科"开始招人 (
new WMS
)。 - 招人过程中,WMS 局长说:"我需要先请个策略顾问 (
PWM
) 来定规矩"。于是"显示设备科"又把请顾问的任务委托给"UI策略科" (android.ui
)。 - "显示设备科"等着"UI策略科"把顾问 (
PWM
) 请来并完成初始化 (PWM.init()
)。 - "UI策略科"完成任务后,"显示设备科"才完成 WMS 局长的招聘 (
new WMS
完成)。 - "显示设备科"把任命书交给总部 (
system_server
)。 - 总部拿到任命书,继续工作:告诉 WMS 屏幕好了 (
displayReady
),系统好了 (systemReady
)。
📌 总结:WMS 诞生记的核心要点
- 何时何地出生? 在 Android 系统启动的
system_server
进程的startOtherServices()
阶段诞生。 - 谁负责创建? 创建过程主要在专门的
android.display
线程中执行 (WMS.main()
->new WMS()
)。 - 为何跨线程? 因为创建 WMS(尤其是涉及显示初始化)需要低延迟,避免阻塞
system_server
主线程启动其他服务。runWithScissors
保证了必要的同步等待。 - 关键依赖? 创建时需要
InputManagerService (IMS)
,构造时获取ActivityManagerService (AMS)
引用,并为每块屏幕创建DisplayContent
。 - 大脑是谁?
PhoneWindowManager (PWM)
是 WMS 的核心策略制定者,它的初始化 (init()
) 在专门的android.ui
线程中完成。 - 如何保证稳定? 将自己注册到
Watchdog
接受监控,防止自身死锁导致系统崩溃。 - 何时上岗? 创建完成后,通过
displayReady()
知晓屏幕状态,最终通过systemReady()
得知系统完全启动,可以全面开展工作。
这篇文章清晰地描绘了 WMS 这个 Android 窗口系统的"大脑"是如何在系统启动时,通过精心的线程协作和依赖管理,一步步被创建并初始化的过程。理解了 WMS 的诞生,就为理解其后续如何管理窗口、动画、输入等复杂行为打下了坚实基础。