EN

Android Systrace 流畅性实战 1 :了解卡顿原理

字数统计: 6k阅读时长: 22 min
2021/04/24
loading

不同的人对流畅性(卡顿掉帧)有不同的理解,对卡顿阈值也有不同的感知,所以有必要在开始这个系列文章之前,先把涉及到的内容说清楚,防止出现不同的理解,也方便大家带着问题去看这几篇问题,下面是一些基本的说明

  1. 对手机用户来说,卡顿包含了很多场景,比如在 滑动列表的时候掉帧、应用启动白屏过长、点击电源键亮屏慢、界面操作没有反应然后闪退、点击图标没有响应、窗口动画不连贯、滑动不跟手、重启手机进入桌面卡顿 等场景,这些场景跟我们开发人员所理解的卡顿还有点不一样,开发人员会更加细分去分析这些问题,这是开发人员和用户之间的一个认知差异,这一点在处理用户(或者测试人员)的问题反馈的时候尤其需要注意
  2. 对开发人员来说,可以先按 流畅度(画面节奏不连贯)、响应速度(操作后等待过长)和 稳定性(崩溃、ANR 等)整理反馈。这些现象可能重叠;点击没有响应不一定是稳定性故障,需要结合输入、应用状态和日志进一步分类。
  3. 技术上,这三类问题并不是同一个 Message 超时机制的不同阈值。主线程长任务会同时影响输入和绘制,但 GPU、SurfaceFlinger、显示链路、线程调度或远端服务也可能造成延迟。ANR 由具体输入/组件等超时规则触发,崩溃则另有异常或信号等原因;不能仅凭一次长 Message 判定它们。
  4. 流畅性这个系列主要是分析流畅度相关的问题,响应速度和稳定性会有专门的文章介绍,在理解了流畅性相关的内容之后,再去分析响应速度和稳定性问题会事半功倍
  5. 流畅性这个系列主要是讲如何使用 Systrace (Perfetto) 工具去分析,之所以 Systrace 为切入点,是因为影响流畅度的因素很多,有 App 自身的原因、也有系统的原因。而 Systrace(Perfetto) 工具可以从一个整机运行的角度来展示问题发生的过程,方便我们去初步定位问题

版本说明(2026-10-14 核查):本文发表于 2021 年,保留旧 Systrace 截图和附件。下文框架代码按 AOSP android-10.0.0_r1 核对,不代表各厂商截图对应的完整实现。60 Hz / 16.67 ms 是示例,具体帧预算和 Buffer 路径需按系统版本与采集数据判断。新采集优先使用 Perfetto,Android 12(API 31)及以上可结合 FrameTimeline;没有相应数据时不能倒推现代帧指标。

本文目录

Systrace 系列文章如下

  1. Systrace 简介
  2. Systrace 基础知识 - Systrace 预备知识
  3. Systrace 基础知识 - Why 60 fps ?
  4. Systrace 基础知识 - SystemServer 解读
  5. Systrace 基础知识 - SurfaceFlinger 解读
  6. Systrace 基础知识 - Input 解读
  7. Systrace 基础知识 - Vsync 解读
  8. Systrace 基础知识 - Vsync-App :基于 Choreographer 的渲染机制详解
  9. Systrace 基础知识 - MainThread 和 RenderThread 解读
  10. Systrace 基础知识 - Binder 和锁竞争解读
  11. Systrace 基础知识 - Triple Buffer 解读
  12. Systrace 基础知识 - CPU Info 解读
  13. Systrace 流畅性实战 1 :了解卡顿原理
  14. Systrace 流畅性实战 2 :案例分析: MIUI 桌面滑动卡顿分析
  15. Systrace 流畅性实战 3 :卡顿分析过程中的一些疑问
  16. Systrace 响应速度实战 1 :了解响应速度原理
  17. Systrace 响应速度实战 2 :响应速度实战分析-以启动速度为例
  18. Systrace 响应速度实战 3 :响应速度延伸知识
  19. Systrace 线程 CPU 运行状态分析技巧 - Runnable 篇
  20. Systrace 线程 CPU 运行状态分析技巧 - Running 篇
  21. Systrace 线程 CPU 运行状态分析技巧 - Sleep 和 Uninterruptible Sleep 篇

