Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


title: Android 17 FrameTimeline、FrameTracer 与合成边界 chapter: '2.12' section: '2.12' status: finalized applicable_versions: Android 12 (API 31) - Android 17 (API 37) last_verified: '2026-08-30' last_verified_against: AOSP android-17.0.0_r1 last_idle_audit_at: '2026-08-30T14:42:08+08:00' last_idle_audit_run_id: 20260830-143503-idle-audit-c720f524 confidence: medium tags:

  • rendering
  • frametimeline
  • gpu-cpu-boundary
  • android17
  • surfaceflinger
  • hwc
  • perfetto related_chapters:
  • '2.1'
  • '2.3'
  • '2.9'
  • '2.8' sources:
  • type: aosp path: frameworks/native/services/surfaceflinger/Scheduler/FrameTimeline.h
  • type: aosp path: frameworks/native/services/surfaceflinger/Scheduler/FrameTimeline.cpp
  • type: aosp path: frameworks/native/services/surfaceflinger/FrameTracer/FrameTracer.cpp
  • type: aosp path: frameworks/base/core/java/android/view/Choreographer.java
  • type: aosp path: frameworks/base/core/java/android/view/SurfaceControl.java
  • type: aosp path: external/perfetto/protos/perfetto/trace/android/graphics_frame_event.proto
  • type: aosp path: external/perfetto/protos/perfetto/trace/android/frame_timeline_event.proto
  • type: official path: https://perfetto.dev/docs/data-sources/frametimeline
  • type: blog path: https://androidperformance.com task2b_state: fixed task6_state: reviewed task9_state: reviewed pipeline_stage: ready-to-publish last_consolidated_at: '2026-08-11' consolidated_from:
  • src/part1-fundamentals/ch02-rendering/2.32-android-17-frametimeline-数据结构.md
  • src/part1-fundamentals/ch02-rendering/2.52-android17-gpu-debug-performance-tools.md

Android 17 FrameTimeline、FrameTracer 与合成边界

FrameTimeline 用于判断一帧是否按调度器预测的时间显示,以及延误更接近应用、SurfaceFlinger、GPU composition(GPU 合成)还是 Display HAL(显示硬件抽象层)。它无法覆盖所有 Producer(内容生产者),也不能单独证明某段 CPU 或 GPU 工作就是根因。

以下分析以 Android 17(API 37)的 android-17.0.0_r1 为平台版本,以 android17-6.18-2026-06_r6 为内核同步版本。公共显示主线如下:

Producer 生成内容
  → queueBuffer / SurfaceControl.Transaction + acquire fence
  → SurfaceFlinger 接收、选择并 latch buffer
  → HWC validate / present,必要时 RenderEngine 生成 client target
  → present fence 给出显示提交的完成反馈
  → release fence 约束旧 buffer 何时可以复用

这条主线把“应用提交”“SurfaceFlinger 采纳”“合成”“显示反馈”和“buffer 复用”分成不同边界。acquire fence 表示新 buffer 何时可读,latch 表示 SurfaceFlinger 采纳 buffer,client target 是 RenderEngine(SurfaceFlinger 的 GPU 合成组件)的合成结果,present fence 与 release fence 分别约束显示完成反馈和旧 buffer 复用。HWC 是 Hardware Composer(硬件合成器)。queueBuffer() 返回只代表提交动作完成,不能作为上屏时间。

先确认 FrameTimeline 覆盖了哪条出图路径

FrameTimeline 对标准 App Window 最有解释力。页面包含独立 Surface、外部流或多个 Producer 时,应先画出 layer(图层)与 BufferQueue(buffer 生产者和消费者之间的队列)拓扑,再决定 FrameTimeline 能证明哪一段。下表中的 Expected 表示预测区间,Actual 表示观测到的实际区间。

