Android系统中WMS原理解析

272 阅读9分钟

WMS是Android图形和窗口系统的核心枢纽,其复杂性和重要性极高。理解WMS是深入理解Android UI框架、多任务、性能优化乃至安全机制的关键。

核心定位: WMS是系统级服务,运行在system_server进程中。它是Android窗口管理策略的核心执行者,负责:

  1. 窗口生命周期管理: 创建、添加、更新、删除窗口。
  2. 窗口层级管理: 确定窗口的Z-order(前后顺序)、可见性、透明度、动画效果。
  3. 布局计算: 根据窗口属性、状态、系统策略计算窗口的位置和大小。
  4. 输入事件分发: 将触摸、按键等输入事件精准路由到正确的窗口(与InputManagerService紧密协作)。
  5. 动画管理: 协调窗口的转场动画、属性动画。
  6. 多窗口模式支持: 分屏、画中画、自由窗口等模式的核心实现者。
  7. 屏幕旋转管理: 处理屏幕方向改变时的窗口重建和布局。
  8. 壁纸管理: 特殊窗口(壁纸)的显示策略。
  9. 聚焦窗口管理: 确定哪个窗口当前拥有输入焦点。
  10. 与SurfaceFlinger交互: 管理窗口对应的Surface,通过SurfaceControl控制其属性,并最终驱动图形合成。