Systrace (Perfetto) 工具的基本使用如果还不是很熟悉,那么需要优先去补一下上面列出的 Systrace 基础知识系列,本文假设你已经熟悉 Systrace(Perfetto)的使用了

了解卡顿原理

卡顿现象及影响

本文主要分析连续动画和滚动中的画面节奏。fps(frames per second)是一定时间内的帧数,必须说明统计的是应用生成、提交还是屏幕呈现的帧。假设目标确实是每秒呈现 120 个新画面,一秒只呈现 110 个,说明没有维持目标吞吐量;但仅凭平均 fps 不能确定哪一帧晚了、停顿分布如何或用户是否察觉。稳定的 60 fps 和平均 60 fps、间隔忽长忽短,体验并不相同。

同时掉帧的原因非常多,有 APP 本身的问题,有系统原因导致卡顿的,也有硬件层的、整机卡的,这个可以参考下面四篇文章

  1. Android 中的卡顿丢帧原因概述 - 方法论
  2. Android 中的卡顿丢帧原因概述 - 系统篇
  3. Android 中的卡顿丢帧原因概述 - 应用篇
  4. Android 中的卡顿丢帧原因概述 - 低内存篇

用户在使用手机的过程中,卡顿是最容易被感受到的

  1. 偶尔出现的小卡顿会降低用户的使用体验,比如刷微博的时候卡了一下,比如返回桌面动画卡顿这种
  2. 整机出现卡顿的则会让手机无法使用
  3. 现在的高帧率时代,如果用户习惯了 120 fps ,在用户比较容易感知的场景下突然切换到 60 fps,用户也会有明显的感知,并觉得出现了卡顿

所以不管是应用还是系统,都应该尽量避免出现卡顿,发现的卡顿问题最好优先进行解决

卡顿定义

应用一帧渲染的整体流程

为了知道卡顿是如何发生的,我们需要知道应用主线程的一帧是如何工作的

从执行顺序的角度来看

下面以 View/HWUI 硬件加速路径为例,从 Choreographer 的帧回调,经 UI Thread、RenderThread 和 GPU,到 SurfaceFlinger/HWC 再到屏幕呈现。CPU 提交完成、GPU 完成、合成完成和实际呈现是不同的时刻;绘制与合成可以跨帧流水重叠,不能把全过程限制在图里的一个 16.6 ms 格子。

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled.webp

图中 RenderThread 框里的“GPU”标注不准确:RenderThread 是运行在 CPU 上的线程,负责准备/提交图形命令,GPU 异步执行。issue 应理解为提交命令,不是“命令问题”;swap buffer 也不等于 GPU 已完成或屏幕已显示。图中的 measure/layout 只在需要时发生。

从 Systrace 的角度来看

上面的流程图从 Systrace (Perfetto)的角度来看会更加直观

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled%201.webp

这张旧图展示 OPPO Launcher 的一次流水过程,不能只按红箭头的先后认定同一帧的因果链。需要核对窗口/Layer、buffer 身份和 fence:队列计数上升不是 GPU 完成证据,HWC 调用结束也不等于已扫描到屏幕。长耗时应沿实际依赖检查应用主线程、RenderThread、GPU、SystemServer、SurfaceFlinger 和调度状态。

卡顿定义

本文把卡顿理解为:在预期连续更新的场景中,画面没有按预期节奏呈现,出现迟到、停顿或不均匀推进。原文“没有绘制”只是可能的中间现象,不能代替最终呈现判断。静态页面、主动限帧或低帧率内容不需要每个屏幕刷新周期都产生新 Buffer。

下图标出的 UI Thread 空档是一个待查点。先确认当时确实应该更新,再追踪对应窗口的提交和呈现;已有排队帧、RenderThread 独立动画、SurfaceFlinger 的 Layer 属性动画,都可能使“主线程没画”与“屏幕没动”不同。原图的 Jank 箭头不能单独作为判定依据。

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled%202.webp