出图类型FrameTimeline 能直接观察的部分必须补充的证据
标准 View 或 Compose App Window宿主应用的 Expected、Actual SurfaceFrame,及其关联的 SF DisplayFrameChoreographer#doFrameDrawFrame、RenderThread、BufferQueue 与 fence
TextureViewTexture 内容被采样后形成的宿主 App Window 帧上游 SurfaceTexture BufferQueue、updateTexImage() 与 acquire、外部 Producer
SurfaceView、自管 SurfaceControl可能看到部分 transaction 或 display 结果;Perfetto 官方 FrameTimeline 文档仍声明 SurfaceView 主体不受完整支持独立 layer、BufferTX、queue、latch,以及 acquire、present、release fence
Camera、MediaCodec、视频 overlay、sideband(旁路视频流)宿主控制层或最终 DisplayFrameCamera、codec、provider(服务提供方)、HAL 的 Producer、独立队列、HWC 与厂商显示轨迹
Native game使用 Choreographer token 并随 buffer transaction 传递时可获得部分关联AChoreographer、引擎线程、EGL 或 Vulkan 提交、独立 BufferQueue、GPU 与 fence
混合页面、多窗口一个 DisplayFrame 可关联多个进程、多个 SurfaceFrame每个 layer 的 Producer、Z-order(层级顺序)、transform(变换)、刷新率与独立队列

这张表有两个工程含义:

  • FrameTimeline 没有 App slice(带起止时间的 trace 片段),不等于应用没有提交 buffer;
  • FrameTimeline 标记 App 正常,也不能排除未纳入该 SurfaceFrame 的 Camera、视频或游戏 Producer 迟到。

FrameTimeline 的数据模型

SurfaceFrame 与 DisplayFrame

frame_timeline_event.proto(FrameTimeline trace 协议定义)包含两类对象:

  • SurfaceFrame 表示某个应用或 layer 的一次帧更新;
  • DisplayFrame 表示 SurfaceFlinger 把多个 layer 组织成一次显示更新。

二者是多对一关系。关联条件写在 proto 注释中:

DisplayFrame.token = SurfaceFrame.display_frame_token

等式表示一个 SurfaceFrame 通过 display_frame_token 指向所属 DisplayFrame。同一个应用 token(关联帧的整数标识)还可能对应多个 layer,例如一个进程同时更新多个 Surface。查询时必须保留 upid(Perfetto 进程标识)与 layer_name,不能只按 token 去重。

token 怎样从应用到达 SurfaceFlinger

Android 17 的关键对象是 FrameTimelineInfo

  1. ChoreographerAChoreographer 从当前 VSync(垂直同步)timeline 取得 vsyncId
  2. HWUI(Android 硬件加速 UI 管线)或原生 Producer 把 vsyncId、帧开始时间、dequeue(取得可写 buffer)等信息写入 FrameTimelineInfo
  3. 标准窗口路径由 BLAST(以 BLASTBufferQueue 管理窗口 buffer 的路径)按 frame number(帧序号)保存这份信息,并在 Transaction::setFrameTimelineInfo() 中随 buffer transaction 发给 SurfaceFlinger;
  4. FrameTimeline::createSurfaceFrameForToken()vsyncId 查询预测值并创建 SurfaceFrame
  5. SurfaceFlinger 完成本轮 display 分类时,把对应 DisplayFrame token 写入 SurfaceFrame trace packet(trace 数据包)。

FrameTimelineInfo.aidl 中还包含 startTimeNanosvsyncResyncedJitterNanosdequeueBufferDurationNanos。token 除了标识 UI 帧,还携带分类所需的应用侧时序信息。

token 可能无效或过期。SurfaceFrame::trace() 会跳过无效 token;预测过期时,expected 时间戳已经不能用于正常比较,Android 17 会采用专门的过期分类与 trace 处理。因此,看到 prediction_type = Expired Prediction 时,应先检查 token 传递与调度延迟,不能继续机械计算 Expected 与 Actual 的差。

TokenManager 的容量边界

源码注释把预测描述为大约保留 120 ms,但 Android 17 的具体实现是固定容量环形缓冲区,不是为每个 token 建一个 TTL(Time To Live,存活时间)定时器。生产速度、刷新率和是否及时消费都会影响某个 token 何时被覆盖。分析 prediction expired 时,应检查 token 创建、transaction 到达和 SurfaceFlinger 消费之间的真实时间,不要把 120 ms 当作精确过期闹钟。

FrameTracer 与 FrameTimeline 的身份边界

Android 图形 trace 中有两个独立的数据源:

维度FrameTracerFrameTimeline
数据源android.surfaceflinger.frameandroid.surfaceflinger.frametimeline
核心标识buffer ID、frame number、layer namesurface token、display token、PID、layer name
主要问题buffer 在 dequeue、queue、fence、latch、present 哪段停留Expected 与 Actual 是否偏离、哪一侧被分类为 jank(卡顿)
Trace Processorframe_sliceexpected_frame_timeline_sliceactual_frame_timeline_slice

