android WMS 详解
Android WMS(Window Manager Service)详解
WMS(Window Manager Service)是 Android 系统的核心服务之一,负责窗口的管理、布局、动画、层级排序以及输入事件的分发。它是连接应用层(View 系统)与底层显示系统(SurfaceFlinger)的桥梁。
一、WMS 的定位与职责
┌─────────────────────────────────────────────────────────┐
│ 应用层 (App) │
│ Activity / Dialog / PopupWindow │
├─────────────────────────────────────────────────────────┤
│ 窗口管理层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │
│ │ AMS │◄──►│ WMS │◄──►│ InputManager │ │
│ └─────────┘ └────┬────┘ └─────────────────┘ │
├─────────────────────────┼───────────────────────────────┤
│ 显示层 │
│ SurfaceFlinger / HWComposer │
├─────────────────────────┼───────────────────────────────┤
│ HAL 层 │
│ Gralloc / Display HAL │
└─────────────────────────┴───────────────────────────────┘
核心职责
| 职责 | 说明 |
|---|---|
| 窗口管理 | 维护所有窗口的添加、移除、更新 |
| Z-Order 排序 | 决定窗口的层级顺序(谁在上谁在下) |
| 布局计算 | 计算每个窗口的位置和大小 |
| 动画系统 | 管理窗口的进入、退出、切换动画 |
| 输入分发 | 将触摸/按键事件路由到正确的窗口 |
| 屏幕旋转 | 处理方向变化时的窗口重排 |
| 多窗口/分屏 | 管理 Freeform、Split-Screen 等模式 |
二、WMS 的启动与初始化
WMS 在 SystemServer 中启动:
java
// SystemServer.java
private void startOtherServices() {
// 1. 创建 WMS 实例
WindowManagerService wm = WindowManagerService.main(
context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
// 2. 注册到 ServiceManager
ServiceManager.addService(Context.WINDOW_SERVICE, wm, false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
// 3. 初始化显示
wm.displayReady();
// 4. 系统准备就绪
wm.systemReady();
}
关键初始化对象
-
WindowManagerPolicy:策略接口,PhoneWindowManager 是默认实现,定义系统 UI 行为
-
DisplayContent:代表一个物理或虚拟显示设备
-
RootWindowContainer:管理所有 DisplayContent
-
WindowAnimator:负责窗口动画
-
InputManagerService:输入事件管理
三、核心架构与类关系
核心类层次
RootWindowContainer
└── DisplayContent (每个屏幕一个)
└── TaskDisplayArea
└── Task
└── ActivityRecord
└── WindowToken
└── WindowState (对应一个窗口)
关键类详解
表格
| 类名 | 作用 |
|---|---|
| WindowState | 代表一个具体的窗口,包含窗口的所有状态信息 |
| WindowToken | 窗口的令牌,将一组 WindowState 绑定到一个应用组件 |
| DisplayContent | 代表一个显示设备,管理该屏幕上的所有窗口 |
| DisplayPolicy | 定义屏幕策略(状态栏、导航栏位置等) |
| WindowContainer | 所有窗口容器的基类,实现树形结构 |
| SurfaceControl | 与 SurfaceFlinger 通信的句柄 |
四、窗口类型与层级
Android 窗口分为三大类,通过 type 参数指定:
1. 应用窗口 (1-99)
java
TYPE_BASE_APPLICATION = 1 // Activity 主窗口
TYPE_APPLICATION = 2 // 普通应用窗口
TYPE_APPLICATION_STARTING = 3 // 启动窗口(冷启动时的白屏/黑屏)
TYPE_DRAWN_APPLICATION = 4 // 已绘制完成的窗口
2. 子窗口 (1000-1999)
java
TYPE_APPLICATION_PANEL = 1000 // Panel(如 PopupWindow)
TYPE_APPLICATION_MEDIA = 1001 // 媒体覆盖层
TYPE_APPLICATION_SUB_PANEL = 1002 // 子面板
TYPE_APPLICATION_ABOVE_SUB_PANEL = 1003
3. 系统窗口 (2000-2999)
java
TYPE_STATUS_BAR = 2000 // 状态栏
TYPE_SEARCH_BAR = 2001 // 搜索栏
TYPE_NOTIFICATION_SHADE = 2014 // 通知面板
TYPE_NAVIGATION_BAR = 2019 // 导航栏
TYPE_INPUT_METHOD = 2011 // 输入法
TYPE_VOLUME_OVERLAY = 2024 // 音量条
TYPE_SYSTEM_ALERT = 2015 // 系统警告(需要权限)
TYPE_TOAST = 2005 // Toast
TYPE_PHONE = 2002 // 悬浮窗(需要权限)
Z-Order 规则
窗口层级由 mBaseLayer 和 mSubLayer 决定:
-
mBaseLayer:由窗口类型决定,类型值越大层级越高
-
mSubLayer:子窗口相对父窗口的偏移
┌─────────────────────────────┐ ← 最上层 (TYPE_SYSTEM_ALERT)
│ 系统弹窗/悬浮窗 │
├─────────────────────────────┤
│ 输入法窗口 │
├─────────────────────────────┤
│ 应用窗口 (Activity) │
├─────────────────────────────┤
│ 壁纸窗口 │
├─────────────────────────────┤
│ 底层系统窗口 │
└─────────────────────────────┘ ← 最下层
五、窗口添加流程
当应用调用 WindowManager.addView() 时,完整的调用链如下:
ViewManager.addView()
└── WindowManagerImpl.addView()
└── WindowManagerGlobal.addView()
└── ViewRootImpl.setView()
└── IWindowSession.addToDisplay() [跨进程]
└── WindowManagerService.addWindow()
WMS.addWindow() 核心逻辑
java
public int addWindow(Session session, IWindow client, LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame,
InputChannel outInputChannel) {
// 1. 权限检查
int res = mPolicy.checkAddPermission(attrs, appOp);
// 2. 获取或创建 WindowToken
WindowToken token = displayContent.getWindowToken(
attrs.token);
if (token == null) {
// 创建新的 WindowToken
token = new WindowToken(this, attrs.token, type, ...);
}
// 3. 创建 WindowState
final WindowState win = new WindowState(this, session, client,
token, parentWindow, attrs, viewVisibility, ...);
// 4. 调整窗口参数
mPolicy.adjustWindowParamsLw(win, win.mAttrs, ...);
// 5. 将 WindowState 加入 WindowToken
win.mToken.addWindow(win);
// 6. 将 WindowToken 加入 DisplayContent
displayContent.addWindow(win);
// 7. 创建 SurfaceControl
win.createSurfaceControl();
// 8. 分配输入通道
win.openInputChannel(outInputChannel);
// 9. 触发布局
assignWindowLayers(displayContent);
displayContent.getDisplayPolicy().addWindowLw(win, attrs);
// 10. 通知 SurfaceFlinger
win.applyToken();
return ADD_OKAY;
}
六、窗口布局与测量(relayoutWindow)
relayoutWindow 是 WMS 中最核心的方法之一,负责计算窗口大小和创建 Surface。
ViewRootImpl.relayoutWindow()
└── IWindowSession.relayout()
└── WMS.relayoutWindow()
核心流程
java
public int relayoutWindow(Session session, IWindow client,
LayoutParams attrs, int requestedWidth, int requestedHeight,
int viewFlags, int flags, long frameNumber, Rect outFrame,
Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets,
Rect outOutsets, Rect outBackdropFrame,
DisplayCutout outCutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl) {
WindowState win = windowForClientLocked(session, client, false);
// 1. 更新窗口属性
if (attrs != null) {
win.setAttrs(attrs);
}
// 2. 计算窗口大小
win.computeFrameLw();
// 3. 如果 Surface 不存在,创建新的 SurfaceControl
if (win.mHasSurface && !win.mSurfaceController.getSurfaceControl().isValid()) {
win.createSurfaceControl();
}
// 4. 将 SurfaceControl 返回给应用
outSurfaceControl.copyFrom(win.mSurfaceController.getSurfaceControl());
// 5. 计算 insets
win.getContentInsets(outContentInsets);
win.getVisibleInsets(outVisibleInsets);
// 6. 触发布局
mWindowPlacerLocked.performSurfacePlacement();
return win.mRelayoutResult;
}
Surface 创建时序
WMS.relayoutWindow()
└── WindowState.createSurfaceControl()
└── WindowSurfaceController.createSurfaceLocked()
└── new SurfaceControl.Builder(mSurfaceSession)
└── SurfaceFlinger.createLayer()
└── 分配 GraphicBuffer
七、窗口动画系统
Android 窗口动画分为三个层级:
1. 应用层动画(View Animation)
java
view.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fade_in));
-
只影响单个 View,不涉及 WMS
2. 窗口动画(Window Animation)
java
// WindowManager.LayoutParams
params.windowAnimations = R.style.MyWindowAnimation;
-
由
WindowStateAnimator处理 -
在
WindowAnimator中统一调度
3. 过渡动画(Transition Animation)
Android 12+ 引入的 WindowAnimationTransition,由 TransitionController 管理:
java
// Transition 类型
TRANSIT_OPEN // 窗口打开
TRANSIT_CLOSE // 窗口关闭
TRANSIT_TO_FRONT // 窗口移到前台
TRANSIT_TO_BACK // 窗口移到后台
动画执行流程
WindowAnimator.animate()
└── WindowStateAnimator.stepAnimationLocked()
└── 计算动画变换矩阵
└── SurfaceControl.setMatrix()
└── SurfaceFlinger 合成时应用变换
八、输入事件分发
WMS 在输入事件中扮演路由角色:
plain
InputDispatcher (Native)
└── WMS 注册 InputMonitor
└── 根据窗口层级找到目标 WindowState
└── 通过 InputChannel 发送给对应进程
└── ViewRootImpl.dispatchInputEvent()
└── DecorView.dispatchTouchEvent()
事件分发关键逻辑
java
// InputDispatcher.cpp
int32_t InputDispatcher::findTouchedWindowTargetsLocked(...) {
// 1. 从顶层向下遍历窗口
// 2. 找到包含触摸点的最上层窗口
// 3. 检查窗口是否可接收事件(FLAG_NOT_TOUCHABLE 等)
// 4. 将事件分发给目标窗口
}
WMS 中的输入相关配置
| Flag | 说明 |
|---|---|
FLAG_NOT_FOCUSABLE | 窗口不可获取焦点 |
FLAG_NOT_TOUCHABLE | 窗口不可触摸 |
FLAG_NOT_TOUCH_MODAL | 窗口只接收自身区域的触摸 |
FLAG_WATCH_OUTSIDE_TOUCH | 接收窗口外部的触摸事件 |
FLAG_SPLIT_TOUCH | 支持多点分屏触摸 |
九、WMS 与 SurfaceFlinger 的关系
┌─────────────┐ SurfaceControl ┌─────────────────┐
│ WMS │ ◄──────────────────────► │ SurfaceFlinger │
│ (逻辑管理) │ transaction │ (合成显示) │
└──────┬──────┘ └─────────────────┘
│
│ 创建/配置 Surface
▼
┌─────────────┐
│ WindowState │
│ SurfaceControl│
└─────────────┘
│
│ 应用绘制
▼
┌─────────────┐
│ Surface │
│ (GraphicBuffer)│
└─────────────┘
SurfaceTransaction
WMS 通过 SurfaceControl.Transaction 与 SurfaceFlinger 通信:
java
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setLayer(surfaceControl, layer); // 设置层级
t.setPosition(surfaceControl, x, y); // 设置位置
t.setMatrix(surfaceControl, matrix); // 设置变换
t.setCrop(surfaceControl, crop); // 设置裁剪
t.setAlpha(surfaceControl, alpha); // 设置透明度
t.apply(); // 提交事务
十、WMS 与 AMS 的协作
WMS 和 AMS 紧密协作管理 Activity 生命周期和窗口状态:
Activity 启动时的窗口流程plain
AMS.startActivity()
└── ActivityTaskManager.startActivity()
└── ActivityStarter.execute()
└── ActivityStack.startActivityLocked()
└── WMS.addAppToken() // 添加 AppWindowToken
└── 创建启动窗口 (StartingWindow)
└── Activity 绘制完成
└── WMS.reportStartingWindowDrawn()
└── 移除启动窗口
关键协作点表格
| 场景 | AMS 操作 | WMS 操作 |
|---|---|---|
| Activity 启动 | 创建 ActivityRecord | 创建 AppWindowToken + StartingWindow |
| Activity 暂停 | onPause() | 窗口变为不可见,降低层级 |
| Activity 恢复 | onResume() | 窗口移到前台,提升层级 |
| Activity 销毁 | 移除 ActivityRecord | 移除 WindowToken 及所有 WindowState |
| 屏幕旋转 | 通知 Activity 重建 | 重新计算所有窗口尺寸 |
十一、多窗口模式
Android 7.0+ 支持多窗口,WMS 负责管理:
分屏模式(Split-Screen)
┌─────────────────────────────┐
│ Task 1 (上半屏) │
│ (Activity A) │
├─────────────────────────────┤ ← Divider
│ Task 2 (下半屏) │
│ (Activity B) │
└─────────────────────────────┘
自由窗口模式(Freeform)
┌─────────────────────────────────────┐
│ ┌─────────┐ │
│ │ Freeform│ │
│ │ Window │ │
│ └─────────┘ │
│ ┌─────────┐ │
│ │ Freeform│ │
│ │ Window │ │
│ └─────────┘ │
└─────────────────────────────────────┘
多窗口实现原理
-
Task:代表一个任务栈,包含多个 Activity
-
TaskFragment:Task 的细分单元
-
WindowContainer:树形结构管理所有容器
十二、WMS 的线程模型
┌─────────────────────────────────────┐
│ Main Thread (SystemServer) │
│ - 处理 IPC 调用 │
│ - 窗口状态变更 │
├─────────────────────────────────────┤
│ Animation Thread │
│ - 执行窗口动画 │
│ - 计算变换矩阵 │
├─────────────────────────────────────┤
│ SurfaceAnimation Thread │
│ - 与 SurfaceFlinger 同步动画 │
├─────────────────────────────────────┤
│ Input Thread (Native) │
│ - 读取输入设备 │
│ - 分发输入事件 │
└─────────────────────────────────────┘
十三、常见问题与调试
1. 查看窗口层级
bash
adb shell dumpsys window windows
2. 查看 SurfaceFlinger 信息
bash
adb shell dumpsys SurfaceFlinger
3. 查看动画状态
bash
adb shell dumpsys window animator
4. 常见窗口问题
| 问题 | 原因 | 解决方向 |
|---|---|---|
| 窗口无法获取焦点 | FLAG_NOT_FOCUSABLE | 检查 Window 属性 |
| 触摸事件不响应 | FLAG_NOT_TOUCHABLE | 检查 touchable 标志 |
| 窗口被遮挡 | Z-Order 过低 | 调整窗口类型或层级 |
| 黑屏/白屏 | Surface 未创建 | 检查 relayoutWindow |
| 动画卡顿 | SurfaceFlinger 掉帧 | 检查 GPU 负载 |
十四、Android 版本演进
| 版本 | WMS 重大变化 |
|---|---|
| Android 4.1 | 引入 Project Butter,VSync 同步 |
| Android 5.0 | 引入 SurfaceFlinger 的 HWC2,多显示支持 |
| Android 7.0 | 多窗口模式(Split-Screen, Freeform) |
| Android 8.0 | 画中画(PIP)模式 |
| Android 10 | 折叠屏支持,多 resume |
| Android 11 | 窗口注入限制,气泡通知 |
| Android 12 | 引入 SplashScreen API,Transition 动画重构 |
| Android 13+ | 进一步模块化,改进多任务处理 |
总结
WMS 是 Android 显示系统的调度中心,核心要点:
-
窗口是树形结构:从 RootWindowContainer 到 WindowState 的层级管理
-
Surface 是绘制载体:WMS 管理 Surface 的创建和配置,实际绘制由应用完成
-
Z-Order 决定可见性:层级高的窗口遮挡层级低的窗口
-
relayout 是核心流程:计算大小、创建 Surface、触发布局
-
与 AMS 紧密协作:Activity 生命周期驱动窗口状态变化
更多推荐


所有评论(0)