可以从三个层面收集证据,但它们不是三个等价的判定公式:

  1. 画面:预期每次刷新都有新内容时,重复画面是停顿线索;30 fps 视频在 60 Hz 屏幕上重复一帧则可能完全正常。平均 fps、刷新次数和内容变化次数要分开。
  2. SurfaceFlinger/显示链路:检查目标 Layer 是否及时有可用内容、acquire fence 是否满足、合成及呈现是否错过期限。没有新 Buffer 时仍可使用上一张 Buffer 合成,或只改变 Layer 属性;SurfaceFlinger 也可能因没有任何更新而休眠。
  3. 应用:检查帧开始、UI 工作、RenderThread 提交和 GPU 完成是否符合本帧的计划。一个 Vsync 周期内缺少 queueBuffer 不是充分证据;及时 queue 也不能保证 GPU、合成或呈现及时。

主线程长任务是常见排查入口,但不能预设所有问题都在主线程。即使 CPU 片段较短,也可能存在 Runnable 等待、锁/Binder 等待、GPU 或显示链路延迟。

原文所说的 逻辑卡顿,是指本该推进的动画/内容没有推进,即使新的 Buffer 仍持续提交。这是对内容异常的描述,不是 FrameTimeline 的统一分类:先排除静态内容、视频节奏和有意重复,再检查应用状态及时间步进;仅凭截图相同不能直接锁定代码根因。

Android 12 及以上:结合 FrameTimeline

在采集到 android.surfaceflinger.frametimeline 的 Perfetto trace 中,按窗口/Layer 和 token 关联 Expected/Actual Timeline,检查预期与实际呈现、jank_type 和 on_time_finish。应用 Actual 的结束涉及 GPU 完成和提交,不只是 doFrame 的 CPU 片段。Buffer Stuffing 还可能表现为画面连续但输入延迟增加。支持范围和字段随系统/采集条件变化;缺轨道不是“零卡顿”。参见 Perfetto FrameTimeline 文档。

若只有旧 Systrace,就把线程、队列和可获得的 fence 证据串起来,并明确哪些呈现时刻未知。ANR 应另按 官方诊断指南 核对触发类型;例如异步广播还可能在主线程空闲时等待 PendingResult.finish()。

系统运行机制简介

由于卡顿的原因比较多,如果要分析卡顿问题,首先得对 Android 系统运行的机制有一定的了解,下面简单介绍一下分析卡顿问题需要了解的系统运行机制:

  1. App 主线程运行原理
  2. Message、Handler、MessageQueue、Looper 机制
  3. 屏幕刷新机制和 Vsync
  4. Choreographer 机制
  5. Buffer 流程和 TripleBuffer
  6. Input 流程

系统机制 - App 主线程运行原理

普通应用进程从 Zygote 派生后,经过运行时初始化进入 ActivityThread.main。以下是 AOSP android-10.0.0_r1 的相关节选,省略号注释代表未展示的系统代码,不是可复制到应用中运行的独立示例。prepareMainLooper() 创建 Looper/MessageQueue;ActivityThread 的实例字段初始化会创建其 Handler,不是 prepare 一次创建三者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
// ...
Looper.prepareMainLooper();
long startSeq = 0;
// 省略从 args 解析 startSeq 的代码
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// ...
Looper.loop();
// ...
}

// 准备主线程的 Looper
// frameworks/base/core/java/android/os/Looper.java
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

// prepare 方法中会创建一个 Looper 对象
// frameworks/base/core/java/android/os/Looper.java
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

// Looper 对象创建的时候,同时创建一个 MessageQueue
// frameworks/base/core/java/android/os/Looper.java
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

主线程完成初始化后,Looper 从队列取可执行 Message,交给目标 Handler 串行分发。Application、Activity、Service 和通常的 BroadcastReceiver 回调主要在主线程,但不能据此说组件的所有方法都在主线程:ContentProvider 的 onCreate() 在主线程,远程数据访问通常由 Binder 线程处理,需支持并发;广播也可指定调度 Handler。下面只节选 H 的部分常量和 BIND_APPLICATION 分支。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// frameworks/base/core/java/android/app/ActivityThread.java
class H extends Handler {
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;

public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
}

这部分可以看 Android Systrace 基础知识 - MainThread 和 RenderThread 解读 这篇文章

系统机制 - Message 机制