两套 proto 没有声明 FrameTracer.frame_number = FrameTimeline.surface_frame_token。可靠关联需要同一 layer、Producer、相邻时间窗、buffer 与 transaction 事件和 display token 共同收窄;只按整数相等执行 join(表连接)会把无关帧拼在一起。

FrameTracer 的事件时间位于外层 TracePacket.timestamp。带 fence 的事件会先进入 pending tracker(待完成事件跟踪器),fence signal(发出完成信号)后再闭合 span(时间区间);立即完成的事件可能表现为 instant(瞬时事件)。Trace Processor 依据事件 phase(阶段)构造 frame_slice,因此不能假设每个枚举都对应一条固定 duration slice,也不能由协议中存在某个枚举推断 Android 17 的生产代码一定发射它。

FrameTimeline 的 Expected、Actual start packet 用 cookie(配对标识)建立 slice,end packet 用同一 cookie 闭合。Trace Processor 再把 surface token、display token、PID、layer、present type、prediction type 和 jank bit(卡顿位标记)暴露给 SQL。数据源名称不是 SQL 表名,FrameTracer 的 frame_slice 也不是 FrameTimeline actual 表的别名。

怎样解读预期值与实际值

应用侧 SurfaceFrame

应用侧四个边界的含义如下:

字段或区间Android 17 口径
Expected start调度器预测应用开始处理该帧的时间
Expected end应用应当完成 buffer 提交与相关 GPU 工作的 deadline(截止时间)
Actual start优先使用应用传入的 startTimeNanos;没有时回退到预测 start
Actual endmax(actual queue time, acquire fence signal time);acquire fence 仍 pending(未完成)时暂用 queue time

SurfaceFrame::setAcquireFenceTime() 给出了 Actual end 的直接依据:

if (acquireFenceTime == Fence::SIGNAL_TIME_PENDING) {
    mActuals.endTime = mActualQueueTime;
} else {
    mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
}

这段代码把 CPU 提交完成与 Producer GPU 完成分开处理。应用很早调用 queueBuffer(),但 acquire fence 很晚才 signal,Actual SurfaceFrame 仍会延长到 GPU 可供 Consumer(消费者)读取的时刻。

SurfaceFrame 的 Actual slice 结束于上述 ready(可供后续读取)边界,不延伸到最终上屏;present_typejank_type 会在 DisplayFrame 获得 present 反馈后回填分类结果。slice 右边界不能直接作为屏幕更新时间。

SurfaceFlinger 侧 DisplayFrame

DisplayFrame 的 Actual slice 从 SurfaceFlinger 为该帧醒来或开始工作延伸到 actual present:

  • start 来自 onSfWakeUp() 或相应的实际开始记录;
  • SF CPU end 由调用 setSfPresent() 时的时间保存;
  • actual present 来自 pacesetter display(提供本轮显示节奏基准的 Display)的 present fence signal;
  • client composition 存在时,分类还会把 GPU done fence(GPU 完成栅栏)纳入 ready deadline。

DisplayFrame 的 slice 时长包含 Composer、Display HAL 与 present 反馈,不等于 SurfaceFlinger 主线程纯 CPU 时间。分析 SF CPU 时仍要看线程 slice 与调度;分析 SF GPU 时要看 client target GPU fence 和 GPU track(轨道);分析 Display HAL 时要看“SF 已按时完成,但 present 仍晚”的组合证据。

三个字段不能互相替代

字段回答的问题常见误读
on_time_finish该对象是否在预测 end 前 readytrue 不保证按时 present
present_typeactual present 相对 predicted present 是 on-time、late、early、dropped 还是 unknown(按时、晚、早、丢弃或未知)early 不自动等于 pacing bug(节奏控制错误)
prediction_type用于比较的预测是否仍有效expired 仍直接比较两个 slice

FrameTimeline 的 jank 定义围绕 predicted present 与 actual present 是否匹配。单独用 Actual Display Time - Expected Display Time > 0 作为所有场景的“用户可见卡顿”判据,会把持续但平滑的高延迟状态、预测误差、模式切换和无效预测混在一起。

GraphicsFrameEvent:buffer 与 fence 的补充证据

