上一篇讲了 MVI 架构,切换到性能分析工具——Systrace 与 Perfetto。每个 Android 工程师都该会 Systrace 抓问题,但 Perfetto 是更强的下一代工具。这篇把它们一起讲清楚。
Systrace 是什么
Systrace 是 Android 自带的性能分析工具,记录设备在指定时间段内所有进程、线程的活动:
[Systrace 输出样例简化]
process: com.example.app
线程 main:
Task: onCreate 0ms -- 50ms
Task: setContentView 50ms -- 200ms
Task: user input handled 200ms -- 250ms
[(等待)] 250ms -- 800ms <- 卡!
底层数据源:Linux kernel ftrace(ftrace 是 Linux 内核 trace 工具)。Android 在 ftrace 上包了一层。
命令行抓 trace
# 1. 确保 adb 调试就绪
adb devices
# 2. 进入开发者选项,打开"USB 调试"和"跟踪"选项
# 3. 监控 5 秒,操作你的 App
adb shell atrace --async_start -t 10 view gfx input webview am wm res dalvik
# 4. 或者直接抓 + 拉取
adb shell atrace --async_dump > /tmp/mytrace.html
# 5. 打开 mytrace.html 看图
open /tmp/mytrace.html
参数说明:
注意:-async_start 是后台运行不阻塞,后台启动后再操作 App,结束时 atrace --async_stop。
Perfetto 比 Systrace 强在哪里
Perfetto 是 Google 主导的下一代 tracing 工具,整合了:
Systrace(系统级)
ftrace(内核)
atrace(Android)
Chrome trace format
自定义事件
Perfetto 命令行使用
# 1. 启动录制
adb shell perfetto \
--out /data/misc/perfetto-traces/trace.perfetto-trace \
--time_in_state 10 \
--async
# 2. 抓 10 秒后停止
sleep 10
adb shell kill -INT $(pidof perfetto)
# 3. 拉取
adb pull /data/misc/perfetto-traces/trace.perfetto-trace
# 4. 在 https://ui.perfetto.dev 上传查看
指定配置(录制自定义数据):
cat > config.txt << 'EOF'
duration_ms: 10000
buffers: {
size_kb: 2048
fill_policy: DISCARD
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched"
ftrace_events: "task_rename"
}
}
}
data_sources: {
config {
name: "android.process_stat"
}
}
data_sources: {
config {
name: "android.surfaceflinger"
}
}
EOF
adb push config.txt /data/local/tmp/trace_config.txt
adb shell perfetto -c /data/local/tmp/trace_config.txt \
--out /data/misc/perfetto-traces/trace.perfetto-trace
更详细的配置可见 Perfetto 文档。
在代码里插桩自定义事件
Systrace(ATRACE)
// Native
ATRACE_BEGIN("MyModule::init");
doSomething();
ATRACE_END();
// Java
import android.os.Trace;
Trace.beginSection("LoadUser");
loadUser();
Trace.endSection();
Perfetto(更强大)
// 1. 添加依赖
dependencies {
implementation("androidx.tracing:tracing-perfetto:1.0.0")
}
// 2. 注册自定义事件
import androidx.tracing.perfetto.Tracing
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Tracing.enable()
}
}
}
// 3. 业务里打点
Tracing.trace("MySection", block = { ... })
// 协程集成
Tracing.traceCoroutine("MyNetworkCall") {
api.fetchData()
}
自定义事件能在 Perfetto UI 上专门过滤。
分析常见问题模式
1. 启动慢
打开启动 trace,重点看:
[zygote 启动] 0ms -- 200ms
[classloader 加载 classes.dex] 200ms -- 800ms <- 关注
[Application.onCreate] 800ms -- 1200ms
[Activity.onCreate] 1200ms -- 1500ms
[第一次 measure/layout] 1500ms -- 2500ms <- 关注
常见优化点:
classloader 加载时间 → 用 Baseline Profiles 提前 AOT
onCreate 耗时 → 移到工作线程
第一次 measure/layout → 拆解布局、减少嵌套
2. 卡顿
滑动列表卡顿时,每个 frame 应该 16ms(60Hz)或者 8.3ms(120Hz):
[vsync 0] 0ms
[Choreographer.doFrame 0] 0.5ms
[measure] 0.5ms -- 4ms
[layout] 4ms -- 6ms
[draw] 6ms -- 12ms
[swap buffers] 12ms -- 15ms
[vsync 1] 16.6ms
[Choreographer.doFrame 1] 17.1ms
[measure] 17ms -- 25ms <- 拖了 5ms
[layout] 25ms -- 30ms
[draw] 30ms -- 50ms <- 掉帧!
Perfetto UI 上能看每个 vsync 是不是 16ms 间隔,红色就是掉帧。
3. ANR
ANR 时 trace 关键看:
主线程 task 持续时间
Binder call 阻塞时间
主线程 sleep/wait
Binder 阻塞最常见,主线程调用其它服务被卡。常见的有:
ContentProvider 创建
Application.onCreate 里的网络请求(!)
BroadcastReceiver 长任务
Perfetto 与网络分析结合
新版 Perfetto 能录制网络包:
# data sources 里加
data_sources: {
config {
name: "android.network_packets"
}
}
或者用 Network Inspector(Android Studio 自带),能直接看每个请求的时间、响应、stack。
自己用 Perfetto 分析冷启动
# 1. 把 App 杀掉
adb shell am force-stop com.example
# 2. 后台启动 trace
adb shell perfetto --async_start -c /sdcard/config.txt
# 3. 启动 App
adb shell am start -n com.example/.MainActivity
# 4. 等 5 秒,停止
sleep 5
adb shell kill -INT $(pidof perfetto)
# 5. 拉取 trace
adb pull /data/misc/perfetto-traces/trace.perfetto-trace
# 6. 上传到 ui.perfetto.dev
可以对比优化前后的两版 trace,看启动时间是否降了。
自动化测试
CI 里跑 Systrace 做性能回归:
@Test
fun verifyStartUpTime() {
val startTime = System.currentTimeMillis()
activityScenario.launch(MainActivity::class.java)
// 验证主 Activity 完整显示
onView(withId(R.id.main_content)).check(matches(isDisplayed()))
val totalTime = System.currentTimeMillis() - startTime
assertThat(totalTime).isLessThan(2000) // 启动小于 2 秒
}
但更精确的是:
// macrobenchmark
@RunWith(AndroidJUnit4::class)
class StartupBenchmarks {
@get:Rule
val rule = MacrobenchmarkRule()
@Test
fun coldStartup() = rule.measureRepeated(
packageName = "com.example",
metrics = listOf(StartupTimingMetric()),
compilationMode = CompilationMode.DEFAULT,
startupMode = StartupMode.COLD,
iterations = 5
) {
pressHome()
startActivityAndWait()
}
}
实战经验
1. 不要在生产环境开 trace
ATRACE_BEGIN 是有开销的。线上只在上报问题时偶尔抓。
2. 性能回归用 Baseline Profiles
只要加了 Baseline Profiles,冷启动跑 Systrace 会快 30%+。
3. 看 trace 别只看主线程
RenderThread、SurfaceFlinger、Binder 线程都可能出瓶颈。
4. 数据量太大时的过滤
Perfetto 录制 1 小时可能上 GB 体积。在 UI 里只关注一个进程的:
slice_filter: {
name_filter: "com.example.app*"
}
5. UI 上善用快捷键
W: 放大时间窗口
A: 缩小时间窗口
D: 下一个 vsync(帧)
小结
Systrace 是 Android 性能分析的"老一辈",Perfetto 是"新贵"。两者协同覆盖大多数场景:日常快速排查用 Systrace,深入分析(小时级 trace、多源数据)用 Perfetto。理解 trace 数据格式,自定义事件插桩是进阶必修课。每个 Android 工程师都该掌握基本 trace 分析,定位性能问题远不止看 profiler。
下一篇进入前台服务与后台限制,理解 Android 14/15 在后台治理上的所有新规则。