17 KiB
好的,遵照您的指示,我将基于您提供的详细提示词和搜索材料,为您创作一份《Android WindowManagerService核心原理深度解析》培训课件。
Android WindowManagerService核心原理深度解析
目录
- 引言:为什么需要深入理解WMS?
- WMS概览与架构定位
- 系统服务中的WMS
- 核心概念定义 (
Window,Token,State) - WMS核心职责
- 窗口的生命周期管理
- 从
ViewRootImpl到WindowState的旅程 - 关键流程序列图:添加窗口
- 核心数据结构:
WindowState解析
- 从
- 布局、动画与Surface管理
- 布局循环的核心:
performSurfacePlacement - 窗口动画的管理者:
WindowAnimator - Surface的申请与合成协调
- 布局循环的核心:
- 输入事件的中转与分发
- WMS作为IMS的中转站
- 关键流程序列图:触摸事件分发
- 命中测试(Hit Test)与
InputChannel
- 与关键系统服务的协同
- WMS & AMS:Activity状态与窗口的同步
- WMS & SurfaceFlinger:通过
Transaction提交变更 - UML简化类图:核心协作关系
- 高级主题与案例分析(可选)
- 从
dumpsys window看窗口状态 - 常见问题分析:窗口泄漏、事件丢失
- 从
- 总结与Q&A
1. 引言:为什么需要深入理解WMS?
各位同事,在日常开发中,我们面对的挑战往往不止于业务逻辑的实现。当遇到多窗口适配的诡异布局、悬浮窗权限的反复横跳、应用启动或转场时的莫名卡顿,甚至是触摸事件偶尔“灵异”丢失的问题时,我们是否感到束手无策,只能依靠试错或搜索碎片化的解决方案?
这些复杂UI场景和性能瓶颈的根源,往往深藏在Android Framework的核心——WindowManagerService(WMS) 之中。WMS是Android图形系统的“总调度中心”和“交通警察”,它管理者所有窗口的创建、布局、显示顺序以及它们与输入系统的交互。
本次培训旨在穿透API层面,深入Framework核心,系统性地揭示从应用视图请求到最终像素显示的完整链路。我们将聚焦WMS在其中扮演的核心角色,帮助大家建立起完整的窗口系统知识体系,从而在面对疑难杂症时,能够定位根因、精准施策。
2. WMS概览与架构定位
2.1 系统服务中的WMS
WMS是System Server中最早启动的核心服务之一。它在SystemServer的startOtherServices方法中被创建和启动。
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
// ...
traceBeginAndSlog("StartWindowManagerService");
// 注意:WMS的main方法运行在"android.display"线程,优先级高于"system_server"线程
wm = WindowManagerService.main(context, inputManager, ...);
traceEnd();
// ...
// 将WMS和IMS注册到ServiceManager
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
// ...
}
*代码示例:WMS在SystemServer中的启动 *
WMS的启动涉及多线程同步(system_server, android.display, android.ui),体现了其初始化对UI相关线程的优先级要求。
2.2 核心概念定义
在深入代码前,我们必须统一对以下几个核心抽象的理解:
Window(窗口):一个抽象的概念,不是实体,可以理解为绘制表面(Surface) 的载体或容器。每一个窗口都对应着一个用于绘制的Surface。在应用层,PhoneWindow是Window的唯一实现类。WindowManager:应用层与WMS通信的接口。它是一个Binder客户端,应用通过它发送添加、删除窗口的请求。其实现类WindowManagerImpl将工作委托给单例的WindowManagerGlobal。View:窗口的实体表现形式。窗口的内容正是通过View树来填充和呈现的。可以说,Window是View的载体,View是Window的内容。WindowToken:一个令牌。用于建立Binder通信的映射关系,并将一组相关的窗口(例如同一个Activity的所有窗口,包括主窗口和子窗口)组织在一起。对于Activity,它是AppWindowToken。WindowState:WMS内部用于描述一个窗口所有状态的真实对象。它保存了窗口的尺寸、位置、Z-order、是否可见、对应的Session、InputChannel等所有信息。它是WMS管理窗口的“活档案”。DisplayContent:用于描述一块逻辑屏幕。它管理着显示在这个屏幕上的所有窗口的根层级。WMS通过DisplayContent来管理多屏(如双屏、折叠屏)的窗口。
2.3 WMS核心职责
- 窗口管理:负责窗口的添加、删除、Z-order排序、焦点管理。
- Surface管理:作为“仲裁者”,为窗口分配
Surface,并协调应用与SurfaceFlinger的关系。 - 窗口动画:管理所有窗口切换、移动时的动画效果。
- 输入事件中转:配合
InputManagerService,将触摸或按键事件准确地分发给合适的窗口。
3. 窗口的生命周期管理
3.1 从ViewRootImpl到WindowState的旅程
以一个典型的Activity窗口创建为例,看看它是如何被WMS纳入管理的。
核心流程序列图:添加窗口
sequenceDiagram
participant App as 应用进程(UI Thread)
participant ViewRoot as ViewRootImpl
participant WMS as WindowManagerService
participant SF as SurfaceFlinger
App->>ViewRoot: 1. requestLayout()
ViewRoot->>ViewRoot: 2. scheduleTraversals()
ViewRoot->>WMS: 3. relayoutWindow() (Binder调用)
Note over WMS: 4. 创建/获取Surface
WMS->>SF: 5. createSurface() (通过SurfaceSession)
SF-->>WMS: 返回SurfaceControl
WMS-->>ViewRoot: 返回relayoutResult & Surface (Binder返回)
Note over ViewRoot: 6. 将Surface保存到mSurface
ViewRoot->>ViewRoot: 7. performMeasure/Layout/Draw
ViewRoot->>SF: 8. 通过Canvas/Skia渲染到Surface的BufferQueue
关键步骤详解:
- 发起请求:当View树需要布局时,
ViewRootImpl的requestLayout被调用,最终通过Binder调用进入WMS的relayoutWindow方法。 - WMS处理 (核心逻辑):
- 权限与合法性检查:WMS首先检查调用者的权限和窗口参数(
LayoutParams)是否合法。 - 创建/获取WindowState:如果是首次添加,WMS会创建一个
WindowState对象,并将其添加到全局的mWindowMap中,同时根据WindowToken建立层级关系。 - Surface分配:如果窗口需要新的绘图表面,WMS会通过
Session(内部封装了与SurfaceFlinger的SurfaceSession连接)请求SurfaceFlinger创建一个Layer(在WMS侧对应为SurfaceControl)。
- 权限与合法性检查:WMS首先检查调用者的权限和窗口参数(
- 返回与绘制:WMS将分配好的
Surface(实际上是SurfaceControl的句柄)通过Binder返回给应用层的ViewRootImpl。应用层拿到Surface后,便可以开始渲染内容。
3.2 核心数据结构:WindowState 解析
WindowState是WMS中最重要的数据结构,我们可以通过简化源码来理解其核心成员:
// frameworks/base/services/core/java/com/android/server/wm/WindowState.java
class WindowState extends WindowContainer<WindowState> {
// 指向持有该窗口的客户端Session (每个应用进程一个)
final Session mSession;
// 应用层 ViewRootImpl 的 W Binder对象,用于向应用进程通信
final IWindow mClient;
// 与该窗口关联的窗口令牌 (如 AppWindowToken)
final WindowToken mToken;
// 窗口的布局参数 (x, y, width, height, type, flags...)
final WindowManager.LayoutParams mAttrs;
// 窗口所属的逻辑屏幕
final DisplayContent mDisplayContent;
// 窗口在WMS侧控制的Surface句柄,用于设置位置、大小、层级等
SurfaceControl mSurfaceControl;
// 接收输入事件的通道
InputChannel mInputChannel;
// 窗口的帧大小和位置信息 (包含四个矩形:包含框架、内容框架、可见框架等)
final Rect mFrame = new Rect();
final Rect mContentFrame = new Rect();
// 窗口当前的Z-order 值
int mLayer;
// ... 以及其他大量状态和方法
}
*代码示例:WindowState核心成员变量 *
WindowState不仅保存了窗口的属性,其本身也参与到WindowContainer的层级管理中,构成了WMS内部对窗口树的描述。
4. 布局、动画与Surface管理
4.1 布局循环的核心:performSurfacePlacement
WMS的核心工作引擎是performSurfacePlacement(旧称performLayoutAndPlaceSurfacesLocked)。这个方法会在窗口状态发生变化(如添加窗口、更改大小、动画更新)时被触发。
它的主要任务是遍历所有DisplayContent及其下的WindowState,计算每个窗口最终的位置、大小和Z-order。然后,它会将这些变更通过SurfaceControl.Transaction提交给SurfaceFlinger。
4.2 窗口动画的管理者:WindowAnimator
WMS内部有一个WindowAnimator对象,专门负责管理所有窗口动画。
- 当一个窗口需要执行动画(如启动、退出、旋转)时,WMS会创建相应的动画对象(如
MoveAnimation,AlphaAnimation)。 WindowAnimator会定期(在VSync信号驱动下)更新动画状态,并再次触发performSurfacePlacement,将动画过程中的新位置、透明度等属性通过Transaction设置给SurfaceFlinger,从而实现流畅的动画效果。
4.3 Surface的申请与合成协调
WMS并不负责绘制,它只负责**“布局”和“定序”**。
- 应用侧Surface:由
ViewRootImpl持有,用于应用线程绘制UI。 - WMS侧SurfaceControl:由
WindowState持有,用于WMS控制该窗口在屏幕上的最终呈现属性。 - 与SurfaceFlinger的交互:WMS通过一系列的
Transaction,将窗口的位置、大小、旋转、透明度、Z-order等信息同步给SurfaceFlinger。SurfaceFlinger则根据这些信息,将所有窗口的Surface(图形缓冲区)进行混合(Compose),最终输出到屏幕硬件。
5. 输入事件的中转与分发
5.1 WMS作为IMS的中转站
InputManagerService(IMS)负责从内核读取原始输入事件,但它不知道这些事件该发给谁。这时,WMS作为窗口的管理者,就成为了理想的“导航员”。
5.2 关键流程序列图:触摸事件分发
sequenceDiagram
participant IMS as InputManagerService
participant WMS as WindowManagerService
participant Dispatcher as InputDispatcher (Native)
participant AppView as 目标窗口 (View)
IMS->>Dispatcher: 1. 读取并派发事件
Dispatcher->>WMS: 2. 查询目标窗口 (通过InputMonitor)
WMS-->>Dispatcher: 3. 返回焦点窗口及其InputChannel
Dispatcher->>Dispatcher: 4. 命中测试,确定目标
Dispatcher->>AppView: 5. 通过InputChannel发送事件 (Socket)
AppView->>AppView: 6. ViewRootImpl$WindowInputEventReceiver 处理
AppView->>AppView: 7. 事件分发 (dispatchTouchEvent)
5.3 命中测试与InputChannel
-
建立通道:在窗口添加时(
WMS.addWindow),如果窗口需要接收输入,WMS会为它创建一对InputChannel(基于Socket)。服务端的一端注册到IMS的InputDispatcher,客户端的一端通过Binder返回给ViewRootImpl,并封装成WindowInputEventReceiver。// WMS.addWindow 中创建InputChannel的片段 if (outInputChannel != null && (attrs.inputFeatures & ...) == 0) { String name = win.makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); // 创建Socket对 win.setInputChannel(inputChannels[0]); inputChannels[1].transferTo(outInputChannel); // 将客户端Channel返回 mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); // 注册服务端Channel }*代码示例:InputChannel的创建与注册 *
-
命中测试:当IMS的
InputDispatcher有事件到来时,它会调用WMS(通过InputMonitor)获取当前所有窗口的信息(Z-order、位置、焦点状态)。InputDispatcher执行命中测试,找到最合适的窗口,然后通过之前建立的Socket连接(InputChannel)直接将事件发送给目标应用进程。 -
应用内处理:应用进程的
WindowInputEventReceiver收到事件后,将其传递给ViewRootImpl,进而开始我们在应用层熟悉的View树事件分发流程。
6. 与关键系统服务的协同
6.1 WMS & AMS:状态同步
AMS和WMS是一对紧密协作的“好基友”。以Activity启动为例:
- AMS准备:AMS在启动一个Activity时,首先会调用WMS的
addAppToken,告诉WMS:“我要启动一个Activity了,这是它的令牌(AppWindowToken)”。WMS将其加入到mAppTokens列表中。 - WMS同步:当Activity在应用进程创建完毕,并通过
ViewRootImpl请求添加窗口时,WMS会通过AppWindowToken找到这个窗口属于哪个Activity,并将其与已有的Token关联起来。 - 状态回调:当窗口显示或隐藏时,WMS也会回调AMS的方法,通知它窗口的
finishedStarting、finishedPausing等状态,以便AMS继续执行生命周期的下一步。
6.2 UML简化类图:核心协作关系
下图展示了WMS、AMS及其核心内部类与周边服务的关系,有助于建立宏观印象。
classDiagram
class WindowManagerService {
- InputManagerService mInputManager
- ActivityManagerService mActivityManager
- WindowAnimator mAnimator
- HashMap~IBinder, WindowState~ mWindowMap
- ArrayList~AppWindowToken~ mAppTokens
+ addWindow()
+ relayoutWindow()
+ performSurfacePlacement()
}
class ActivityManagerService {
+ startActivity()
+ resumeTopActivity()
}
class InputManagerService {
- InputDispatcher mDispatcher
+ registerInputChannel()
}
class SurfaceFlinger {
+ createSurface()
+ setTransaction()
}
class WindowState {
- IWindow mClient
- WindowToken mToken
- SurfaceControl mSurfaceControl
- InputChannel mInputChannel
}
class AppWindowToken {
- IApplicationToken mAppToken
}
class DisplayContent {
- int mDisplayId
- WindowList mWindows
}
WindowManagerService --> ActivityManagerService : 持有引用
WindowManagerService --> InputManagerService : 持有引用
WindowManagerService --> SurfaceFlinger : Binder通信
WindowManagerService *-- WindowAnimator
WindowManagerService *-- WindowState : 管理 (mWindowMap)
WindowManagerService *-- AppWindowToken : 管理 (mAppTokens)
WindowManagerService *-- DisplayContent : 管理
WindowState --> WindowToken
AppWindowToken --|> WindowToken
DisplayContent --> WindowState : 包含
7. 高级主题与案例分析(可选)
7.1 从dumpsys window看窗口状态
adb shell dumpsys window是我们调试窗口问题的利器。通过它,我们可以看到:
Display信息:当前有几个逻辑屏幕,分辨率如何。Window Hierarchy:当前所有窗口的堆叠顺序,最上层的是焦点窗口。WindowState详情:每个窗口的包名、token、mSurfaceControl是否有效、mFrame坐标、mInputChannel状态等。Focus:当前焦点窗口是哪个。
案例分析: 当遇到窗口无法显示时,可以通过dumpsys window查看对应WindowState是否存在。如果存在,检查mSurfaceControl是否有效;如果不存在,说明窗口添加失败,可能是权限或token问题。
7.2 常见问题分析
-
问题1:悬浮窗无法显示或显示位置不对
- 可能原因:未正确申请
SYSTEM_ALERT_WINDOW权限;LayoutParams中的type设置错误;在Android 10+上,未对Display进行适配。 - WMS视角:检查
dumpsys window中该悬浮窗的WindowState是否存在,以及其mFrame和mAttrs.gravity是否符合预期。
- 可能原因:未正确申请
-
问题2:触摸事件“被窃取”或无法传递到目标View
- 可能原因:有其它窗口(如系统弹窗、输入法窗口)覆盖在目标窗口之上,但被设置为可触摸(
FLAG_NOT_TOUCH_MODAL处理不当);焦点窗口不是你期望的那个。 - WMS视角:通过
dumpsys window查看Window Hierarchy,确认Z-order的顺序。点击事件会首先发给Z-order最大的窗口。检查焦点窗口Focus是否正确。
- 可能原因:有其它窗口(如系统弹窗、输入法窗口)覆盖在目标窗口之上,但被设置为可触摸(
8. 总结与Q&A
总结
WMS作为Android GUI系统的“大脑”,其核心价值在于:
- 集中管理:通过
WindowState、WindowToken和DisplayContent,统一维护所有窗口的状态和层级。 - 协调调度:作为中心枢纽,协调应用进程的绘制请求(
relayoutWindow)、输入系统的派发请求(命中测试)以及SurfaceFlinger的合成请求(Transaction)。 - 状态同步:与AMS深度绑定,确保Activity的生命周期与窗口的显示状态同步。
深入理解WMS,不仅能帮助我们诊断疑难杂症,更能让我们对整个Android系统的设计哲学有更深刻的体会。