graphics_frame_event.proto 定义了 DEQUEUEQUEUEPOSTACQUIRE_FENCELATCHHWC_COMPOSITION_QUEUEDFALLBACK_COMPOSITIONPRESENT_FENCERELEASE_FENCE 等枚举。枚举存在只表示协议允许表达该事件,不表示 Android 17 的生产代码一定发出它。

android-17.0.0_r1 的 SurfaceFlinger 生产调用点中,可以确认的事件如下:

事件Android 17 发射条件判读重点
DEQUEUELayer::setBuffer() 收到有效的 bufferData.dequeueTimeProducer 取得该 buffer 的时间;不是所有路径都携带
QUEUE与上项同一条件,时间戳使用 transaction 的 postTime该 buffer update(更新)进入 SF transaction 的时间锚点
ACQUIRE_FENCElatchBufferStatsAndHandles() 追踪 buffer acquire fencefence span 的终点是 signal time;表示 Consumer 可安全读取
LATCHSF 采纳该 bufferqueue 与 latch 之间可包含 transaction readiness(事务就绪条件)、fence 与调度等待
FALLBACK_COMPOSITIONoutputLayer->requiresClientComposition()该 output layer 本轮进入 RenderEngine client composition
PRESENT_FENCEper-layer(逐 layer)记录 display present fence;无有效 fence 时可回退到 HWC present timestamp是显示侧反馈,不是 panel(面板)光学响应

POSTHWC_COMPOSITION_QUEUEDRELEASE_FENCE 等枚举在这组 Android 17 SurfaceFlinger 生产调用点中没有活跃发射点。分析脚本不应要求每帧出现完整枚举序列,也不应仅因缺少 RELEASE_FENCE 事件便断言 buffer 已经或尚未可复用。

android.surfaceflinger.frame 数据源承载这些 GraphicsFrameEventandroid.surfaceflinger.frametimeline 承载 SurfaceFrame 与 DisplayFrame。两者用途不同,需要结合 layer、buffer ID、frame number 与相邻时间关系观察。

CLIENT、DEVICE 与 gpu_composition

HWC 决策会逐帧变化

SurfaceFlinger 每轮根据当前可见 layer 集合准备 CompositionEngine 输出,并与 HWC(Hardware Composer,硬件合成器)交互。Android 17 既可能走 presentOrValidate() 快路径,也可能进入 validate:

  1. HWC 检查当前 display 与 layer 状态;
  2. validate 返回 composition type changes(合成类型变化)与 requests(附加请求);
  3. SurfaceFlinger 与 CompositionEngine 接受变化;
  4. 需要 CLIENT 的 layer 由 RenderEngine 合成到 client target;
  5. client target 与可做 DEVICE composition 的 layer 一起交给 HWC present。

overlay plane(硬件叠加平面)数量、format(格式)、transform、dataspace(颜色语义)、blend(混合)、protected content(受保护内容)、display mode 与厂商 Composer 能力都会影响结果。不能把流程写成“SurfaceFlinger 发现 CLIENT layer 太多,再把一部分改成 GPU”;composition type changes 来自 HWC validate 协议与 CompositionEngine 的当前策略。

SurfaceFrame 标志是 layer 粒度

Layer::onCompositionPresented() 的条件是:

if (outputLayer && outputLayer->requiresClientComposition()) {
    mFrameTracer->traceTimestamp(..., FrameEvent::FALLBACK_COMPOSITION);
    mDrawingState.bufferSurfaceFrameTX->setGpuComposition();
}

这段条件只在对应 output layer 需要 client composition 时写入标志。因此,SurfaceFrame 的 gpu_composition = true 表示该 layer 在这一轮需要 client composition。FALLBACK_COMPOSITION 是 proto 的历史事件名,不能扩写成“原本一定可以由 HWC 合成,后来因异常退回 GPU”。

DisplayFrame 标志是 pacesetter display 粒度

SurfaceFlinger::onCompositionPresented() 只在 display 的 usesClientComposition 为真时取得 client target acquire fence,并把 pacesetter display 的 fence 交给 FrameTimeline::setSfPresent()DisplayFrame::traceActuals() 随后使用下面的条件:

actualDisplayFrameStartEvent->set_gpu_composition(
        mGpuFence != FenceTime::NO_FENCE);

