WMS视角解析 Activity 启动流程

0 阅读4分钟

本文从 WindowManagerService(WMS)视角解析 Activity 启动流程,揭示窗口创建、层级管理及跨进程交互的核心逻辑,帮助理解 Android 界面显示的底层机制。

一、Activity 启动的双阶段视角:系统进程与应用进程的协作

Activity 启动涉及两个核心阶段,分别在system_server 进程(系统服务)应用进程(UI 线程)中完成,通过Binder 跨进程通信衔接。

阶段一:system_server 进程 ——WMS 的窗口预处理

当 AMS 触发 Activity 启动时,WMS 首先介入处理窗口相关逻辑:

  1. 创建任务与令牌:moveTaskToTop & addAppToken

    • moveTaskToTop:将目标 Activity 所属任务(Task)移至窗口栈顶部,确保其显示优先级。
    • addAppToken:创建AppWindowToken对象,关联 Activity 与窗口令牌(Token),记录窗口属性(如全屏、方向),存储于 WMS 的mTokenMap
      类比AppWindowToken如同活动的 “入场券”,记录活动的显示规则,WMS 通过它管理所有窗口的状态。
  2. 启动窗口(StartingWindow)的显示

    • 若应用进程未启动,WMS 创建临时启动窗口(类型为TYPE_APPLICATION_STARTING),显示应用图标或主题背景,避免黑屏。
    • 通过setAppStartingWindow发送消息到android.display 线程,创建启动窗口视图并添加到 WMS。
      作用:在真实窗口就绪前提供过渡界面,提升用户体验。
  3. 窗口过渡动画准备

    • prepareAppTransition设置动画类型(如淡入淡出),并启动 5 秒超时机制,防止动画阻塞。

阶段二:应用进程 ——UI 线程的窗口构建

当应用进程创建后,ActivityThread(UI 线程)开始构建 Activity 界面,并与 WMS 交互完成窗口添加:

  1. Activity 初始化与窗口创建

    • performLaunchActivity:创建 Activity 实例,调用attach方法初始化PhoneWindow(窗口实现类)和WindowManagerImpl(窗口管理接口)。
    • PhoneWindow:作为 Activity 的根窗口,后续通过setContentView设置的布局均添加到此窗口。
    • WindowManagerImpl:通过 Binder 获取 WMS 代理,用于跨进程调用窗口管理方法(如addView)。
  2. 窗口添加到 WMS:ViewRootImpl 的桥梁作用

    • ViewRootImpl:连接应用视图与 WMS 的核心类,创建时通过getWindowSession获取 WMS 的Session代理(跨进程通信通道)。
    • setView方法:通过 Binder 调用 WMS 的addWindow,将视图(如 DecorView)添加到系统窗口列表。
      关键步骤

    java

    // 应用进程调用(伪代码)
    viewRootImpl.setView(decorView, layoutParams); 
    // 触发WMS的addWindow,创建WindowState对象
    
  3. 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
    

三、典型流程时序图

wms1.png

四、关键问题与设计考量

1. 为什么需要启动窗口(StartingWindow)?

  • 场景:应用进程启动较慢时,显示启动窗口(主题背景或图标)避免黑屏,提升用户感知。
  • 实现:启动窗口是临时窗口(TYPE_APPLICATION_STARTING),不可触摸,真实窗口就绪后通过动画替换。

2. 窗口层级如何管理?

  • Z 轴排序:WMS 根据窗口类型(如系统窗口、应用窗口)和setZOrder设置层级,确保系统窗口(如状态栏)始终在顶层。
  • 焦点窗口:通过computeFocusedWindowLocked遍历窗口列表,找到可接收按键事件的最顶层窗口。

3. 跨进程通信如何保证效率?

  • Binder 优化:使用异步 Binder 调用减少阻塞,如sendMessageAtFrontOfQueue优先处理紧急消息(如启动窗口创建)。
  • 线程隔离:WMS 核心逻辑在android.display线程执行,避免 UI 线程阻塞。

五、总结:WMS 在 Activity 启动中的角色

WMS 作为 Android 窗口管理的核心,在 Activity 启动中承担以下职责:

  1. 任务与令牌管理:创建任务栈和窗口令牌,维护窗口所属关系。

  2. 临时界面过渡:显示启动窗口,平滑过渡到真实界面。

  3. 跨进程窗口添加:通过 Binder 接收应用进程的窗口请求,创建并管理WindowState

  4. 焦点与层级控制:确保当前活动窗口获取输入焦点,正确渲染层级顺序。

理解 WMS 的窗口管理逻辑,有助于优化应用启动速度、处理多窗口冲突,以及定制系统级窗口功能(如悬浮窗、锁屏界面)。