android Surface绘制状态流转-WindowStateAnimator

java 复制代码
/**
 * Keep track of animations and surface operations for a single WindowState.
 **/
class WindowStateAnimator {
    /** This is set when there is no Surface */
    static final int NO_SURFACE = 0;
    /** This is set after the Surface has been created but before the window has been drawn. During
     * this time the surface is hidden. */
    static final int DRAW_PENDING = 1;
    /** This is set after the window has finished drawing for the first time but before its surface
     * is shown.  The surface will be displayed when the next layout is run. */
    static final int COMMIT_DRAW_PENDING = 2;
    /** This is set during the time after the window's drawing has been committed, and before its
     * surface is actually shown.  It is used to delay showing the surface until all windows in a
     * token are ready to be shown. */
    static final int READY_TO_SHOW = 3;
    /** Set when the window has been shown in the screen the first time. */
    static final int HAS_DRAWN = 4;

WindowStateAnimator 是 WMS 中每个窗口对应的 Surface 动画与绘制状态管理器。它维护了从 Surface 创建到最终显示到屏幕的完整生命周期,核心职责包括:

职责 说明
Surface 生命周期管理 创建 (createSurfaceLocked)、销毁 (destroySurfaceLocked) 窗口的 SurfaceControl
绘制状态机 管理 mDrawState 的 5 个状态流转(核心机制)
Surface 属性控制 控制透明度 (setAlpha)、可见性 (show/hide)、不透明度 (setOpaque)、颜色空间等
入场动画 applyEnterAnimationLocked() 为窗口首次显示播放动画
Transaction 提交 finishDrawingLocked() 将客户端的 postDrawTransaction 合并到 getSyncTransaction()

完整时序图
SurfaceControl WindowStateAnimator(绘制状态机) WindowState WindowManagerService 应用客户端(ViewRootImpl) SurfaceControl WindowStateAnimator(绘制状态机) WindowState WindowManagerService 应用客户端(ViewRootImpl) #mermaid-svg-5Todbye6GHBBaUwF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5Todbye6GHBBaUwF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5Todbye6GHBBaUwF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5Todbye6GHBBaUwF .error-icon{fill:#552222;}#mermaid-svg-5Todbye6GHBBaUwF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5Todbye6GHBBaUwF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5Todbye6GHBBaUwF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5Todbye6GHBBaUwF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5Todbye6GHBBaUwF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5Todbye6GHBBaUwF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5Todbye6GHBBaUwF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5Todbye6GHBBaUwF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5Todbye6GHBBaUwF .marker.cross{stroke:#333333;}#mermaid-svg-5Todbye6GHBBaUwF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5Todbye6GHBBaUwF p{margin:0;}#mermaid-svg-5Todbye6GHBBaUwF .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-5Todbye6GHBBaUwF text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-5Todbye6GHBBaUwF .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-5Todbye6GHBBaUwF .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-5Todbye6GHBBaUwF .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-5Todbye6GHBBaUwF .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-5Todbye6GHBBaUwF #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-5Todbye6GHBBaUwF .sequenceNumber{fill:white;}#mermaid-svg-5Todbye6GHBBaUwF #sequencenumber{fill:#333;}#mermaid-svg-5Todbye6GHBBaUwF #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-5Todbye6GHBBaUwF .messageText{fill:#333;stroke:none;}#mermaid-svg-5Todbye6GHBBaUwF .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-5Todbye6GHBBaUwF .labelText,#mermaid-svg-5Todbye6GHBBaUwF .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-5Todbye6GHBBaUwF .loopText,#mermaid-svg-5Todbye6GHBBaUwF .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-5Todbye6GHBBaUwF .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-5Todbye6GHBBaUwF .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-5Todbye6GHBBaUwF .noteText,#mermaid-svg-5Todbye6GHBBaUwF .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-5Todbye6GHBBaUwF .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-5Todbye6GHBBaUwF .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-5Todbye6GHBBaUwF .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-5Todbye6GHBBaUwF .actorPopupMenu{position:absolute;}#mermaid-svg-5Todbye6GHBBaUwF .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-5Todbye6GHBBaUwF .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-5Todbye6GHBBaUwF .actor-man circle,#mermaid-svg-5Todbye6GHBBaUwF line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-5Todbye6GHBBaUwF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 阶段1: Surface 创建 (NO_SURFACE → DRAW_PENDING) mDrawState = NO_SURFACE Surface 已创建但隐藏 mDrawState = DRAW_PENDING 阶段2: 客户端首次绘制完成 (DRAW_PENDING → COMMIT_DRAW_PENDING) 状态转换 合并事务到同步组 altmDrawState == DRAW_PENDING 阶段3: 布局提交与准备显示 (COMMIT_DRAW_PENDING → READY_TO_SHOW) 状态转换 检查 Activity 生命周期 altmDrawState == COMMIT_DRAW_PENDING 阶段4: 最终显示 (READY_TO_SHOW → HAS_DRAWN) 验证显示条件 应用进入动画(如果需要) 状态转换 触发动画帧渲染 altmDrawState == READY_TO_SHOW \&\& isReadyForDisplay() 阶段5: 正常显示循环 (HAS_DRAWN 状态) altmDrawState == HAS_DRAWN \&\& !mLastHiddenmDrawState != HAS_DRAWN \|\| mLastHidden loop每帧渲染 阶段6: 窗口销毁 (任意状态 → NO_SURFACE) 销毁 Surface 资源 状态重置 relayoutWindow() 请求创建窗口创建 WindowState构造 WindowStateAnimatorcreateSurfaceLocked()创建 SurfaceControl (HIDDEN标志)resetDrawState()返回 Surface,等待客户端绘制执行 onDraw() 渲染内容finishDrawing() 通知绘制完成finishDrawing(postDrawTransaction, syncSeqId)finishDrawingLocked(postDrawTransaction)mDrawState = COMMIT_DRAW_PENDINGgetSyncTransaction().merge(postDrawTransaction)返回 layoutNeeded = trueperformLayoutAndPlaceSurfaces()commitFinishDrawingLocked()commitFinishDrawingLocked()mDrawState = READY_TO_SHOWperformShowLocked()performShowLocked()检查 showToCurrentUser()检查 mActivityRecord.canShowWindows()applyEnterAnimationLocked()mDrawState = HAS_DRAWNscheduleAnimationLocked()递归调用子窗口 performShowLocked()prepareSurfaceLocked(transaction)transaction.show(mSurfaceControl)setShown(true)transaction.hide(mSurfaceControl)setShown(false)移除窗口或 Activity 停止destroySurface(cleanupOnResume, appStopped)destroySurfaceUnchecked()destroySurfaceLocked(transaction)transaction.remove(mSurfaceControl)setShown(false)mSurfaceControl = nullmDrawState = NO_SURFACEmAnimatingExit = false

BUFFER 的 fence 机制

当 App 通过 eglSwapBuffers / queueBuffer 将 buffer 提交给 BLASTBufferQueue 时,buffer 带有一个 fence(GraphicBuffer 的 acquireFence):

当 App 通过 eglSwapBuffers / queueBuffer 将 buffer 提交给 BLASTBufferQueue 时,buffer 带有一个 fence(GraphicBufferacquireFence):

text 复制代码
queueBuffer(buffer, fence) → BBQ
                               │
                               ├── buffer 进入 BBQ 的待处理队列
                               ├── fence 被附加到 Transaction 中
                               └── Transaction → SF
                                     │
                                     ├── SF: t.show() → Surface 可见
                                     ├── SF: 尝试合成 buffer
                                     ├── SF: 发现 fence 未 signal
                                     ├── SF: 等待 fence  ← GPU 仍在渲染
                                     ├── ... GPU 完成 → fence signal
                                     └── SF: 合成并显示

绘制状态与屏显的关系

时间点 事件 GPU 状态 mDrawState
T1 GPU 命令提交,queueBuffer 渲染中 DRAW_PENDING
T2 finishDrawing() → WMS 渲染中 COMMIT_DRAW_PENDING
T3 commitFinishDrawingLocked() 渲染中 READY_TO_SHOW
T4 performShowLocked() 渲染中 HAS_DRAWN
T5 showRobustly()t.show() 渲染中 HAS_DRAWN
T6 GPU fence signal 完成 ✅ HAS_DRAWN
T7 SF 合成并显示 完成 HAS_DRAWN

HAS_DRAWN 是 WMS 侧的"决策状态",不是 GPU 侧的"完成状态"。从 HAS_DRAWN 设置到 GPU 真正完成渲染之间的时间差,由 buffer 的 acquire fence 机制来保证画面正确性------SF 会在合成前自动等待 fence,不会出现显示不完整帧的问题。

相关推荐
码云骑士1 小时前
Android 应用启动过程
android
bqliang1 小时前
译 · Jake Wharton 访谈:Android 圈最熟悉的那个名字
android·程序员·开源
三少爷的鞋1 小时前
Android Data 层 Flow 最佳实践:以冷流为基础,按需转热,避免过早共享状态
android
私人珍藏库9 小时前
【Android】Soul v5.86.0 内置模块版
android·app·工具·软件·多功能
千里马学框架10 小时前
aosp新增窗口层级 Type 完整实现方案(有源码)-wms需求和面试题
android·智能手机·架构·wms·aaos·车机
峥嵘life16 小时前
Android 蓝牙设备连接广播详解-2026
android·python·学习
MusingByte18 小时前
别再裸用 Claude Code 了!安卓开发者必装 13 个官方推荐插件,效率翻 3 倍省 70% token
android
_李小白18 小时前
【android opencv学习笔记】Day 29: 滤波算法之Sobel 边缘检测
android·opencv·学习
Dxy123931021619 小时前
Python 操作 MySQL 事务:从入门到避坑
android·python·mysql