代码以是否存在 mGpuFence 写入 DisplayFrame 标志,由此可以得到几个严格边界:

  • DisplayFrame gpu_composition = true:本轮 pacesetter display 存在 SF client composition GPU fence;
  • DisplayFrame gpu_composition = false:FrameTimeline 没有记录这条 SF client composition fence;
  • false 不能证明应用没用 GPU,HWUI、游戏或视频 Producer 仍可能在生产自己的 buffer;
  • true 不能单独证明 GPU 是瓶颈,还要检查 GPU fence、RenderEngine 与 GPU track,以及 deadline;
  • DEVICE composition 表示 SF 这一层的图层叠加交给 HWC,不等于系统中“没有 CPU”或“没有 GPU 工作”。

这组标志描述的是 CLIENT 与 DEVICE 合成边界。CPU 调度与控制工作贯穿两条路径,差别在于 SurfaceFlinger 是否用 RenderEngine 生成 client target。

Jank 分类与颜色

Android 17 的主要分类

frame_timeline_event.protojank_type 定义为 bitmask(位掩码),一帧可以同时具有多个原因。工程分析常用的分类如下:

类型解释下一步证据
App Deadline MissedSurfaceFrame ready 晚于应用 deadline,并影响 presentdoFrame、RenderThread、acquire fence、dequeue wait(出队等待)
Buffer StuffingProducer 持续提交,旧帧尚未 present,队列形成高延迟状态pending(待处理)buffer、queue、latch、present 序列,以及 dequeue 阻塞
SurfaceFlinger CPU Deadline MissedSF 的就绪时间错过截止时间,且没有 client composition GPU fence 作为 GPU 分支依据SF 主线程运行与调度、HWC 阻塞调用
SurfaceFlinger GPU Deadline MissedSF 使用 client composition,CPU end 尚可,但 client target GPU fence 迟到RenderEngine、GPU queue 与 fence、频率与带宽
Display HALSF ready 尚可,显示侧没有在预测 VSync 完成 presentHWC、DRM(Direct Rendering Manager,Linux 显示子系统)、厂商 display trace、模式与电源状态
SurfaceFlinger Schedulingpresent 偏差符合 VSync cadence(显示节奏)等调度特征SF wakeup(唤醒)、VSync、线程调度
Prediction Errorpredicted present 与显示反馈的偏差不符合当前预测VSync 预测、刷新率或模式切换;孤立样本不宜放大
Dropped FrameApp 或 SF 侧帧被丢弃前后 token、layer 更新、是否被更新帧取代
UnknownNon Animating当前证据不足,或不适合按动画连续性分类先检查 prediction、display power、mode 与出图类型

Android 17 还包含 App Resynced JitterSurfaceFlinger StuffingDisplay Not OnDisplay Mode Change In ProgressDisplay Power Mode Change In Progress 等分类。显示模式或电源切换期间的样本不应直接归咎于业务渲染。

proto 同时携带 legacy(旧版)与 experimental(实验性)的 jank、present 值,并明确标注 experimental 字段不用于 jank 分析。报告应以 Perfetto 公开的 jank_typepresent_typeprediction_type 为主,实验字段只用于平台开发调试。

Perfetto 颜色的含义

颜色含义
绿色没有观察到 jank
浅绿色帧率可以保持平滑,但帧持续晚显示,输入延迟升高
红色slice 所属进程被判为本次 jank 的责任侧;不是固定等同于 App
黄色只用于 App track:应用帧被标为 janky(发生卡顿),但责任被归到 SurfaceFlinger
蓝色dropped frame;App 与 SF 侧的具体丢帧语义不同

颜色适合定位候选帧,根因仍需结合字段、token flow(token 关联流)、线程 slice、buffer 与 fence 证明。

TimeStats 与 JankTracker 的统计边界

FrameTimeline 负责逐帧计划、完成时间和 jank 分类;另外两套机制处理聚合与通知:

  • TimeStats 按 layer 与 display 汇总 present-to-present、post-to-present、acquire-to-present、jank、composition 等趋势,可通过受控的 dumpsys SurfaceFlinger --timestats 或 statsd pull(拉取聚合统计)做前后对照。它不是逐帧根因表,也不保证提供任意分位数。
  • JankTracker 接收已经分类的结果,按 listener(监听器)批量投递;Android 17 的 batch(批次)以 50 条为边界,并支持显式 flush(立即发送积累结果)。通知晚到只说明批量或调度延迟,不表示 jank 到那一刻才被判定。

