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 显示系统的调度中心,核心要点:

  1. 窗口是树形结构:从 RootWindowContainer 到 WindowState 的层级管理

  2. Surface 是绘制载体:WMS 管理 Surface 的创建和配置,实际绘制由应用完成

  3. Z-Order 决定可见性:层级高的窗口遮挡层级低的窗口

  4. relayout 是核心流程:计算大小、创建 Surface、触发布局

  5. 与 AMS 紧密协作:Activity 生命周期驱动窗口状态变化

更多推荐