Files
mkdocs/docs/# Android WindowManagerService (WMS) 架构深度解析(专家第一次提示词).md
2026-02-28 01:44:55 +08:00

18 KiB
Raw Permalink Blame History

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 窗口删除流程

主要步骤:

  1. 线程检查: 确保调用线程与创建线程一致
  2. 移除引用: 从ViewRootImpl列表、布局参数列表、View列表中删除
  3. 动画处理: 如果窗口正在运行动画,延迟删除
  4. 资源释放: 释放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-order
  • setAlpha / 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: 设置焦点窗口

关键交互场景:

  1. Activity启动: AMS通知WMS创建AppWindowToken
  2. 窗口可见性: AMS控制生命周期WMS控制显示/隐藏
  3. Configuration变化: 横竖屏切换需两服务协同
  4. 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 推荐文献

  1. 《深入理解Android内核设计思想》- 窗口系统章节
  2. AOSP官方文档: source.android.com/docs/core/graphics
  3. 老罗的Android之旅: WMS系列博客

总结

WindowManagerService作为Android窗口系统的中枢承担着窗口生命周期管理、布局计算、输入事件路由三大核心职责。理解WMS需要把握以下几点

  1. 架构分层: 客户端(WindowManager) ↔ 服务端(WMS) ↔ 底层(SurfaceFlinger)的三层模型
  2. 核心对象: WindowState(窗口实体)、WindowToken(逻辑分组)、DisplayContent(显示区域)
  3. 关键流程: addWindow/removeWindow/relayoutWindow 构成窗口生命周期
  4. 锁机制: mGlobalLock是性能关键点,异步化是优化方向
  5. 协同机制: AMS控制生命周期WMS控制显示SurfaceFlinger负责合成

掌握WMS原理不仅是解决窗口相关问题的基石更是深入理解Android图形系统、输入系统的必备知识。