一轮诊断应先用 FrameTimeline 找出同一 SurfaceFrame 与 DisplayFrame 的异常,再用 FrameTracer、线程 slice、BufferTX、fence 与 HWC 解释阶段;最后用 TimeStats 验证现象是否在稳定样本中持续。若业务需要在线反馈,再核对 JankTracker listener 收到的 bit(分类位)、批次和 flush 时机。

fence 与 BufferQueue:不要把三个方向混在一起

同步对象生产者与消费者关系能回答的问题
acquire fenceProducer 随新 buffer 交给 Consumer新 buffer 何时写完、何时可安全读取
present fenceHWC、display 对本次 display present 的反馈本轮显示更新到达哪个系统完成边界
release fenceConsumer、HWC 交还旧 buffer 的使用完成约束Producer 何时可以安全复用该 buffer

Android 用户态通过 FenceFenceTime 与 sync file(同步文件对象)传递这些同步对象;指定内核锚点中的 dma_fence 提供 signal、wait 与 callback 基础。FrameTimeline 读取的是用户态和 HAL 传回的时间,不是直接把某个内核函数耗时当作 jank 根因。

排查 buffer starvation(可用 buffer 不足)时,应观察 dequeueBuffer 等待、可用 slot(槽位)、pending buffer、release callback 与 fence,以及前序帧的 present。把“当前 Actual end 到下一帧 Expected start”的差当作 release fence 时间,会混淆两个不同对象。

Android 的 BufferQueue 与 fence 设计用于避免 Consumer 读取未完成内容。看到游戏或视频画面撕裂感时,先区分 frame pacing(帧节奏控制)、重复帧或丢帧、transform 更新不同步和厂商显示路径;只有拿到绕过正常同步或显示扫描异常的证据,才适合使用 classic tearing(经典撕裂)结论。

采集一份可解释的 trace

Perfetto UI 的 Android preset(预设配置)通常会启用 FrameTimeline。需要可复现的命令行配置时,下面的配置会同时收集两类 SurfaceFlinger 数据,以及 App 与 SF 常用的 atrace(Android trace 标记)数据:

buffers {
  size_kb: 32768
  fill_policy: RING_BUFFER
}

duration_ms: 10000

data_sources {
  config {
    name: "android.surfaceflinger.frametimeline"
  }
}

data_sources {
  config {
    name: "android.surfaceflinger.frame"
  }
}

data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      ftrace_events: "sched/sched_switch"
      ftrace_events: "sched/sched_waking"
      atrace_categories: "gfx"
      atrace_categories: "view"
      atrace_categories: "sched"
      atrace_apps: "com.example.app"
    }
  }
}

com.example.app 替换成目标包名。android.surfaceflinger.frametimeline 提供 Expected、Actual 与 jank 分类,android.surfaceflinger.frame 提供 buffer 和 fence 事件,gfxviewsched 用于解释应用与线程调度。

配置保存为 /data/local/tmp/frame.pbtxt 后,可以用下面的命令采集:

adb shell perfetto --txt \
  -c /data/local/tmp/frame.pbtxt \
  -o /data/misc/perfetto-traces/frame.perfetto-trace

adb pull /data/misc/perfetto-traces/frame.perfetto-trace

第一条命令按配置采集 10 秒,第二条把 trace 拉回主机。复现窗口应覆盖问题前后的稳定帧,避免只截到一次模式切换或应用刚启动的瞬态。

用 SQL 保留 token、layer 与进程上下文

查询应用侧 SurfaceFrame

下面的查询用于列出应用侧 Actual SurfaceFrame,并保留归因所需字段:

SELECT
  a.ts,
  a.dur,
  a.surface_frame_token AS app_token,
  a.display_frame_token AS sf_token,
  p.name AS process_name,
  a.layer_name,
  a.present_type,
  a.on_time_finish,
  a.gpu_composition,
  a.jank_type,
  a.prediction_type
FROM actual_frame_timeline_slice AS a
LEFT JOIN process AS p USING (upid)
WHERE a.surface_frame_token IS NOT NULL
ORDER BY a.ts;

