18 KiB
Android WindowManagerService (WMS) 架构深度解析
版本: Android 13 (API 33)
面向对象: Framework层高级工程师
作者: Android系统团队
1. WMS概述
1.1 架构地位与服务初始化
WindowManagerService作为Android图形系统的中枢,运行于system_server进程,管理所有窗口的生命周期、布局、层级与输入事件分发。它与ActivityManagerService(AMS)、SurfaceFlinger构成Android Framework的三驾马车。
服务启动时序 (SystemServer.java):
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
// 1. 初始化WMS
wm = WindowManagerService.main(context, inputManager, ...);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
// 2. WMS就绪后通知AMS
wm.displayReady();
wm.systemReady();
}
核心初始化链路:
main()→ 创建WindowManagerService实例- 初始化
WindowManagerPolicy(策略接口,实际为PhoneWindowManager) - 创建
DisplayContent管理多显示器 - 关联
InputManagerService建立输入通道
1.2 核心架构类图
classDiagram
class WindowManagerService {
- WindowManagerPolicy mPolicy
- WindowHashMap mWindowMap
- RootWindowContainer mRoot
- H mH
+ addWindow()
+ removeWindow()
+ relayoutWindow()
- performLayoutAndPlaceSurfacesLocked()
}
class WindowState {
- IWindow mClient
- WindowToken mToken
- WindowManager.LayoutParams mAttrs
- Session mSession
- SurfaceControl mSurfaceControl
+ openInputChannel()
+ attach()
}
class WindowToken {
- IBinder token
- int windowType
- DisplayContent mDisplayContent
+ addWindow()
}
class DisplayContent {
- Display mDisplay
- TaskDisplayArea mTaskDisplayArea
- DisplayPolicy mDisplayPolicy
- InputMonitor mInputMonitor
+ getWindowToken()
+ computeImeTarget()
}
class InputMonitor {
- InputWindowHandle mInputWindowHandles
+ updateInputWindowsLw()
+ setInputFocusLw()
}
WindowManagerService --> DisplayContent : 管理
WindowManagerService --> WindowState : 管理
DisplayContent --> WindowToken : 包含
WindowToken --> WindowState : 包含
WindowManagerService --> InputMonitor : 持有
InputMonitor --> WindowState : 监控
2. 窗口管理核心
2.1 核心数据结构
| 类名 | 作用 | 关键成员 |
|---|---|---|
| WindowState | 真实窗口状态实体 | mAttrs(窗口参数), mFrame(显示区域), mSurfaceControl(Surface句柄) |
| WindowToken | 窗口令牌,同一组窗口的集合 | token(Binder令牌), mChildren(子窗口列表) |
| DisplayContent | 逻辑屏幕管理 | mDisplay(物理显示), mTaskDisplayArea(任务区) |
| ActivityRecord | Activity对应的窗口Token | 继承自WindowToken,绑定AMS生命周期 |
| Session | 应用进程与WMS的会话 | 每个应用进程对应一个Session |
2.2 窗口添加流程 (addWindow)
sequenceDiagram
participant App as 应用进程
participant WMS as WindowManagerService
participant DC as DisplayContent
participant SF as SurfaceFlinger
App->>WMS: Session.addToDisplayAsUser()
activate WMS
WMS->>WMS: 权限校验(mPolicy.checkAddPermission)
WMS->>DC: displayContent.getWindowToken()
alt Token不存在
WMS->>WMS: 创建WindowToken
end
WMS->>WMS: 创建WindowState
WMS->>WMS: displayPolicy.adjustWindowParamsLw()
WMS->>WMS: validateAddingWindowLw()
WMS->>WindowState: openInputChannel()
Note right of WindowState: 创建InputChannel对,<br/>一端给WMS,一端给应用
WMS->>WMS: win.attach() → 加入容器
WMS->>mWindowMap: put(client.asBinder(), win)
WMS->>WindowToken: addWindow(win)
WMS->>WMS: updateFocusedWindowLocked()
WMS->>DC: getInputMonitor().setInputFocusLw()
WMS->>WindowState: getParent().assignChildLayers()
WMS-->>SF: SurfaceControl.openTransaction()
WMS-->>SF: 创建Surface
WMS-->>SF: SurfaceControl.closeTransaction()
deactivate WMS
源码核心片段 (Android 13) :
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, ...) {
synchronized (mGlobalLock) {
// 1. 重复添加检查
if (mWindowMap.containsKey(client.asBinder())) {
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
// 2. Token获取/创建
WindowToken token = displayContent.getWindowToken(attrs.token);
if (token == null) {
token = new WindowToken.Builder(this, binder, type)
.setDisplayContent(displayContent)
.build();
}
// 3. 创建WindowState
final WindowState win = new WindowState(this, session, client, token,
parentWindow, appOp[0], attrs, viewVisibility, ...);
// 4. 打开输入通道
if (outInputChannel != null) {
win.openInputChannel(outInputChannel);
}
// 5. 加入管理容器
win.attach();
mWindowMap.put(client.asBinder(), win);
win.mToken.addWindow(win);
// 6. 触发布局与焦点更新
performLayoutAndPlaceSurfacesLocked();
}
}
2.3 窗口删除流程
主要步骤:
- 线程检查: 确保调用线程与创建线程一致
- 移除引用: 从
ViewRootImpl列表、布局参数列表、View列表中删除 - 动画处理: 如果窗口正在运行动画,延迟删除
- 资源释放: 释放Surface、关闭InputChannel
// WindowManagerService.removeWindow() 核心逻辑
void removeWindow(Session session, IWindow client) {
synchronized(mGlobalLock) {
WindowState win = mWindowMap.remove(client.asBinder());
if (win == null) return;
// 关闭输入通道
win.removeInputChannel();
// 从Token中移除
win.mToken.removeWindow(win);
// 释放Surface
win.mSurfaceControl.reparent(null);
win.mSurfaceControl = null;
// 重新计算焦点
updateFocusedWindowLocked();
performLayoutAndPlaceSurfacesLocked();
}
}
2.4 窗口层级管理 (Z-order)
Android窗口分为三大类,层级规则如下:
| 窗口类型 | 范围 | 层级特点 |
|---|---|---|
| 应用窗口 | 1 ~ 99 | 随Activity生命周期,由Task组织 |
| 子窗口 | 1000 ~ 1999 | 必须依附于父窗口,Z-order在父窗口之上 |
| 系统窗口 | 2000 ~ 2999 | 最高层级,如状态栏、输入法、Toast |
层级分配算法:
assignLayersLocked()在每次布局时调用- 基于
BaseLayer + (type * 10000) + subLayerOffset计算 - 系统窗口 > 输入法窗口 > 应用窗口 > 壁纸窗口
// frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void assignChildLayers() {
for (int i = 0; i < mChildren.size(); i++) {
WindowContainer child = mChildren.get(i);
child.assignLayer(getPrefix(), ++layer);
}
}
3. 布局与合成机制
3.1 布局流程核心方法
performLayoutAndPlaceSurfacesLocked() (简称LAPS) 是WMS的心脏,处理所有窗口位置、大小、可见性的计算。
调用时机:
- 窗口添加/删除/更新
- 配置变化(横竖屏切换、多窗口调整)
- 动画更新
- VSync信号到达
执行流程:
// 简化版LAPS流程
void performLayoutAndPlaceSurfacesLocked() {
// 1. 布局窗口位置
performLayoutLocked();
// 2. 分配Surface层值
assignLayersLocked();
// 3. 准备Surface (与SurfaceFlinger交互)
for (WindowState win : mWindows) {
if (win.hasSurface() && win.shouldPrepareSurface()) {
win.prepareSurfaceLocked();
}
}
// 4. 提交事务给SurfaceFlinger
mSurfaceControlFactory.getTransaction().apply();
// 5. 更新输入焦点窗口信息
mInputMonitor.updateInputWindowsLw();
}
3.2 relayoutWindow 核心流程
应用通过ViewRootImpl.relayoutWindow()请求WMS重新计算窗口布局并分配Surface。
sequenceDiagram
participant AppThread as UI线程
participant VRI as ViewRootImpl
participant WMS as WindowManagerService
participant SF as SurfaceFlinger
AppThread->>VRI: performTraversals()
VRI->>WMS: relayoutWindow()
activate WMS
WMS->>WMS: 获取mGlobalLock
WMS->>WindowState: 计算新Frame
WMS->>WindowState: 更新可见区域
alt Surface需要重建
WMS->>WindowState: createSurfaceControl()
WMS-->>SF: createSurface()
else Surface无变化
WMS->>WindowState: setPosition/setSize
end
WMS->>WMS: performLayoutAndPlaceSurfaces()
WMS-->>VRI: 返回RelayoutResult
deactivate WMS
VRI->>AppThread: 通知布局完成
VRI->>SF: 队列绘制命令
性能关键点: relayoutWindow 持有mGlobalLock,长时间操作会阻塞其他窗口更新,导致丢帧。
3.3 与SurfaceFlinger的交互
WMS通过SurfaceControl与SurfaceFlinger通信:
// WindowState.createSurfaceControl() 核心逻辑
void createSurfaceControl() {
SurfaceControl.Builder b = new SurfaceControl.Builder()
.setName(mAttrs.getTitle().toString())
.setSize(mFrame.width(), mFrame.height())
.setFormat(mAttrs.format)
.setFlags(flags)
.setParent(mToken.getSurfaceControl());
mSurfaceControl = b.build();
// 设置初始属性
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setPosition(mSurfaceControl, mFrame.left, mFrame.top);
t.setLayer(mSurfaceControl, mLayer);
t.setAlpha(mSurfaceControl, mAttrs.alpha);
t.apply();
}
关键事务类型:
setPosition/setSize: 更新位置尺寸setLayer: 设置Z-ordersetAlpha/setMatrix: 动画相关reparent: 改变Surface父子关系(用于窗口切换动画)
4. 输入事件分发机制
4.1 完整分发链路
flowchart TD
A[InputReader读取事件] --> B[InputDispatcher派发]
B --> C{InputMonitor筛选窗口}
C -->|焦点窗口| D[获取窗口InputChannel]
C -->|触摸坐标命中测试| E[获取命中窗口]
D --> F[通过socket发送]
E --> F
F --> G[应用进程ViewRootImpl]
G --> H[InputEventReceiver接收]
H --> I[ViewRootImpl处理]
I --> J[View树分发]
4.2 InputMonitor角色
InputMonitor是WMS中的核心组件,负责维护输入窗口信息并传递给InputDispatcher:
// frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
void updateInputWindowsLw(boolean force) {
// 遍历所有窗口,收集输入窗口信息
mDisplayContent.forAllWindows((w) -> {
InputWindowHandle handle = w.getInputWindowHandle();
handle.setTouchableRegion(w.getTouchableRegion());
handle.setFocus(w == mDisplayContent.mCurrentFocus);
handle.setLayer(w.getLayer());
// 添加到列表
mInputWindowHandles.add(handle);
}, true);
// 提交给InputDispatcher
mInputManager.setInputWindows(mInputWindowHandles);
}
4.3 InputChannel建立
每个窗口在添加时通过openInputChannel创建一对Socket连接:
// WindowState.openInputChannel()
void openInputChannel(InputChannel outInputChannel) {
String name = getName();
InputChannel[] channels = InputChannel.openInputChannelPair(name);
// 服务端注册到InputDispatcher
mInputWindowHandle = new InputWindowHandle(this);
mService.mInputManager.registerInputChannel(channels[0], mInputWindowHandle);
// 客户端通道通过Binder返回
channels[1].transferTo(outInputChannel);
// 保存服务端通道
mClientChannel = channels[0];
}
5. 跨服务协作机制
5.1 WMS与AMS协作
AMS与WMS通过ActivityRecord(继承自WindowToken)建立绑定关系:
sequenceDiagram
participant AMS
participant WMS
participant Activity as ActivityRecord
AMS->>WMS: setAppWindowToken(token, activity)
Note right of WMS: 绑定Activity与WindowToken
AMS->>AMS: startActivityLocked()
AMS->>WMS: setAppStartingWindow()
WMS-->>Activity: 创建启动窗口
AMS->>WMS: setAppVisibility(visible)
WMS->>Activity: 显示/隐藏Activity窗口
AMS->>WMS: moveTaskToFront()
WMS->>Activity: 调整Task层值
AMS->>WMS: setFocusedApp(token)
WMS->>Activity: 设置焦点窗口
关键交互场景:
- Activity启动: AMS通知WMS创建
AppWindowToken - 窗口可见性: AMS控制生命周期,WMS控制显示/隐藏
- Configuration变化: 横竖屏切换需两服务协同
- Task管理: AMS维护Task栈,WMS维护显示层级
5.2 WMS与InputManagerService
// WMS持有IMS引用,IMS回调WMS
class WindowManagerService {
InputManagerService mInputManager;
// IMS回调WMS处理注入事件
boolean injectInputEvent(InputEvent event, int mode) {
return mInputManager.injectInputEvent(event, mode);
}
}
5.3 容器遍历机制 (Android 13新特性)
WMS基于WindowContainer树形结构管理,提供统一的遍历API:
// 遍历所有叶子Task执行操作
void forAllLeafTasks(Consumer<Task> callback) {
mRoot.forAllLeafTasks(callback, true);
}
// 遍历所有Activity
void forAllActivities(Consumer<ActivityRecord> callback) {
mRoot.forAllActivities(callback, true);
}
// 实际应用:pause所有后台Task
void pauseBackTasks() {
mRoot.forAllLeafTasks((task) -> {
if (task.isVisible()) task.startPausing();
}, false);
}
6. 性能优化与问题排查
6.1 锁竞争优化
WMS重度依赖mGlobalLock,优化策略:
| 问题 | 优化方案 |
|---|---|
| 长时间持有锁 | 拆分锁粒度,DisplayContent独立锁 |
| 布局计算耗时 | 异步布局预览 |
| Surface创建阻塞 | 预创建Surface池,复用缓冲区 |
| Binder调用同步 | 增加异步接口,如relayoutAsync |
典型案例: ANR日志分析
"android.fg" Blocked -> "JobScheduler" Blocked -> "WMS.relayoutWindow" Blocked
→ 表明relayoutWindow持有锁时间过长,导致前台线程阻塞
6.2 常见异常及解决方案
| 异常 | 触发条件 | 排查方向 |
|---|---|---|
BadTokenException |
窗口Token无效 | 检查Activity是否已销毁,WindowToken是否正确传递 |
| 窗口闪烁 | Surface频繁重建 | 检查relayoutWindow调用频率,View层级是否稳定 |
| 触摸事件错乱 | InputChannel未正确关闭 | 使用dumpsys input查看窗口注册状态 |
| 多窗口卡顿 | Z-order计算复杂 | 简化窗口层级,减少重叠窗口数量 |
6.3 调试命令
# 查看所有窗口状态
adb shell dumpsys window windows
# 查看输入系统状态
adb shell dumpsys input
# 查看显示信息
adb shell dumpsys display
# 查看WMS内部锁状态
adb shell dumpsys window traces
# 开启WMS详细日志
adb shell setprop log.tag.WindowManager VERBOSE
adb logcat -s WindowManager
关键输出解读:
Window #7 Window{...}:
mDisplayId=0
mSession=Session{...}
mClient=android.view.IWindow$Stub$Proxy
mSurfaceControl=Surface(name=...)
mFrame=[0,0][1080,1920]
mAttrs=WM.LayoutParams{... flags=0x... type=TYPE_BASE_APPLICATION}
7. 附录
7.1 核心源码路径
| 组件 | 源码路径 |
|---|---|
| WMS主类 | frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java |
| WindowState | frameworks/base/services/core/java/com/android/server/wm/WindowState.java |
| DisplayContent | frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java |
| InputMonitor | frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java |
| RootWindowContainer | frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java |
| ActivityRecord | frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java |
7.2 版本演进特性
| Android版本 | WMS关键变化 |
|---|---|
| Android 10 | 引入TaskFragment,支持更细粒度窗口组织 |
| Android 11 | 窗口同步机制优化,减少Surface重建 |
| Android 12 | 新增WindowInsets动画,改进多窗口布局 |
| Android 13 | 容器遍历API标准化,锁粒度细化 |
7.3 推荐文献
- 《深入理解Android内核设计思想》- 窗口系统章节
- AOSP官方文档: source.android.com/docs/core/graphics
- 老罗的Android之旅: WMS系列博客
总结
WindowManagerService作为Android窗口系统的中枢,承担着窗口生命周期管理、布局计算、输入事件路由三大核心职责。理解WMS需要把握以下几点:
- 架构分层: 客户端(WindowManager) ↔ 服务端(WMS) ↔ 底层(SurfaceFlinger)的三层模型
- 核心对象: WindowState(窗口实体)、WindowToken(逻辑分组)、DisplayContent(显示区域)
- 关键流程: addWindow/removeWindow/relayoutWindow 构成窗口生命周期
- 锁机制:
mGlobalLock是性能关键点,异步化是优化方向 - 协同机制: AMS控制生命周期,WMS控制显示,SurfaceFlinger负责合成
掌握WMS原理不仅是解决窗口相关问题的基石,更是深入理解Android图形系统、输入系统的必备知识。