Looper.loop() 会取出当前可执行的 Message;没有可执行项时才进入等待,不保证刚进入 loop 就一定休眠。延迟消息可能尚未到期,同步屏障也可能挡住同步消息。输入和显示事件还会经 native Looper 的文件描述符回调进入,并非所有唤醒都对应一条普通 Java Message。

从下图可以看到 ,Android Message 机制的核心就是四个:Handler、Looper、MessageQueue、Message

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled%203.webp

网上有很多关于 Message 机制代码细节的分析,所以这里只是简单介绍 Message 机制的四个核心组件的作用

  1. Handler:把 Message/Runnable 交给指定 Looper 的线程执行;创建 Handler 本身不创建线程。隐式选择当前 Looper 的旧构造方法已弃用,没有当前 Looper 时还会抛异常。应用代码应明确使用如 new Handler(Looper.getMainLooper()) 的目标。
  2. Looper:取出可执行 Message,调用其 target 的 dispatchMessage();Runnable、Handler.Callback 与 handleMessage() 有各自分发路径。setMessageLogging() 可观察分发前后,传统 APM 会利用它,但测到的墙钟时长可包含等待,不覆盖队列等待、GPU 和呈现全过程,日志本身也有开销。
  3. MessageQueue:在这里的 Android 10 实现中按执行时间管理消息,并处理屏障/异步消息。nativePollOnce 通向 native Looper 等待,可能由事件、唤醒或到期时间结束;不是只在队列完全为空时等待,也不是任何入队都立即执行。异步 Message 仍在同一 Looper 线程执行,不是新后台线程。
  4. Message:携带 what、arg1、arg2、obj 或 Runnable callback 等信息,实际处理由目标 Handler 决定。

具体合同见 Handler API 和 ContentProvider 线程说明。框架内部结构需按系统版本查源码。

系统机制 - 屏幕刷新机制 和 Vsync

首先我们需要知道什么是屏幕刷新率,简单来说,屏幕刷新率是一个硬件的概念,是说屏幕这个硬件刷新画面的频率:举例来说,60Hz 刷新率意思是:这个屏幕在 1 秒内,会刷新显示内容 60 次;那么对应的,90Hz 是说在 1 秒内刷新显示内容 90 次

与刷新率对应,FPS 描述每秒帧数,统计口径可在应用生成、提交或屏幕呈现等阶段。60 Hz 屏幕可以承载 30 fps 内容;应用也可能生成过多帧,其中一些没有呈现。Android 11 引入的 多刷新率支持 还允许系统结合显示模式、策略和内容需求选择刷新率,不能认为硬件频率永远固定或与应用 fps 一一对应。

Vsync(Vertical Synchronization)为显示更新及图形流水提供时序参考,帮助协调提交与呈现。它不会保证应用生成足够的帧,也不能靠一个开关消除所有卡顿。

目标节奏 相邻目标帧间隔
60 fps 约 16.67 ms
90 fps 约 11.11 ms
120 fps 约 8.33 ms

这些是周期,不是所有线程通用的超时阈值。实际可用预算取决于帧开始、调度预测、流水深度、GPU 与合成期限;即使每段 CPU 工作都小于 16.67 ms,也不能据此证明没有迟到呈现。

延伸阅读:

  1. Android 新的流畅体验,90Hz 漫谈
  2. Android Systrace 基础知识 - Vsync 解读

系统机制 - Choreographer

Choreographer 是应用帧回调的协调器。需要动画或遍历时,它请求帧时机,再按阶段执行到期回调;静态界面无需每次物理刷新都绘制。60 Hz 只是例子,不应在应用中硬编码 16.6 ms。回调的帧时间用于动画计算,也不是回调开始执行或最终呈现的保证时刻。

Choreographer 承接上下游:

  1. 处理回调:Android 10 的顺序包括 Input、Animation、Insets Animation、Traversal、Commit。图只画了主要阶段;不是所有输入都等待 Input 阶段,也不是每帧都需 measure/layout。迟执行的日志是线索,不是屏幕最终掉帧统计。
  2. 请求显示时序:通过 FrameDisplayEventReceiver 请求/接收 Vsync,再向所属 Looper 安排异步消息执行 doFrame。这里的“异步”能越过同步屏障,但不能抢占正在执行的主线程任务。应用公开入口可用 Choreographer.postFrameCallback(API 16 起),该回调执行一次,持续动画需按生命周期继续请求。