结果中的 dur 是应用 ready 区间,present_type 是后来根据显示反馈完成的分类。相同 app_token 出现多行时,应先查看 process(进程)与 layer,不要立即去重。

按 DisplayFrame 关联 App 与 SurfaceFlinger

下面的查询用 display_frame_token 把每个应用 SurfaceFrame 关联到同一轮 SF DisplayFrame:

WITH app AS (
  SELECT *
  FROM actual_frame_timeline_slice
  WHERE surface_frame_token IS NOT NULL
),
sf AS (
  SELECT *
  FROM actual_frame_timeline_slice
  WHERE surface_frame_token IS NULL
)
SELECT
  app.ts AS app_ts,
  app.surface_frame_token AS app_token,
  app.display_frame_token AS sf_token,
  app.layer_name,
  app.jank_type AS app_jank,
  app.gpu_composition AS app_client_composition,
  sf.ts AS sf_ts,
  sf.dur AS sf_dur,
  sf.present_type AS sf_present_type,
  sf.jank_type AS sf_jank,
  sf.gpu_composition AS sf_client_composition
FROM app
LEFT JOIN sf USING (display_frame_token)
ORDER BY app.ts;

一个 SF token 关联多条 App 记录是正常现象:一次显示更新可以合成多个 layer。SF 记录缺失时,应检查 token 是否无效、预测是否过期、trace 是否从帧中途开始,以及目标是否属于 FrameTimeline 覆盖有限的独立 Surface。

计算 per-frame deadline overrun(逐帧超期量)

Perfetto v54 的 android.frames.per_frame_metrics 模块提供 android_frame_stats。下面的查询用于按 deadline overrun 排序:

INCLUDE PERFETTO MODULE android.frames.per_frame_metrics;

SELECT
  frame_id,
  overrun / 1e6 AS overrun_ms,
  cpu_time / 1e6 AS cpu_time_ms,
  ui_time / 1e6 AS ui_time_ms,
  was_jank
FROM android_frame_stats
ORDER BY overrun DESC;

overrun 是 Actual end 减 Expected end,负数表示没有错过该 deadline。该表依赖能被 stdlib(Perfetto 标准模块库)关联的 Choreographer#doFrameDrawFrame 与 FrameTimeline slice;缺行时不能把 NULL 当作 0,也不能用它替代 jank_type 对 SF 或 Display HAL 的分类。

四类常见问题怎样复核

标准 HWUI 页面:App Deadline Missed

建议按同一个 App token 检查:

  1. Actual start 是否已经晚于 Expected start;
  2. Choreographer#doFrame 内 INPUT、ANIMATION、TRAVERSAL、COMMIT 哪段变长;
  3. DrawFrame 或 RenderThread 是 CPU 提交慢,还是 GPU acquire fence 晚;
  4. dequeueBuffer 是否因旧 buffer 尚未 release(释放)而等待;
  5. 对应 DisplayFrame 是否又叠加 SF 或 Display HAL jank。

SurfaceFrame gpu_composition = false 只表示该 layer 没有被 SF 放入 client composition,不能排除 HWUI 生成 buffer 时的 GPU 延迟。

SurfaceView 或游戏:画面节奏不稳

不要假定 Native(原生)引擎一定把 Choreographer.FrameData 正确传到了目标 Surface。验证 token 存在后,再沿独立 layer 检查:

AChoreographer / engine tick
  → EGL/Vulkan submit
  → queueBuffer + acquire fence
  → BufferTX / latch
  → HWC present + present fence

这条序列用来定位“逻辑 tick(引擎帧节拍)晚、GPU 完成晚、buffer 到达晚、SF 没采纳、显示后段晚”中的哪一段。buffer 早于目标时间 ready 通常只是留出排队余量,不能单凭“早”判为 pacing 错误。

大量 gpu_composition = true

这只说明 SF 频繁使用 CLIENT composition 路径。要证明它造成 deadline miss(错过截止时间),还需要同时看到:

  • SurfaceFlinger GPU Deadline Missed 或相符的 deadline;
  • client target GPU fence signal 偏晚;
  • RenderEngine、GPU track 与该 DisplayFrame 时间重叠;
  • 排除 App 自己的 GPU、HWC validate、Display HAL 或频率切换。

