2. 埋点技术基础:Systrace与Perfetto简介,Trace事件的类型,如何查看系统已有的trace点

咱们做AOSP启动优化,说白了就是在跟时间赛跑。想跑赢这场赛,必须有一把精准的“计时尺”和一张“地图”。说到工具,Systrace和Perfetto就是最趁手的两把。

2.1 从Systrace到Perfetto:工具的进化

Systrace是老前辈了,Android 4.1就开始用。它的核心是读取内核的ftrace和Android的ATRACE(应用层trace),然后生成一份HTML报告。我记得刚开始做启动优化时,全组都靠它吃饭。但你想想看,Systrace有两个硬伤——数据细节不够深,而且分析时交互做得比较粗糙。

Perfetto是2018年Google推出的新一代工具,可以理解成Systrace的“Pro Max版”。它不仅能抓ftrace和ATRACE,还能并抓heap profile、CPU调度、Binder延迟、GPU渲染等上百个数据源。启动耗时分析,如果没有Perfetto,说句不好听的,就像闭着眼睛开车。

一个重要事实:从Android 10开始,Google官方已经用Perfetto完全替代了Systrace。新项目不要再开Systrace了,Perfetto才是未来的方向。

2.2 Trace事件的核心类型:B/E、S/F、C

不管用Systrace还是Perfetto,底层的trace点都遵循同一套标记协议。基本上就三类,我直接给你们总结个表:

类型标记符语义典型示例
B / EB(begin)/ E(end)异步时间片开始和结束B|1234|inflation
E|1234
S / FS(start)/ F(finish)同步函数调用入栈/出栈S|1234|onCreate
F|1234
CC(counter)计数器,跟踪数值变化C|1234|MemFree:1048576

我刚开始做埋点的时候,总把B/E和S/F搞混。业内曾经有个笑话——用S/F标记的函数如果中间发生了异步回调,那trace图会乱成一锅粥。所以最佳实践是:同步调用用S/F,异步任务用B/E。

我的习惯:在写ATRACE时,如果函数的生命周期和调用线程完全绑定,就用S/F;如果任务可能跨线程或者存在post操作,一定用B/E。避免trace显示“反人类”的嵌套。

2.3 计数器(C)的妙用

C事件虽然看起来简单,但实际作用很大。它记录的是某个时刻的数值快照,比如剩余内存、CPU频率、帧率等。Perfetto的SQL分析引擎可以直接对C事件做聚合、求平均、画曲线,启动阶段的内存抖动通过C事件看得一清二楚。

避坑指南:我曾经在启动过程中埋了一个C事件记录“已加载的Class数量”,代码写的是每加载一个Class就更新一次。结果Perfetto图里出现了一条细密的“锯齿”——因为C事件更新太频繁,Perfetto采样率跟不上。所以C事件的更新间隔建议控制在1ms以上,否则数据会失真。

2.4 如何查看系统已有的trace点

你不需要从零开始手动埋点。AOSP有大量现成的trace点,关键是你要知道它们藏在哪。我总结了三条路:

  1. ATRACE宏:在frameworks/native/libs/utils/Trace.h中定义。源码里随处可见ATRACE_CALL()、ATRACE_NAME()等宏,直接启用即可。
  2. ftrace点:内核中的调度、中断、内存、文件系统等事件,通过/sys/kernel/tracing/available_events查看。Perfetto后台自动收集。
  3. Perfetto自带数据源:在Perfetto配置文件中声明data_sources,例如“android.surfaceflinger.trace”“android.hardware.power”等,Google已经内置好了。

怎么快速确认系统里到底有哪些trace点?我教你个命令:

adb shell atrace --list_categories

输出会列出所有当前设备支持的trace种类,像input、view、am、pm、rs、gfx等。如果你需要更底层的,可以看:

adb shell ls /sys/kernel/tracing/events/

这下面全是ftrace事件组,比如sched、irq、kmem、i2c、power等。每个组下面都有几十个事件,启动阶段最常用的是sched_switch、sched_wakeup、cpu_idle、tracing_mark_write。

关键技巧:如果你在Perfetto里看到一大块“灰色”区域,原因往往是某个trace点没有开启。检查一下你的profile配置中是否漏掉了对应数据源。我遇到过整整一天没找到“为什么SystemServer的某个阶段耗时200ms”,最后发现是没拉取binder_driver数据源。

2.5 知识结构全景图

埋点技术基础知识结构 埋点技术基础 Systrace 与 Perfetto Trace事件类型 查看已有trace点 Systrace ftrace + ATRACE Android 10前标配 Perfetto (替代Systrace) 多数据源、SQL分析 三类trace事件 B/E : 异步起止 S/F : 同步栈 C : 计数器 间隔≥1ms 查看方法 atrace --list_categories ls /sys/kernel/tracing/events Perfetto配置数据源 核心原则:同步用S/F,异步用B/E,计数器C间隔≥1ms

2.6 实战检查:我的设备有多少trace点?

我建议你马上打开终端,连上你的开发板或Pixel手机,跑一下:

adb shell atrace --list_categories
adb shell ls /sys/kernel/tracing/events/sched

如果第二行返回了一堆sched_switch、sched_wakeup之类的文件,说明内核trace点默认就开了。如果为空,可能是内核没打开ftrace,需要重新编译内核并配置CONFIG_FTRACE=y。

嗯,开头那俩命令的输出,建议你截图保存到笔记里。后续我们在做启动耗时分段时,需要用这些来确认到底是哪个子系统没数据。