下图就是 Vsync 信号到来的时候,Choreographer 借助 Message 机制开始一帧的绘制工作流程图

这部分详细的流程可以看 Android 基于 Choreographer 的渲染机制详解 这篇文章

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled%204.webp

系统机制 - Buffer 流程和 TripleBuffer

BufferQueue 连接图形 Buffer 的生产者和消费者,交换的是 Buffer 的使用权、元数据与同步信息,不是每次 queue 都复制整张图片。生产者和消费者可以在不同进程,也可以位于同一进程。下面先用旧式应用 Surface → SurfaceFlinger 的队列模型解释。

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled%205.webp

旧式窗口 Surface 路径中,应用是生产者,SurfaceFlinger 消费其提交的图形内容:

  1. dequeueBuffer() 取得可写槽位/Buffer;不是“释放 Buffer”。需要遵守返回的同步 fence,才能安全复用内存。
  2. 应用通过 CPU 或 GPU 生成内容,queueBuffer() 提交 Buffer 和就绪 fence。GPU 工作可能仍在执行;queue 完成不等于像素已经全部可读。
  3. 消费者通过 acquireBuffer() 取得内容及其 fence,并在正确的同步条件下使用。SurfaceFlinger 会结合计划时刻选择适合的内容,并不是每个 Vsync 都必然 acquire 一张新图。
  4. 消费方不再需要旧 Buffer 后,通过 release 及相应 fence 交还复用条件。CPU 上 release 调用返回,不保证显示/GPU 对这块内存的访问已结束。

图形内存和同步合同见 BufferQueue 与 同步框架。一个应用可以有多个 Surface/队列,容量与实际分配量由具体路径和两端配置决定,不是“每个应用固定三个 Buffer”。

现代路径补充:AOSP android-16.0.0_r1 的 BLASTBufferQueue 在客户端 acquire Buffer,再通过 SurfaceControl Transaction 的 setBuffer 把 Buffer 和 fence 交给 SurfaceFlinger。因此,旧图“队列消费者就在 SurfaceFlinger”不能直接套到所有现代窗口。

下图是双 Buffer 和 三 Buffer 的一个对比图

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled%206.webp

三 Buffer 可以增加生产和消费之间的重叠空间:

  1. 减少等待空闲 Buffer:当一张还在消费、另一张正在生成时,多一个可用 Buffer 可能让生产者继续工作。dequeue 等待常见于 RenderThread/生产线程,也可能经同步传到主线程。
  2. 缓冲短时波动:已经排队且及时就绪的内容,可能维持某个显示周期的更新。图中的“两次重复减少到一次”只对应所画的时序,不是通用收益;它仍画出了第一处重复帧。
  3. 无法消除持续瓶颈:更多 Buffer 不会缩短 GPU 执行,也不能修复持续超过预算的生产/合成。App 与 SurfaceFlinger 的 Vsync 可以有不同相位,不能假定同时唤醒。GPU 命令由应用图形栈提交,BufferQueue 不是等待 SurfaceFlinger 来启动 GPU 的任务队列。

代价除内存外还有潜在的排队延迟。队列越深,用户输入对应的画面可能越晚呈现;应同时看流畅度与响应时间,不是 Buffer 越多越好。

这部分详细的流程可以看 Android Systrace 基础知识 - Triple Buffer 解读 这篇文章

系统机制 - Input 流程

