理解这两个流程,是掌握WMS工作原理的基础。为了方便理解,我们可以把它们想象成一个"入住"和"退房"的过程:应用进程是"房客",WMS是"酒店前台",SurfaceFlinger是"客房部"。
🏨 窗口添加流程:"办理入住"
一个窗口从创建到显示在屏幕上,需要经过"房客"发起请求和"酒店前台"登记分配房间两大阶段。
1. 客户端侧(房客发起请求)
这一阶段主要发生在应用进程,目标是准备好"入住手续"并跨进程通知WMS。
- 发起者 :通常始于
Activity.onResume()之后,或者手动调用WindowManager.addView()(如创建悬浮窗)。 - 创建ViewRootImpl :
WindowManagerImpl将工作委托给单例的WindowManagerGlobal,后者创建ViewRootImpl对象。ViewRootImpl是应用进程与WMS通信的桥梁,也是View树开始绘制的起点。 - 建立通信会话 :
ViewRootImpl在构造时会通过WindowManagerGlobal.getWindowSession(),经过一系列Binder调用,在WMS所在进程(system_server)中为当前应用进程获取或创建一个Session对象。这个Session代表了该应用与WMS之间用于窗口操作的会话通道。 - 发起添加请求 :
ViewRootImpl.setView()方法中,会调用mWindowSession.addToDisplay(),将添加窗口的请求通过Binder发送给WMS。这里传递的关键参数包括:代表应用窗口回调的mWindow(一个IWindow.StubBinder对象)和窗口布局参数WindowManager.LayoutParams。
2. WMS侧(酒店前台登记)
WMS接收到请求后,开始进行核心的处理和登记工作,主要入口是WindowManagerService.addWindow()方法。
这个过程非常关键,我们可以通过一个时序图来直观地看到主要步骤的流转:
(存入mWindowMap) WMS->>WMS: 4. 关联Token (WindowToken/AppWindowToken) WMS->>SF: 5. 创建SurfaceSession
(进程级连接) WMS-->>App: 返回添加结果 deactivate WMS Note over App,SF: 应用收到结果后,开始绘制UI App->>WMS: 6. relayoutWindow() activate WMS WMS->>SF: 7. 分配Surface (创建图层) SF-->>WMS: 返回Surface对象 WMS-->>App: 返回Surface及窗口位置信息 deactivate WMS Note over App: 应用将UI内容绘制到Surface App->>WMS: 8. finishDrawingWindow() activate WMS WMS->>WMS: 9. performLayoutAndPlaceSurfacesLocked()
(计算最终Z轴顺序、位置) WMS->>SF: 10. 提交事务(Transaction)
设置图层属性 deactivate WMS
让我们结合时序图,详细分解WMS侧的每一个核心步骤:
-
步骤1-2:前置校验与准备 :
addWindow()执行一系列严格的检查,包括:- 权限:检查调用者是否有权限添加指定类型的窗口(如系统窗口需要特殊权限)。
- Token验证 :对于应用窗口,需要验证传入的Token是否对应一个有效的、正在启动的Activity(
AppWindowToken)。对于子窗口,需要验证其父窗口是否存在。 - 重复检查 :确保同一个窗口(通过
IWindow标识)没有被重复添加。
-
步骤3:创建"房间登记表"------WindowState :校验通过后,WMS会为这个新窗口创建一个
WindowState对象。这是窗口在WMS中的灵魂 ,它记录了窗口的所有状态:大小、位置、包名、对应的Session、IWindow代理等。这个对象会被加入全局的mWindowMap中进行管理。 -
步骤4:关联"房客组"------WindowToken :将新创建的
WindowState与一个WindowToken(或其子类AppWindowToken)关联。WindowToken代表一组相关窗口(例如一个Activity和它弹出的所有对话框),这有助于WMS对它们进行统一管理。 -
步骤5-7:申请"房间钥匙"------Surface :窗口需要一块画布才能绘制内容。WMS并不直接绘制,而是通过
relayoutWindow()流程,向SurfaceFlinger申请一块Surface。这个过程会建立一个SurfaceSession连接,并由SurfaceFlinger创建对应的图层(Layer),最终将Surface的句柄返回给应用进程。 -
步骤8-10:最终"入住" :应用进程拿到
Surface后,就可以将UI绘制上去。绘制完成后,通过finishDrawingWindow()通知WMS。WMS的核心布局函数performLayoutAndPlaceSurfacesLocked()会被触发,它会综合所有窗口的状态,计算每个窗口最终的Z轴顺序(层叠关系)、位置和大小,并将这些结果通过SurfaceControl.Transaction提交给SurfaceFlinger,最终由SurfaceFlinger合成并显示到屏幕上。
🧹 窗口删除流程:"办理退房"
窗口的删除通常由两种原因触发:用户主动操作(如finish() Activity)或系统因资源紧张而回收。
1. 显式删除(用户主动退房)
- 触发点 :调用
WindowManager.removeView()或ViewManager.removeView(),或Activity正常结束(finish())。 - 流程 :
- 应用层 :
WindowManagerImpl.removeView()同样委托给WindowManagerGlobal,找到对应的ViewRootImpl,发起跨进程删除请求。 - WMS处理 :调用
WindowManagerService.removeWindow()。WMS会从mWindowMap中移除对应的WindowState,并销毁与之关联的Surface,释放图形内存。同时,与该窗口关联的InputChannel也会被断开,确保不再接收输入事件。 - 收尾 :触发
performLayoutAndPlaceSurfacesLocked(),重新计算剩余窗口的布局和焦点。
- 应用层 :
2. 隐式删除(系统强制退房)
- 触发点 :当系统内存不足,AMS(ActivityManagerService)决定终止一个进程时,它会回调WMS的
removeAppToken()方法。 - 流程 :
- WMS找到与该应用
AppWindowToken关联的所有WindowState。 - 批量清理:一次性移除所有这些窗口,执行上述的资源释放和重排流程。这确保了即使应用进程被异常杀死,其窗口也不会残留在屏幕上,防止内存泄漏。
- WMS找到与该应用
窗口的添加与删除,是WMS作为窗口管理核心的最基本操作。它通过与AMS协作管理窗口生命周期,通过与SurfaceFlinger协作管理窗口的绘制表面,通过与IMS协作管理窗口的输入事件通道,完美地诠释了它在上次讲解中提到的"四大核心职责"。