优化方向应根据触发 CLIENT 的具体 layer 状态确定。直接移除 ColorMatrix、改成 SurfaceView 或强制 overlay,可能改变透明度、保护内容、颜色管理与生命周期语义,而且 HWC 仍可在下一帧返回不同结果。

App 与 SF 都 ready,但 present 仍晚

当 App on_time_finish = true、SF 的 CPU 与 GPU 也在 deadline 内 ready,而 DisplayFrame 仍 late 并标记 Display HAL,排查重点应移到 HWC、DRM、厂商显示栈、刷新率或显示模式切换。present fence 能给出显示侧时间锚点,但不能继续细分 panel scanout(面板扫描输出)与光学响应。

一套不跳阶段的诊断顺序

  1. 确认问题窗口与刷新率 记录显示 mode、render rate(渲染帧率)、输入事件和用户看到的现象,排除启动、旋转、亮灭屏与模式切换瞬态。

  2. 确认 Producer 与承载对象 标出 App Window、TextureView、SurfaceView,以及 Camera、video、game 的 Producer、BufferQueue、layer name 与进程。

  3. 选择一个异常 token 同时查看 Expected、Actual、prediction、present、jank、severity(严重程度)、layer 与 flow(跨轨道关联),不按颜色直接归因。

  4. 检查应用 ready 边界 对照 doFrame、RenderThread、queue time 与 acquire fence,区分 CPU、Producer GPU 和 dequeue wait。

  5. 检查 SF 是否采纳新内容 对照 QUEUE、BufferTX、LATCH 与 pending buffer。已经入队但本轮没有 latch,说明问题仍在显示前段。

  6. 检查 CLIENT 与 DEVICE composition 用 SurfaceFrame、DisplayFrame 的 gpu_composition 找到候选,再以 validate、RenderEngine 和 GPU fence 证明成本。

  7. 检查 present 与 buffer 归还 present fence 解释显示更新,release fence 与回调解释 buffer 复用。二者不能交换。

  8. 用相邻稳定帧复核 比较同一 layer 的正常帧与异常帧,确认结论可重复,并排除一次性的 prediction 或 display mode 变化。

Android 12 到 Android 17 的版本边界

平台可验证边界
Android 12(API 31)FrameTimeline 开始提供 App、SF 的 Expected 与 Actual timeline,作为这里分析的最低版本
Android 13(API 33)公开 Choreographer.FrameData 与 FrameTimeline 查询能力;原生与自定义渲染仍要把 token 随目标帧传下去
Android 14(API 34)公共 App Window→BLAST→SF→HWC 主线继续成立;独立 Surface 与混合页面仍需额外 buffer、fence 证据
Android 15(API 35)SurfaceControl.Transaction.setFrameTimeline(long) 受 SDK FLAG_SDK_DESIRED_PRESENT_TIME 约束;flag 开启时可把 Choreographer 的 vsyncId 传给 SurfaceFlinger,flag 关闭时该公开入口返回但不设置 timeline。隐藏的 setFrameTimelineVsync(long) 仍供系统路径使用。它不生成 buffer,也不消除 fence wait(等待)
Android 16(API 36)这里的 token、Expected 与 Actual、CLIENT 与 DEVICE 判读方法继续适用
Android 17(API 37)源码锚点为 Scheduler/FrameTimeline.{h,cpp}、当前 BLAST、CompositionEngine,以及 HWC presentOrValidate 与 validate 路径

表中“源码位于某目录”只描述 Android 17 当前结构,不表示该文件到 Android 17 才出现。涉及更早版本时,应切换到对应 tag 核查函数位置和字段,不能用当前目录结构推断版本演进。

源码核对清单

小结

FrameTimeline 的强项是把预测、应用 ready、SurfaceFlinger display work(显示处理)与 actual present 放进同一套 token 关系中。可靠结论需要同时守住四个边界:

  • SurfaceFrame Actual end 是 queue 与 acquire fence 的较晚者,不是上屏时间;
  • DisplayFrame Actual slice 延伸到 present,不能当作 SF 主线程 CPU 时长;
  • gpu_composition 描述 SF 的 CLIENT composition 边界,不描述应用是否使用 GPU;
  • 独立 Surface、Camera、视频、游戏与混合页面必须补充 layer、BufferQueue 和 fence。

按 Producer → buffer → latch → composition → present → release 的顺序检查,才能把“帧晚了”缩小为可由源码与 trace 共同复现的问题。