WMS(WindowManagerService的诞生

用通俗易懂的故事和代码来拆解这篇关于 ​​WMS(WindowManagerService)诞生​​ 的文章,让小白也能轻松理解 Android 窗口管理的核心是如何启动的。


📖 ​​故事背景:安卓世界的"窗口管理局"​

想象一下,Android 系统就像一座繁华的城市:

  • ​App(应用)​:是城市里的各种店铺、公司(比如微信、抖音)。
  • ​屏幕(Display)​:是城市里的公告板、广告牌、店铺橱窗,用来展示信息。
  • ​用户操作(触摸、按键)​:是市民在橱窗前点击、滑动。

为了让这些"店铺"的"橱窗"(App 的界面)有序展示、响应市民操作、播放炫酷的动画,城市需要一个强大的管理机构------​​窗口管理局(WMS)​​。

这篇文章讲的就是这个"窗口管理局"(WMS)是如何在 Android 系统启动时被"招聘"并"上岗"的。


🏗️ ​​第一章:招聘启事 - WMS 的职责​

WMS 可不是普通部门,它身兼数职(对应文章开头概述):

  1. ​窗口管理(核心)​:决定哪个 App 的"橱窗"能显示、显示多大、叠在谁上面(层级)。就像安排店铺橱窗的位置和大小。
  2. ​窗口动画​:当从一个 App 切换到另一个 App 时,负责播放酷炫的过渡动画(比如滑动、淡入淡出)。就像橱窗切换时的动态效果。
  3. ​输入中转站​ :用户触摸屏幕(点击橱窗),事件会先交给 InputManagerService (IMS) 处理。IMS 需要知道用户点的是哪个"橱窗",这个信息就靠 WMS 提供!WMS 知道所有"橱窗"的位置和层级。​WMS 持有 IMS 的引用​
  4. ​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() 的其他部分。

​通俗比喻​ ​:总部 (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 启动流程复杂性的核心:

  1. system_server 线程 (总部主办公楼)​​:

    • 执行 SystemServer.run() -> startOtherServices()
    • 调用 WMS.main()
    • runWithScissors(..., 0)​等待​ DisplayThread 完成 WMS 创建。
    • WMS 创建完成后,继续执行 wm.displayReady()wm.systemReady()
  2. android.display 线程 (显示设备科)​​:

    • DisplayThread.getHandler() 管理。
    • 执行 WMS.main()runWithScissors 中的 RunnablesInstance = new WindowManagerService(...)
    • 在 WMS 构造函数中,执行到 initPolicy() 时,它又使用 UiThread.getHandler().runWithScissors(...) ​等待​ android.ui 线程完成 PWM.init()
  3. android.ui 线程 (UI策略科)​​:

    • UiThread.getHandler() 管理。
    • 执行 initPolicy()runWithScissors 中的 RunnablemPolicy.init(...) (即 PhoneWindowManager.init())。

​通俗流程​​:

  1. 总部 (system_server) 让"显示设备科" (android.display) 去招 WMS 局长。
  2. "显示设备科"开始招人 (new WMS)。
  3. 招人过程中,WMS 局长说:"我需要先请个策略顾问 (PWM) 来定规矩"。于是"显示设备科"又把请顾问的任务委托给"UI策略科" (android.ui)。
  4. "显示设备科"等着"UI策略科"把顾问 (PWM) 请来并完成初始化 (PWM.init())。
  5. "UI策略科"完成任务后,"显示设备科"才完成 WMS 局长的招聘 (new WMS 完成)。
  6. "显示设备科"把任命书交给总部 (system_server)。
  7. 总部拿到任命书,继续工作:告诉 WMS 屏幕好了 (displayReady),系统好了 (systemReady)。

📌 ​​总结:WMS 诞生记的核心要点​

  1. ​何时何地出生?​ 在 Android 系统启动的 system_server 进程的 startOtherServices() 阶段诞生。
  2. ​谁负责创建?​ 创建过程主要在专门的 android.display 线程中执行 (WMS.main() -> new WMS())。
  3. ​为何跨线程?​ 因为创建 WMS(尤其是涉及显示初始化)需要低延迟,避免阻塞 system_server 主线程启动其他服务。runWithScissors 保证了必要的同步等待。
  4. ​关键依赖?​ 创建时需要 InputManagerService (IMS),构造时获取 ActivityManagerService (AMS) 引用,并为每块屏幕创建 DisplayContent
  5. ​大脑是谁?​ PhoneWindowManager (PWM) 是 WMS 的核心策略制定者,它的初始化 (init()) 在专门的 android.ui 线程中完成。
  6. ​如何保证稳定?​ 将自己注册到 Watchdog 接受监控,防止自身死锁导致系统崩溃。
  7. ​何时上岗?​ 创建完成后,通过 displayReady() 知晓屏幕状态,最终通过 systemReady() 得知系统完全启动,可以全面开展工作。

这篇文章清晰地描绘了 WMS 这个 Android 窗口系统的"大脑"是如何在系统启动时,通过精心的线程协作和依赖管理,一步步被创建并初始化的过程。理解了 WMS 的诞生,就为理解其后续如何管理窗口、动画、输入等复杂行为打下了坚实基础。

相关推荐
一只柠檬新7 小时前
Web和Android的渐变角度区别
android
志旭7 小时前
从0到 1实现BufferQueue GraphicBuffer fence HWC surfaceflinger
android
_一条咸鱼_7 小时前
Android Runtime堆内存架构设计(47)
android·面试·android jetpack
用户2018792831677 小时前
通俗易懂的讲解:Android窗口属性全解析
android
openinstall7 小时前
A/B测试如何借力openinstall实现用户价值深挖?
android·ios·html
二流小码农7 小时前
鸿蒙开发:资讯项目实战之项目初始化搭建
android·ios·harmonyos
志旭8 小时前
android15 vsync源码分析
android
志旭8 小时前
Android 14 HWUI 源码研究 View Canvas RenderThread ViewRootImpl skia
android
whysqwhw9 小时前
Egloo 高级用法
android