核心架构与关键组件:

  1. 客户端接口: WindowManagerGlobal / WindowManagerImpl (App端)

    • 应用通过getSystemService(Context.WINDOW_SERVICE)获取WindowManager实例。
    • WindowManagerImpl将应用请求(如addView())通过Binder IPC传递给WMS。
    • 也负责在主线程(UI线程)执行ViewRootImpl相关的操作。
  2. 服务端核心: WindowManagerService (WMS)

    • 窗口容器树:
      • DisplayContent 代表一个物理或虚拟显示设备(屏幕)。是窗口管理的顶级容器。
      • Task 代表一个用户任务(通常对应一个应用栈,但多窗口模式下可能包含多个Activity)。
      • ActivityRecord 代表一个Activity实例。包含该Activity的所有窗口。
      • WindowToken 一种令牌,用于将一组窗口关联到特定的实体(如Activity、壁纸、输入法)。是权限和策略控制的关键点。
      • WindowState WMS内部表示一个窗口的核心对象。包含窗口的所有状态信息:
        • 关联的Session (客户端连接)
        • 关联的WindowToken
        • 父容器 (Task, ActivityRecord)
        • 窗口属性 (WindowManager.LayoutParams - type, flags, width/height, gravity, x/y, alpha, etc.)
        • Z-order计算相关的值 (mBaseLayer, mSubLayer, mAnimLayer)
        • 可见性 (mViewVisibility, mSurfaceShown)
        • 输入通道 (InputChannel)
        • 关联的SurfaceControl (与图形合成交互的关键句柄)
        • 动画状态
        • 聚焦状态
        • 等等。
    • 窗口添加流程 (addWindow):
      1. 权限和参数校验 (LayoutParams.type的有效性等)。
      2. 查找或创建对应的WindowToken (根据token或type)。
      3. 创建WindowState对象,并将其添加到正确的容器 (DisplayContent -> Task -> ActivityRecord -> WindowToken) 中。
      4. 为该窗口创建InputChannel (用于接收输入事件)。
      5. 通过WindowStateSurfaceSession创建SurfaceControl (最终用于在SurfaceFlinger中创建Surface)。
      6. 触发布局 (performLayoutAndPlaceSurfacesLocked)。
    • 布局流程 (performLayoutAndPlaceSurfacesLocked): 这是WMS最核心、最频繁的流程之一。
      • 收集窗口状态 (buildWindowListLocked): 遍历窗口容器树,收集所有需要考虑的WindowState,并根据Z-order、类型、父容器等进行初步排序。
      • 计算可见性 (computeWindowLayers): 计算每个窗口的最终Z轴层级 (mLayer, mAnimLayer)。考虑:
        • 窗口类型 (SYSTEM_ALERT > APPLICATION > STATUS_BAR > WALLPAPER)
        • 父容器的层级
        • 当前正在应用的动画
        • FLAG_LAYER相关的标志
      • 计算位置和大小 (performLayoutLockedInner):
        • 根据LayoutParams (gravity, width/height, x/y offsets, flags)、父容器大小、系统状态栏/导航栏高度、安全区域、Ime状态等,计算每个窗口的最终Frame (位置和大小)。
        • 处理FLAG_LAYOUT_IN_SCREEN, FLAG_LAYOUT_INSET_DECOR等标志的影响。
        • 处理窗口大小变化 (CONFIGURATION_CHANGED)。
      • 应用布局 (applySurfaceChangesTransaction): 这是与图形合成交互的关键步骤。
        • 遍历WindowState列表。
        • 检查窗口状态变化(位置、大小、可见性、透明度、动画等)。
        • 使用SurfaceControl.Transaction (或旧的SurfaceControl.openTransaction()/closeTransaction()) 批量设置SurfaceControl的属性:
          • setPosition (x, y)
          • setSize (width, height)
          • setLayer (Z-order)
          • setAlpha (透明度)
          • setMatrix (旋转/缩放变换)
          • setVisibility (显示/隐藏)
          • reparent (改变父Surface)
        • 对于需要创建新Surface的窗口(首次添加、配置改变后重建),执行relayoutWindow() -> createSurfaceControl()
        • 对于需要销毁的窗口,销毁SurfaceControl
        • 事务提交: 将累积的Transaction提交给SurfaceFlinger执行。批量提交是优化性能的关键!
    • 输入事件分发:
      • InputManagerService (IMS) 从驱动读取原始输入事件。
      • IMS根据输入事件发生的屏幕坐标,询问WMS:哪个窗口应该接收这个事件?
      • WMS通过findFocusedWindowTargetsLocked遍历其窗口树(按Z-order从高到低),根据窗口的Frame(位置大小)、可见性、FLAG_NOT_TOUCHABLE等标志,找到最顶部的、可接收触摸事件的窗口。
      • WMS将找到的窗口对应的InputChannel返回给IMS。
      • IMS将输入事件写入该InputChannel
      • 应用端的ViewRootImpl通过关联的InputEventReceiverInputChannel读取事件,并分发给视图树。
    • 动画系统:
      • WMS自身管理窗口级别的动画(如Activity转场动画、窗口打开/关闭动画)。
      • 使用WindowStateAnimator对象来管理每个窗口的动画状态。
      • 动画会改变窗口的mAnimLayer (临时Z-order)、透明度、位置、缩放等属性。
      • 动画的执行会触发连续的布局和Surface属性更新请求 (scheduleAnimationLocked -> mChoreographer.postCallback -> performLayoutAndPlaceSurfacesLocked)。
      • 与应用内的属性动画 (ObjectAnimator) 协作:当应用视图树做属性动画时,ViewRootImpl会通过scheduleTraversals()请求重绘,并可能通过relayoutWindow()请求WMS更新窗口Surface的属性(如位置变化导致窗口移动)。
    • 多窗口模式:
      • 分屏: WMS将屏幕划分为不同的区域 (Task容器),每个区域容纳一个Task。管理这些Task容器的位置、大小、Z-order以及它们内部窗口的布局。
      • 画中画: 将特定的ActivityRecord标记为PIP模式。WMS将其放入一个特殊的容器,管理其固定大小、可拖动位置、特殊的Z-order(始终在最上层特定区域之下)以及焦点策略(点击PIP窗口时切换到全屏)。
      • 自由窗口: 更复杂的模式,窗口可以自由缩放和移动。WMS需要动态计算每个自由窗口的Frame,处理窗口间的Z-order调整(如点击置顶),以及复杂的输入事件路由。
    • 与SurfaceFlinger的关系:
      • WMS不直接进行图形绘制,它管理的是Surface元数据(位置、大小、Z-order、可见性、变换)。
      • 每个窗口对应一个SurfaceControl(由WMS通过SurfaceSession创建)。
      • WMS通过SurfaceControl.Transaction设置SurfaceControl的属性。
      • 应用(通过SurfaceViewTextureView)向Surface写入图形内容 (BufferQueue Producer)。
      • SurfaceFlinger作为合成器 (Compositor),根据WMS设置的SurfaceControl属性(层级、位置等)和Surface的内容(BufferQueue Consumer),决定何时以及如何将这些Surface合成到最终的显示帧上。
      • 关键点: WMS控制“在哪里显示什么”,应用负责“画什么”,SurfaceFlinger负责“把它们拼起来显示”。

