WindowManagerService(WMS)是Android Framework中负责管理所有窗口的核心系统服务。你可以把它理解为整个屏幕界面的“总导演”:SurfaceFlinger是只负责渲染的“摄像师”,而WMS决定每个窗口(Activity、对话框、状态栏、输入法等)该在什么时候、出现在哪里、有多大、谁盖住谁,以及谁该获得用户的触摸事件。
由于WMS极其复杂,我将从以下五个层面为你拆解,涵盖职责、启动、数据结构、核心机制及与其他模块的协作:
一、WMS的核心职责
WMS在系统中扮演四个关键角色,这四点被多个源码分析文章反复印证,是其最稳定的核心定义:
| 核心职责 | 具体说明 |
|---|---|
| 窗口管理 | 负责窗口的添加、删除、更新;管理窗口的大小、位置、Z轴顺序(层叠关系)。这是最基础的职能 |
| Surface管理 | 窗口本身不具备绘图能力。客户端向WMS添加窗口的过程,本质是WMS为其分配一块Surface的过程。Window的本质就是Surface |
| 窗口动画 | 管理窗口切换、启动、关闭时的动画效果,由WindowAnimator专门负责 |
| 输入中转站 | WMS掌握所有窗口的位置和状态,因此InputManagerService(IMS)收到触摸事件后,必须由WMS来找出“当前哪个窗口应该接收此事件” |
经典比喻:SurfaceFlinger是摄像机,只负责捕捉画面;WMS是导演,负责舞台效果、演员站位;ViewRoot是演员的长相表情。
二、WMS的诞生(启动流程)
WMS是在SystemServer进程中启动的。SystemServer会启动三大类服务(引导、核心、其他),WMS属于“其他服务”。
关键启动代码逻辑(基于Android 8.0+,近年版本质不变):
- 入口:
SystemServer.startOtherServices() - 创建IMS:先创建
InputManagerService——WMS需要持有它的引用。 - 调用WMS.main():这是创建WMS的静态方法。
- 线程切换:
main()方法通过DisplayThread.getHandler().runWithScissors()强制将WMS的构造逻辑扔到android.display线程执行。- 为什么要这样?因为WMS涉及显示初始化,优先级必须高于当前
system_server线程。runWithScissors会使system_server线程阻塞,直到android.display线程创建完WMS才唤醒。
- 注册服务:
ServiceManager.addService(Context.WINDOW_SERVICE, wm),使客户端(如应用进程)能通过Binder获取WMS代理。 - 后续初始化:
displayReady()、systemReady()。
构造方法的关键动作:
- 保存IMS引用(
mInputManager) - 初始化策略类
PhoneWindowManager(即mPolicy,定义窗口行为的规范,如状态栏多高、键盘怎么顶) - 创建
WindowAnimator - 创建
RootWindowContainer(根容器) - 将自己加入Watchdog监控(防止死锁)
重要知识点:这里涉及三个线程的协作关系:
system_server(主调)、android.display(创建WMS)、android.ui(初始化PhoneWindowManager)。优先级:android.ui>android.display>system_server。
三、WMS的核心数据结构
WMS为了管理成百上千个窗口,设计了一套严谨的“令牌-窗口”映射模型。理解这三个核心类,就理解了WMS的骨架:
1. WindowToken(窗口令牌)
- 是什么:一组拥有相同令牌的窗口集合。
- 作用:同一个Activity(或输入法、壁纸)的所有窗口(主窗口、子窗口、启动窗口)共享同一个Token。
- 来源:对于Activity,Token来自AMS的
ActivityRecord;对于输入法/壁纸,来自对应服务传递的Binder。
2. AppWindowToken(Activity窗口令牌)
- 继承自
WindowToken,专门代表Activity组件。 - WMS中通过
mAppTokens(ArrayList)按Z轴顺序维护所有Activity窗口。
3. WindowState(窗口状态)
- 这是WMS中“真正的窗口”。每个添加到WMS的窗口都会对应一个
WindowState对象。 - 记录该窗口的所有实时信息:尺寸、位置、Z轴层值、包名、是否可见、动画状态、对应的Session等。
- 保存在
mWindowMap(HashMap)中,key为IBinder。
组织关系示意图:
AMS层:ActivityRecord A → 对应 → WMS层:AppWindowToken A
↓
包含一组WindowState:
- 主窗口WindowState
- 启动窗口WindowState
- 子窗口WindowState
所有
WindowState在WMS中按Z轴低→高排列,形成窗口堆栈(Window Stack),决定了谁盖住谁。
四、窗口管理的核心流程(添加与删除)
以应用添加一个窗口(如Activity启动、Dialog显示)为例,走通客户端到WMS的路径:
4.1 窗口添加流程
- 客户端发起:
WindowManager.addView()→WindowManagerGlobal.addView()→ 创建ViewRootImpl。 - 跨进程通信:
ViewRootImpl.setView()→mWindowSession.addToDisplayAsUser()。mWindowSession是每个应用进程与WMS保持的Binder会话(Session对象),由WMS为该进程创建。
- WMS处理(
Session.addWindow()→WMS.addWindow()):- 前置检查:权限、参数合法性、窗口是否已存在等。
- Token处理:根据窗口类型(应用窗口/子窗口/系统窗口)获取或隐式创建
WindowToken。 - 创建WindowState:将此窗口的信息封装为
WindowState,存入mWindowMap,并与Token关联。 - 分配Surface:向SurfaceFlinger申请一块绘图表面(经简化)。
- 层值分配:通过
assignLayersLocked()计算Z轴顺序。 - 焦点处理:如果此窗口可聚焦,更新焦点窗口。
- 布局与放置:触发
performLayoutAndPlaceSurfacesLocked()——这是WMS最核心、最复杂的函数(曾长达1200+行),计算所有窗口的最终位置并告知SF。
4.2 窗口删除流程
- 显式删除:调用
WindowManager.removeView()。 - 隐式删除:Activity销毁(
finish()),AMS回调WMS移除AppWindowToken。 - 核心动作:释放Surface、移除WindowState、重新布局剩余窗口、转移焦点。
五、WMS与三大兄弟模块的协作
WMS不是孤岛,它与AMS、SurfaceFlinger、IMS紧密交织:
5.1 WMS ↔ AMS
- 双向调用:
- AMS启动Activity时,会调用WMS的
addAppToken()(添加令牌)、setAppStartingWindow()(设置启动窗口)、resumeTopActivities()触发窗口显示。 - WMS在横竖屏切换、杀死应用时也会回调AMS。
- AMS启动Activity时,会调用WMS的
- 核心纽带:
AppWindowToken。AMS的ActivityRecord与WMS的AppWindowToken一一对应。
5.2 WMS ↔ SurfaceFlinger (SF)
- WMS不直接绘制,但它通过
SurfaceControl(封装了Surface)向SF申请/释放Layer,并设置Layer的尺寸、位置、Z-order等属性。 - 简单理解:WMS“指挥”SF“怎么叠图层”,SF“执行”合成渲染。
5.3 WMS ↔ InputManagerService (IMS)
- IMS从驱动读取原始输入事件,但它不知道这些事件该发给谁。
- WMS提供“窗口地图”:每个
WindowState在创建时会注册InputChannel,并将窗口的点击区域(hit region)同步给IMS。 - IMS通过Socket找到目标窗口后,事件直接派发给对应的ViewRootImpl。
总结与学习建议
WMS的复杂性主要源于它要同时协调应用进程(Binder通信)、系统策略(PhoneWindowManager)、图形系统(SurfaceFlinger)和输入系统(IMS)。
对于深入源码的学习,建议采用**“分而治之”**的策略,按以下情境逐个击破:
- 窗口添加/删除流程(最基础)
- Z轴顺序计算与窗口组织(理解WindowToken/WindowState)
- 输入法/壁纸窗口的特殊调整(理解WMS策略性)
- 窗口动画原理(WindowAnimator)
- 启动窗口(StartingWindow)的显示与移除