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 中的 Runnable:sInstance = new WindowManagerService(...)。
    • 在 WMS 构造函数中,执行到 initPolicy() 时,它又使用 UiThread.getHandler().runWithScissors(...) ​等待​ android.ui 线程完成 PWM.init()。
  3. ​​android.ui 线程 (UI策略科)​​:

    • 由 UiThread.getHandler() 管理。
    • 执行 initPolicy() 里 runWithScissors 中的 Runnable:mPolicy.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 的诞生,就为理解其后续如何管理窗口、动画、输入等复杂行为打下了坚实基础。

相关推荐
martindelophy1 小时前
用自然语言剪视频:我们在 Timeline Studio 中实现了 ChatCut 对话剪辑
android·音视频
ao-weilai2 小时前
MySQL数据库:复合查询
android·数据库·mysql
三少爷的鞋14 小时前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
Dovis(誓平步青云)18 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码20 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程20 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer