第4章 工具介绍:Systrace / Perfetto 基础使用

做 SystemUI 启动优化,最重要的就是先看清楚它到底慢在哪。我见过不少同学上来就直接翻代码,改了一堆东西,结果跑完一看……根本没动到点子上。说白了,你得先有工具帮你看清“时间去哪了”。

Systrace 和 Perfetto 就是干这个的。它们不是替代关系,而是进化关系。Systrace 是老牌工具,Perfetto 是它的升级版,功能更强、数据更全。我的建议是:新项目直接用 Perfetto,旧环境或者只想快速看个大概,Systrace 照样能打。

Systrace / Perfetto 分析流程 SystemUI 启动慢 Systrace Perfetto adb shell atrace ... adb perfetto ... 打开 UI 查看器分析 定位主线程 / Binder 瓶颈 修改代码 → 重新验证

4.1 Systrace:快速上手

Systrace 从 Android 4.1 就存在了。别看它老,抓取一次启动过程也就几十 KB 到几 MB,轻量又好用。我到现在有些快速排查场景还是会用它,毕竟开 Perfetto 有时候还要配置协议文件,Systrace 一条命令搞定。

核心命令:
# 抓取 SystemUI 启动过程(系统层 + 应用层)
adb shell atrace -b 16384 -t 10 --async_start sched freq gfx am wm

# 开始抓取前启动 SystemUI(假设正在重启)
adb shell am start -S com.android.systemui

# 稍等几秒后停止
adb shell atrace --async_stop -o /data/local/tmp/trace_output
adb pull /data/local/tmp/trace_output systrace_output.html

抓下来的 html 文件直接用 Chrome 打开就能看。你会看到类似“瀑布图”一样的彩色条带。这时候要关注哪几段?我个人经验是优先看这几个地方:

  • 主线程(tid=…):有没有长时间运行的函数?比如 inflate 布局、执行 Binder 调用。
  • Binder 线程:SystemUI 启动过程中经常跟 SystemServer 做 RPC,如果是等待回复导致时间长了,就要看具体是哪个服务慢。
  • SurfaceFlinger:第一帧出来的时间,通常能从 SF 的合成耗时上看出来。
⚠️ 注意: Systrace 默认只抓少数标签(如 sched, freq, gfx, am, wm)。如果你需要分析 I/O 或 binder 详细 lock 时间,记得加上 –a app 或开启 –k tags=…。否则你想看的细节很可能根本没记录。我曾经因为没加 binder 标签,排查一个 Binder 死锁浪费了一个下午……嗯,从那以后我每次抓 trace 前都会检查标签列表。

4.2 Perfetto:新一代王牌

Perfetto 是 Systrace 的继承者。Android 10 开始引入,现在几乎成了官方唯一推荐的 trace 工具。它的优势在于:数据源更丰富(能看内存、I/O、调度延迟等),而且不需要事先开启 ftrace 缓冲区,按需记录。

你想想看,如果你要分析启动过程中到底有多少次布局重新计算,Systrace 只能告诉你“这个函数花了多少 ms”,但 Perfetto 能告诉你“这两个 CPU 核心之间的迁移延迟”……粒度完全不是一个级别。

抓取命令(直接输出 protobuf 格式):
# 抓取 10 秒,包含常见的调度、Binder、渲染、窗口管理器
adb shell perfetto \
  -c - --txt \
  -o /data/local/tmp/startup.perfetto-trace <

然后用浏览器打开 https://ui.perfetto.dev 加载这个文件。注意:这个工具完全在本地运行,不会上传数据。

4.3 两者对比:什么时候选哪个?

维度 Systrace Perfetto
命令长度 短,一条搞定 需要配置文件,稍复杂
数据格式 HTML(含视图) protobuf(需 UI 加载)
可记录数据源 有限(ftrace 标签 + atrace) 丰富(ftrace + 内存 + 堆栈 + 自定义)
能看线程唤醒延迟 不直观 ✅ 有 sched_wakeup 等事件
适合快速打卡 ✅ 有点重
适合深入分析 不够 ✅
💡 我的习惯: 日常开发验证用 Systrace,因为快;到了要发版本前一两个月,或者遇到了玄学卡顿,我就会切换到 Perfetto,把调度、内存、I/O 全开,一次抓 30 秒,然后慢慢分析。(启动场景一般 10~15 秒够用)

4.4 避坑指南 & 实战技巧

  1. 别忘了关掉其他动画/窗口
    抓启动时,最好确认系统没有其他窗口动画在跑(比如前台有悬浮窗、输入法弹窗等),否则 trace 里会混入大量无关的渲染帧。
  2. 抓取时机要准
    我通常先 adb shell am force-stop com.android.systemui,然后立即执行 adb shell am start -S com.android.systemui,同时用 atrace 的 --async_start + 延迟停止模式。Perfetto 简单些,直接配好 duration_ms 即可。
  3. 看清线程名称
    SystemUI 的主线程名是 android.ui 或 main。有时 binder 线程会显示为 Binder:2xxx。记得在 UI 里搜索 main 或者 SystemUI 快速定位。
  4. 标记时间轴
    在 Systrace 或 Perfetto 里可以用 Trace.beginSection("xxx") 在代码里打标记,这样你在 trace 里就能清晰地看到自己关心的区间。我在排查 Keyguard 动画时,就在 onDraw 前后加了 begin/end 段,然后再配合 CPU 频率变化,一眼就看出来是频率没拉起来导致的掉帧。
总结: Systrace 和 Perfetto 不是二选一,而是互补。我会在团队里统一推荐 Perfetto,因为长期看它的数据更完整、分析工具更强。但如果你在客户现场、网络限制、或者只想看一眼大概,Systrace 仍然是无可替代的“快刀”。这两个工具,你都应该熟练掌握。