设计哲学与关键挑战:

  1. 策略与机制分离 (Policy/Mechanism Separation):

    • 机制: WMS核心提供了强大的窗口管理基础功能(布局计算、Z-order排序、Surface控制、输入路由)。
    • 策略: 具体的窗口行为规则(如哪些窗口类型可以重叠、特定系统窗口的位置、多窗口模式的交互逻辑)很大程度上由PhoneWindowManager实现。这允许OEM厂商在不修改WMS核心的情况下定制UI行为。
  2. 性能与响应性:

    • 布局计算优化: 增量更新(只处理脏区域/脏窗口)、高效的数据结构(窗口容器树)、避免不必要的重布局。
    • 事务批处理: 将多个Surface属性的修改打包在一个Transaction中提交给SurfaceFlinger,减少IPC和合成器调度开销。
    • 异步化: 将部分工作(如动画)委托给Choreographer在主线程之外调度执行。
    • 输入延迟: 精确高效的输入事件路由对用户体验至关重要。WMS与IMS的紧密协作和高效的InputChannel机制是关键。
  3. 安全与隔离:

    • 窗口令牌 (WindowToken): 确保只有拥有正确令牌的客户端才能操作属于该令牌的窗口(防止恶意应用随意操作其他应用的窗口)。
    • 权限检查: 对特定的窗口类型(如TYPE_SYSTEM_ALERT, TYPE_APPLICATION_OVERLAY)需要SYSTEM_ALERT_WINDOW权限。
    • 输入事件目标检查: 确保事件只发送给拥有对应窗口和InputChannel的合法客户端。
  4. 复杂性管理:

    • 层级化容器模型: 使用DisplayContent, Task, ActivityRecord, WindowToken, WindowState等对象清晰地组织窗口的从属和层级关系。
    • 状态机: WindowState等对象使用状态机管理复杂的生命周期和状态转换(如NO_SURFACE, DRAW_PENDING, COMMIT_DRAW_PENDING, READY_TO_SHOW, HAS_DRAWN)。

深入优化点:

  1. Transaction 合并:performLayoutAndPlaceSurfacesLocked的一次执行中,所有需要更新的SurfaceControl属性变化会累积到一个Transaction对象中。只有最终需要提交的变化才会真正发送给SurfaceFlinger。中间状态的多次修改会被覆盖(如连续设置位置和大小,最终只提交最新的值)。
  2. 同步屏障: 当应用调用invalidate()requestLayout()时,ViewRootImpl会通过Choreographer安排一次遍历 (performTraversals)。在performTraversals中,会先relayoutWindow(如果需要更新窗口大小/位置/Insets等,这会触发WMS布局和Surface属性更新),然后再进行Measure、Layout、Draw。Choreographer确保了UI更新、WMS更新、VSync信号的同步。
  3. SurfaceControl 生命周期: WMS负责SurfaceControl的创建和销毁。当窗口不再需要显示(或被销毁)时,WMS会销毁其SurfaceControl,通知SurfaceFlinger释放相关资源。应用端的Surface对象持有对SurfaceControl的引用,当应用释放Surface时,会通过Binder通知WMS减少引用计数,最终由WMS决定何时真正销毁SurfaceControl
  4. Insets 控制: WMS计算并分发系统栏(状态栏、导航栏)占据的区域信息 (InsetsState)。应用通过ViewCompat.setOnApplyWindowInsetsListener获取这些信息,用于调整自身内容的布局(如避免被系统栏遮挡)。WMS根据窗口的LayoutParams决定哪些窗口需要避开哪些Insets。

总结:

WindowManagerService是Android图形和窗口系统的中央控制器策略执行引擎。它:

  • 管理着屏幕上的所有视觉元素(窗口)的生命周期、层级关系和视觉表现。
  • 精确地计算着每个窗口的位置和大小。
  • 智能地将用户的输入事件路由到正确的目标。
  • 协调着窗口动画和多窗口模式的复杂交互。
  • 作为应用与图形合成器 (SurfaceFlinger) 之间的桥梁,控制着图形缓冲区 (Surface) 的显示属性。

其设计体现了对性能、安全性、灵活性和可扩展性的极致追求。理解WMS的内部运作机制,对于解决复杂的UI问题(如窗口遮挡、触摸事件穿透、动画卡顿、多窗口适配)、进行深度性能优化以及定制Android系统UI行为都至关重要。其代码庞大而复杂(核心代码超过数万行),但其核心逻辑围绕窗口容器树布局计算事务管理输入路由展开,掌握了这些关键概念就掌握了WMS的精髓。