点击、移动等输入是常见的事件来源。旧图中的 InputReader 和 InputDispatcher 是 system_server 内的 native 线程;线程位置和 trace 标签仍需按具体系统核对。长按则通常由手势逻辑根据按下时刻与后续事件判定,不是 EventHub 直接读到一个“长按”硬件事件。

  1. InputReader 从 EventHub 读取设备事件,完成解释/转换后送往分发链路。
  2. InputDispatcher 根据焦点、触摸目标和策略等选取目标,发到相应窗口/monitor 的 InputChannel;不是向所有应用广播。
  3. OutboundQueue 是某个 Connection 尚待发布的事件队列,不能当作整个应用的全部输入。
  4. WaitQueue 记录已发布但尚待完成确认的事件;完成确认可以是 handled=false,不是只有“处理成功”才出队。队列长度也不是耗时。
  5. PendingInputEventQueue 是应用 ViewRootImpl 的待投递队列。Android 10 在调用 deliverInputEvent 前就减计数,归零不表示处理或屏幕反馈已完成。
  6. deliverInputEvent 是事件投递到应用输入阶段的异步 trace 区间,结束于 finishInputEvent;不是线程唤醒时刻,区间也未必都是 CPU 执行。
  7. 旧查看器的 Input Response / Rendering Response 是交互分组,不能直接当作物理触摸到屏幕发光的完整延迟。
  8. 应用处理输入后可能请求更新。手指释放后是否继续 fling 取决于速度、边界和手势逻辑;不能由 UP 一律推断 fling。输入完成 ACK 也不等于新画面已呈现。

上面流程对应的 Systrace 如下

/images/Systrace-Smooth%20e5d284a979a447ad8b45ff021d6e41cf/Untitled%207.webp

这张图来自魅族 Launcher,前文另有 OPPO Launcher 与 Matrix 示例,不能拼成同一设备、同一次采集的因果链。图中的绿色 F 是旧查看器的帧分析标记,不独立证明 GPU 完成或最终显示正常。

这部分详细的流程可以看 Android Systrace 基础知识 - Input 解读 这篇文章

系列文章

  1. Systrace 流畅性实战 1 :了解卡顿原理
  2. Systrace 流畅性实战 2 :案例分析: MIUI 桌面滑动卡顿分析
  3. Systrace 流畅性实战 3 :卡顿分析过程中的一些疑问

附件

附件已经上传到了 Github 上,可以自行下载:https://github.com/Gracker/SystraceForBlog/tree/master/Android_Systrace_Smooth_In_Action

  1. xiaomi_launcher.zip : 桌面滑动卡顿的 Systrace 文件,这次案例主要是分析这个 Systrace 文件
  2. xiaomi_launcher_scroll_all_the_time.zip : 桌面一直按着滑动的 Systrace 文件
  3. oppo_launcher_scroll.zip :对比文件

2026-10-14 核查时,上述三个 ZIP 均可下载,CRC 校验通过,内含旧 Systrace HTML 和 ftrace 数据。它们是历史采集,不是当前设备复现;未重跑操作,也未验证内嵌旧查看器在当前浏览器中的兼容性。分析时应使用支持该格式的工具,不能给旧数据补算不存在的 FrameTimeline 信息。

源码参考:ActivityThread、Looper、MessageQueue、Choreographer、ViewRootImpl,均为 android-10.0.0_r1。

关于我 && 博客

下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!

  1. 博主个人介绍 :里面有个人的微信和微信群链接。
  2. 本博客内容导航 :个人博客内容的一个导航。
  3. 个人整理和搜集的优秀博客文章 - Android 性能优化必知必会 :欢迎大家自荐和推荐 (微信私聊即可)
  4. Android性能优化知识星球:付费社群已于 2026 年停止运营,不再招收新成员;此处保留历史介绍。

一个人可以走的更快 , 一群人可以走的更远

微信扫一扫

CATALOG
  1. 1. 本文目录
  • 了解卡顿原理
    1. 1. 卡顿现象及影响
    2. 2. 卡顿定义
      1. 2.1. 应用一帧渲染的整体流程
      2. 2.2. 从执行顺序的角度来看
      3. 2.3. 从 Systrace 的角度来看
    3. 3. 卡顿定义
      1. 3.1. Android 12 及以上:结合 FrameTimeline
  • 系统运行机制简介
    1. 1. 系统机制 - App 主线程运行原理
    2. 2. 系统机制 - Message 机制
    3. 3. 系统机制 - 屏幕刷新机制 和 Vsync
    4. 4. 系统机制 - Choreographer
    5. 5. 系统机制 - Buffer 流程和 TripleBuffer
    6. 6. 系统机制 - Input 流程
  • 系列文章
  • 附件
  • 关于我 && 博客