本文从 WindowManagerService(WMS)视角解析 Activity 启动流程,揭示窗口创建、层级管理及跨进程交互的核心逻辑,帮助理解 Android 界面显示的底层机制。
一、Activity 启动的双阶段视角:系统进程与应用进程的协作
Activity 启动涉及两个核心阶段,分别在system_server 进程(系统服务)和应用进程(UI 线程)中完成,通过Binder 跨进程通信衔接。
阶段一:system_server 进程 ——WMS 的窗口预处理
当 AMS 触发 Activity 启动时,WMS 首先介入处理窗口相关逻辑:
-
创建任务与令牌:moveTaskToTop & addAppToken
moveTaskToTop
:将目标 Activity 所属任务(Task)移至窗口栈顶部,确保其显示优先级。addAppToken
:创建AppWindowToken
对象,关联 Activity 与窗口令牌(Token),记录窗口属性(如全屏、方向),存储于 WMS 的mTokenMap
。
类比:AppWindowToken
如同活动的 “入场券”,记录活动的显示规则,WMS 通过它管理所有窗口的状态。
-
启动窗口(StartingWindow)的显示
- 若应用进程未启动,WMS 创建临时启动窗口(类型为
TYPE_APPLICATION_STARTING
),显示应用图标或主题背景,避免黑屏。 - 通过
setAppStartingWindow
发送消息到android.display 线程,创建启动窗口视图并添加到 WMS。
作用:在真实窗口就绪前提供过渡界面,提升用户体验。
- 若应用进程未启动,WMS 创建临时启动窗口(类型为
-
窗口过渡动画准备
prepareAppTransition
设置动画类型(如淡入淡出),并启动 5 秒超时机制,防止动画阻塞。
阶段二:应用进程 ——UI 线程的窗口构建
当应用进程创建后,ActivityThread(UI 线程)开始构建 Activity 界面,并与 WMS 交互完成窗口添加:
-
Activity 初始化与窗口创建
performLaunchActivity
:创建 Activity 实例,调用attach
方法初始化PhoneWindow
(窗口实现类)和WindowManagerImpl
(窗口管理接口)。PhoneWindow
:作为 Activity 的根窗口,后续通过setContentView
设置的布局均添加到此窗口。WindowManagerImpl
:通过 Binder 获取 WMS 代理,用于跨进程调用窗口管理方法(如addView
)。
-
窗口添加到 WMS:ViewRootImpl 的桥梁作用
ViewRootImpl
:连接应用视图与 WMS 的核心类,创建时通过getWindowSession
获取 WMS 的Session
代理(跨进程通信通道)。setView
方法:通过 Binder 调用 WMS 的addWindow
,将视图(如 DecorView)添加到系统窗口列表。
关键步骤:
java
// 应用进程调用(伪代码) viewRootImpl.setView(decorView, layoutParams); // 触发WMS的addWindow,创建WindowState对象
-
WMS 的窗口状态管理
WindowState
:代表一个窗口,记录位置、层级、可见性等状态,存储于 WMS 的mWindowMap
。- 焦点更新:通过
updateFocusedWindowLocked
确定当前聚焦窗口,确保输入事件分发到正确窗口。
类比:WindowState
如同窗口的 “档案”,WMS 根据档案排序、显示和隐藏窗口。
二、核心类与机制解析
1. AppWindowToken:窗口的身份标识
- 作用:关联 Activity 与窗口,记录窗口所属任务(Task)、可见性、动画状态等。
- 生命周期:随 Activity 启动创建,随 Activity 销毁移除,存储于 WMS 的
mTokenMap
。
2. WindowState:窗口的运行时状态
-
关键属性:
mAppToken
:关联的AppWindowToken
。mInputChannel
:与输入系统(IMS)通信的通道,用于接收触摸等事件。mWinAnimator
:管理窗口动画和 Surface 渲染。
-
创建时机:在 WMS 的
addWindow
中创建,对应应用进程的ViewRootImpl
请求。
3. 跨进程通信:Binder 与 Session
-
Session
:WMS 为每个应用进程创建的 Binder 服务端,应用通过IWindowSession
代理(WindowManagerImpl
持有)与 WMS 交互。 -
核心调用链:
plaintext
应用进程调用ViewRootImpl.setView() → Binder调用Session.addToDisplay() → WMS.addWindow() 创建WindowState
三、典型流程时序图
四、关键问题与设计考量
1. 为什么需要启动窗口(StartingWindow)?
- 场景:应用进程启动较慢时,显示启动窗口(主题背景或图标)避免黑屏,提升用户感知。
- 实现:启动窗口是临时窗口(
TYPE_APPLICATION_STARTING
),不可触摸,真实窗口就绪后通过动画替换。
2. 窗口层级如何管理?
- Z 轴排序:WMS 根据窗口类型(如系统窗口、应用窗口)和
setZOrder
设置层级,确保系统窗口(如状态栏)始终在顶层。 - 焦点窗口:通过
computeFocusedWindowLocked
遍历窗口列表,找到可接收按键事件的最顶层窗口。
3. 跨进程通信如何保证效率?
- Binder 优化:使用异步 Binder 调用减少阻塞,如
sendMessageAtFrontOfQueue
优先处理紧急消息(如启动窗口创建)。 - 线程隔离:WMS 核心逻辑在
android.display
线程执行,避免 UI 线程阻塞。
五、总结:WMS 在 Activity 启动中的角色
WMS 作为 Android 窗口管理的核心,在 Activity 启动中承担以下职责:
-
任务与令牌管理:创建任务栈和窗口令牌,维护窗口所属关系。
-
临时界面过渡:显示启动窗口,平滑过渡到真实界面。
-
跨进程窗口添加:通过 Binder 接收应用进程的窗口请求,创建并管理
WindowState
。 -
焦点与层级控制:确保当前活动窗口获取输入焦点,正确渲染层级顺序。
理解 WMS 的窗口管理逻辑,有助于优化应用启动速度、处理多窗口冲突,以及定制系统级窗口功能(如悬浮窗、锁屏界面)。