Android 窗口添加/删除流程 笔记

理解这两个流程,是掌握WMS工作原理的基础。为了方便理解,我们可以把它们想象成一个"入住"和"退房"的过程:应用进程是"房客",WMS是"酒店前台",SurfaceFlinger是"客房部"。

🏨 窗口添加流程:"办理入住"

一个窗口从创建到显示在屏幕上,需要经过"房客"发起请求和"酒店前台"登记分配房间两大阶段。

1. 客户端侧(房客发起请求)

这一阶段主要发生在应用进程,目标是准备好"入住手续"并跨进程通知WMS。

  1. 发起者 :通常始于Activity.onResume()之后,或者手动调用WindowManager.addView()(如创建悬浮窗)。
  2. 创建ViewRootImpl :WindowManagerImpl将工作委托给单例的WindowManagerGlobal,后者创建ViewRootImpl对象。ViewRootImpl是应用进程与WMS通信的桥梁,也是View树开始绘制的起点。
  3. 建立通信会话 :ViewRootImpl在构造时会通过WindowManagerGlobal.getWindowSession(),经过一系列Binder调用,在WMS所在进程(system_server)中为当前应用进程获取或创建一个Session对象。这个Session代表了该应用与WMS之间用于窗口操作的会话通道。
  4. 发起添加请求 :ViewRootImpl.setView()方法中,会调用mWindowSession.addToDisplay(),将添加窗口的请求通过Binder发送给WMS。这里传递的关键参数包括:代表应用窗口回调的mWindow(一个IWindow.Stub Binder对象)和窗口布局参数WindowManager.LayoutParams。

2. WMS侧(酒店前台登记)

WMS接收到请求后,开始进行核心的处理和登记工作,主要入口是WindowManagerService.addWindow()方法。

这个过程非常关键,我们可以通过一个时序图来直观地看到主要步骤的流转:

sequenceDiagram participant App as 应用进程 participant WMS as WindowManagerService participant SF as SurfaceFlinger App->>WMS: 1. addWindow() (通过Session) activate WMS WMS->>WMS: 2. 前置校验 (权限、Token、参数) WMS->>WMS: 3. 创建WindowState<br/>(存入mWindowMap) WMS->>WMS: 4. 关联Token (WindowToken/AppWindowToken) WMS->>SF: 5. 创建SurfaceSession<br/>(进程级连接) 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()<br/>(计算最终Z轴顺序、位置) WMS->>SF: 10. 提交事务(Transaction)<br/>设置图层属性 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作为窗口管理核心的最基本操作。它通过与AMS协作管理窗口生命周期,通过与SurfaceFlinger协作管理窗口的绘制表面,通过与IMS协作管理窗口的输入事件通道,完美地诠释了它在上次讲解中提到的"四大核心职责"。

相关推荐
三少爷的鞋7 小时前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
Dovis(誓平步青云)10 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码12 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程12 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程15 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程17 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程17 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程17 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓17 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程17 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer