第3章 录制卡顿Trace的三种方式与参数选择规则

卡顿排查的第一步是获取高质量的Trace数据。本章围绕“数据采集”阶段,系统讲解命令录制、代码插桩、系统跟踪三种方式及其参数选择规则。你将在实际定位卡顿时,根据问题场景快速选定正确的录制方案。

三种录制方式总览

方式 核心原理 适用场景 优势 限制
命令录制 通过adb/perfetto命令触发一次性的Trace采集 线上/测试环境临时抓取;快速复现卡顿 无需代码改动,即刻使用 依赖终端操作;无法自定义高级触发条件
代码插桩 在应用源码中嵌入Perfetto SDK,按特定逻辑启动/停止Trace 自动触发埋点;精准采集用户操作路径 可定制触发时机;可附带自定义标签 需要集成SDK,增加包体积
系统跟踪 通过系统服务(如long trace)或开发者选项持续采集 系统级卡顿分析;多进程交互问题 覆盖所有进程;支持超长录制 文件体积大;需root或debug构建

方式一:命令录制

命令录制是最灵活的临场式采集方式。典型流程:连接设备 → 设置ATRACE标签 → 执行perfetto命令 → 复现问题 → 停止并拉取Trace。

基础命令模板

adb shell perfetto \
  -o /data/misc/perfetto-traces/card_issue.pb \
  -t 10s \
  -b 32mb \
  sched freq idle am wm gfx view input

参数含义

  • -o:输出路径(必须写入可写分区,建议/data/misc/perfetto-traces/)
  • -t:持续时长,卡顿场景建议10~30秒
  • -b:缓冲区大小,复杂场景推荐32~64 MB
  • 末尾为数据源,卡顿分析必须包含:sched(调度)、gfx(图形)、view(视图)、input(输入)

典型卡顿采集命令

adb shell perfetto \
  -o /data/misc/perfetto-traces/jank_test.pb \
  -t 15s \
  -b 64mb \
  sched freq idle am wm gfx view input
经验法则:线上设备若无法root,使用debug版本或通过adb shell atrace降级采集(功能受限)。优先使用perfetto命令,数据更完整。

方式二:代码插桩

在应用关键路径(如点击响应、列表滑动、动画开始/结束)中嵌入Perfetto SDK的Trace开始/结束调用,实现“按需录制”。

集成要点

// 引入Perfetto SDK
#include "perfetto/tracing.h"

// 定义类别
PERFETTO_DEFINE_CATEGORIES(
    perfetto::Category("app.jank")
        .SetDescription("应用卡顿相关事件"),
    perfetto::Category("app.network")
        .SetDescription("网络请求"));

// 在需要录制的代码段中
TRACE_EVENT("app.jank", "UserClick", "button_id", buttonId);
// ... 实际业务逻辑 ...
TRACE_EVENT_END("app.jank");

参数选择规则

在代码中设置录制时长、缓冲区、数据源时,建议通过远程配置下发,避免硬编码:

// 动态启动Trace
perfetto::Tracing::Begin(
    perfetto::TraceConfig cfg;
    cfg.set_duration_ms(10000);
    cfg.add_buffers()->set_size_kb(32768);
    auto* ds = cfg.add_data_sources();
    ds->mutable_config()->set_name("track_event");
    // 可选:只采集当前进程
    ds->mutable_config()->set_target_buffer(0);
    // 开始录制
    TracingSession::Setup(cfg);
);
注意:插桩录制会引入额外的trace overhead。生产环境务必限制单次录制时长≤30秒,缓冲区≤64 MB,并使用开关量控制录制启动。

方式三:系统跟踪

系统跟踪用于排查无法在单一应用内复现的卡顿(如后台服务抢占、SystemUI响应延迟)。通过perfetto --background或开发者选项中的“系统跟踪”开启持续录制。

启动命令(后台模式)

adb shell perfetto \
  --background \
  -o /data/misc/perfetto-traces/long_trace.pb \
  -c /data/local/tmp/long_trace.cfg

配置文件示例(long_trace.cfg)

duration_ms: 300000  # 5分钟
buffers {
    size_kb: 65536
    fill_policy: RING_BUFFER
}
data_sources {
    config {
        name: "linux.syscalls"
    }
}
data_sources {
    config {
        name: "android.surfaceflinger.frametimeline"
    }
}
data_sources {
    config {
        name: "android.app.packages"
        target_buffer: 0
    }
}
# 只针对系统关键进程,减少体积
incremental_state_config {
    clear_period_ms: 5000
}
适用判断:当卡顿发生在系统动画(如通知栏下拉、多任务切换)或多个应用交替阻塞时,优先使用系统跟踪,配置RING_BUFFER以避免磁盘爆满。

录制参数选择规则

场景特征 推荐方式 缓冲区 时长 关键数据源
应用内滑动/点击瞬间卡顿 命令录制 32 MB 15 s gfx, view, input, sched
首帧渲染慢/启动黑屏 代码插桩(在Application.onCreate中启动) 64 MB 20 s gfx, track_event, startup
系统级卡顿(通知、多任务) 系统跟踪(后台模式) 128 MB (RING_BUFFER) 300 s surfaceflinger, input, sched, freq
网络请求导致UI冻屏 代码插桩(网络库侧边注入) 16 MB 30 s track_event (net events), sched
线上用户偶发卡顿,无法复现 代码插桩 + 远程开关(预埋) 32 MB 按用户操作触发 gfx, view, app自定义事件

故障树:选择正确的录制方式

以下决策树可帮助你在接到卡顿报告后,快速定位最合适的Trace采集路径:

录制方式决策树 卡顿现象报告 是否可以稳定复现? 是 → 命令录制 adb shell perfetto -t 15s -b 32mb 否 → 预埋插桩 代码内嵌入SDK 远程开关控制 是系统级卡顿吗? 系统跟踪(后台) 命令录制/插桩 参数选择参考右侧表格 注意缓冲区与时长限制

排查清单:录制前的检查项

  1. 确认设备已开启“开发者选项”和“USB调试”。
  2. 检查存储空间:至少预留500 MB可用空间(避免Trace写入失败)。
  3. 关闭不必要的后台进程(如游戏、高清视频播放),减少Trace中的噪音。
  4. 根据卡顿现象选择正确的数据源(必选:sched, gfx, input;可选:freq, idle, am)。
  5. 录制时长:尽量短(10~30秒),避免产生超大文件。
  6. 若使用代码插桩,提前确认SDK版本与编译正确。
实践建议:日常开发中,提前在代码内集成Perfetto SDK并添加远程开关(通过Firebase Remote Config或本地调试面板),一旦线上出现卡顿报告,即可远程开启一次Trace,极大缩短数据获取时间。