WMS 是什么,为什么 Android 需要窗口管理员
2026/7/23大约 4 分钟WMS 窗口生命周期Android 14WMSWindowStateSurfaceFlinger
WMS 是什么,为什么 Android 需要窗口管理员
Activity 已经执行 onResume(),屏幕仍可能没有画面;setContentView() 已经完成,WMS 里也 可能还没有对应的 WindowState。窗口从组件状态走到最终合成,需要 WMS、应用绘制、输入 系统和 SurfaceFlinger 分别推进自己的状态。
这条链的上游是 AMS/ATMS 的 Activity 生命周期,系统进程的来源可回到 Bootloader 到 Android 用户空间;窗口产生 Buffer 后,下游进入 SurfaceFlinger 合成。本文只负责把这三个边界接起来。
WMS 管窗口状态,不替应用绘制
| 常见误解 | 正确理解 |
|---|---|
| WMS 负责把窗口画到屏幕上 | WMS 只管理窗口的状态和层级,应用自己绘制 View,SurfaceFlinger 完成合成 |
调用 setContentView() 就是向系统添加窗口 | setContentView() 只建立 Activity 内部的 View 树,加窗要等 WindowManager 客户端发起 |
应用看到的是屏幕区域,系统侧却把窗口所有权、内容绘制、图层合成和输入分发拆给不同组件。 只有明确这些边界,才能区分黑屏、错位和无焦点分别应从哪条链路开始检查。
本系列要证明的主线是:WMS 管理窗口,但窗口画面由 SurfaceFlinger 决定,触摸目标由 InputDispatcher 决定。
WMS 的六类职责
- 接纳窗口:校验窗口是否合法,创建服务端记录
WindowState,入口是addWindow()。 - 组织层级:把窗口放进
WindowToken、Task、Display 组成的容器树,决定 Z-order。 - 计算布局:结合应用请求、显示区域和系统栏 Insets,算出窗口的 frame(位置和尺寸)。
- 维护可见性与 Surface:决定窗口是否可见、何时创建 Surface、何时上报首帧。
- 管理焦点与输入目标:决定哪个窗口获得焦点,并把窗口元数据交给输入系统。
- 处理退出与动画:协调窗口隐藏、移除和 Transition,保证逻辑状态与画面状态最终一致。
一句话小结:WMS 管的是“窗口的一生”,不是“窗口的画”。
和相邻模块的分工
| 模块 | 管理对象 | 典型动作 | 本章结论 |
|---|---|---|---|
| AMS/ATMS | Activity、Task、进程 | 启动 Activity、管理任务栈 | 决定“应用是否该存在” |
| WMS | WindowState、窗口层级、焦点 | 加窗、布局、移除 | 决定“窗口如何被系统接纳” |
| View 系统 | View 树、绘制 | measure、layout、draw | 决定“窗口里画什么” |
| SurfaceFlinger | Layer、Buffer、合成 | 创建图层、合成帧 | 决定“屏幕最终显示什么” |
| InputDispatcher | 输入事件目标 | 命中测试、派发 | 决定“触摸落到哪个窗口” |
生命周期总图
逐步解释:
- ① App 入口:
setContentView()把布局交给 PhoneWindow,只回答“窗口里面有什么”。 - ② 客户端封装:WindowManager 客户端创建 ViewRootImpl,它是 View 树与系统窗口世界的根连接。
- ③ 跨进程入口:ViewRootImpl 通过
IWindowSessionBinder 代理请求 system_server。 - ④ 服务端校验:WMS 检查权限、token、类型和重复添加,创建
WindowState。 - ⑤ 入树:窗口挂到 WindowToken/Task/Display 容器树上,层级由此确定。
- ⑥ 布局:relayout 请求经过布局遍历,产出窗口 frame。
- ⑦ 可见性:窗口可见不等于已有画面;Surface 创建、Buffer 提交、画面合成是三个不同节点。
- ⑧ 焦点与输入:WMS 更新焦点窗口,并把窗口元数据交给输入系统选择触摸目标。
- ⑨ 移除:退出动画期间窗口可能延迟销毁。
- ⑩ SurfaceFlinger:只承接 Layer 创建与合成,不参与窗口管理决策。
从现象认识职责
| 可观察现象 | 对应职责 | 排查方向 |
|---|---|---|
| 两个窗口互相遮挡、顺序不对 | 层级组织 | window dump 的 Z-order |
| 弹窗加不进来、报 BadTokenException | 校验与 token | addWindow() 返回值 |
| 应用错位、顶到状态栏 | 布局与 Insets | window frame 与 InsetsState |
| 黑屏但应用活着 | 可见性与 Surface | Surface/Buffer 是否创建 |
| 点不到、焦点不在预期窗口 | 焦点与输入 | focus 与 input window 信息 |
| 关闭后窗口残留 | 移除与 Transition | removeIfPossible 与 Surface 销毁 |
源码入口
源码基准:android-14.0.0_r75。
以下文件默认位于 frameworks/base/,表中省略该前缀:
| 文件 | 关键位置 | 作用 |
|---|---|---|
services/core/java/com/android/server/wm/WindowManagerService.java | 386 行 class WindowManagerService extends IWindowManager.Stub | WMS 服务端本体 |
| 同文件 | 1448 行 addWindow() | 窗口接纳入口 |
| 同文件 | 2188 行 relayoutWindow() | 布局与 Surface 更新入口 |
services/core/java/com/android/server/wm/DisplayContent.java | 3953 行 updateFocusedWindowLocked() | 焦点更新入口 |
services/core/java/com/android/server/wm/InputMonitor.java | 333 行 updateInputWindowsLw() | 输入窗口信息入口 |
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp | 5903 行 createLayer() | 合成侧 Layer 创建入口 |