4. 准备开发环境与性能工具链
做性能监控,第一步不是写代码,而是搭好环境、选对工具。我见过不少团队花了两周优化代码,结果发现是 profiling 工具没配好——测出来的数据本身就有问题。嗯,这一章我们就踏踏实实把工具链磨利,后面才能砍柴不费功。
4.1 开发环境基础要求
CameraX 本身是 Jetpack 库,依赖不算多,但性能监控需要一些额外配置。我个人习惯用 Android Studio 最新稳定版(目前是 Hedgehog 或 Iguana),Gradle 8.x + AGP 8.x。你想想看,Profiler 和 AGP 版本绑得很紧,老版本可能连 CPU 采样都做不了。
最低环境版本清单
| Android Studio | Flamingo (2022.2.1) 及以上 |
| Gradle | 8.2+ |
| AGP | 8.1+ |
| minSdk | 26(Android 8.0) |
| compileSdk | 34 |
我在项目里遇到过一个问题:用了太旧的 AGP,Perfetto 的 System Tracing 在 Android Studio 里直接灰掉了。排查半天,发现是 Studio 版本不匹配。所以建议你直接升级到最新,别省事。
4.2 CameraX 依赖与性能监控开关
在 build.gradle 里加依赖很简单,但性能监控需要开启一些试验性 API。看代码:
dependencies {
def camerax_version = "1.3.1"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-extensions:${camerax_version}"
// 性能监控需要的扩展库——其实核心就是 camera-camera2 自带的 trace
}
// 如果你需要 Macrobenchmark
androidTestImplementation "androidx.benchmark:benchmark-macro-junit4:1.2.3"
小技巧: 在 build.gradle 里加上 debuggable true 并关闭混淆,否则 Systrace 和 Perfetto 抓到的符号会全是 obfuscated,根本看不懂。我曾经因为这个浪费了整整一下午。
4.3 核心工具链:从 Profiler 到 Perfetto
工具链我分三层来说:快速定位层、深度分析层、自动化监控层。下面这张图帮你理清脉络——
4.4 三个工具怎么选?
我习惯这样区分场景——
- 快速验证:直接用 Android Studio Profiler 的 CPU 录屏,录一段 CameraX 启动过程,看主线程有没有明显卡顿。优点是零配置,缺点是精度一般,不能做批量对比。
- 深度定位:用 Perfetto(Android 10+)抓 trace。你想想看,Perfetto 能精确到微秒级,还能看到 SurfaceFlinger、HAL 层的相机驱动行为。我在一次线上崩溃排查时,就是靠 Perfetto 发现相机初始化里有一个写文件操作阻塞了主线程 200ms。
- 自动化回归:用 Macrobenchmark 写 `startupMode` 测试,配合 CI 每夜跑,自动对比启动时间变化。特别适合团队多人协作时防止性能回退。
⚠️ 避坑: 不要在非 root 设备上用 Systrace 抓 CameraX 的驱动 trace,很多厂商的相机服务在用户空间下不暴露关键事件。建议用 Perfetto 的 ftrace 模式 + camera tag,才能抓到真正的启动瓶颈。
4.5 自定义 Trace 的埋点原则
除了系统工具,我们还需要在代码里埋自定义 Trace。CameraX 本身已经帮你埋了核心步骤(比如 `CameraX.create`、`CameraX.bindToLifecycle`),但有时候我们需要更细的粒度,比如「打开相机硬件」到「第一帧回调」之间的时间。
埋点很简单:
// 在 CameraProvider 初始化前后
Trace.beginSection("CameraInit");
val cameraProvider = ProcessCameraProvider.getInstance(context).get()
Trace.endSection();
// 在 bindToLifecycle 前后
Trace.beginSection("BindLifecycle");
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)
Trace.endSection();
// 在 ImageAnalysis 回调中打点
Trace.beginAsyncSection("FirstFrame", 1);
// … 当 onImageAvailable 触发后
Trace.endAsyncSection("FirstFrame", 1);
个人经验: 埋点标签命名用「功能名_阶段」的模式,比如 CameraInit_waitForProvider 而不是 init。不然后面看 trace 图时会分不清谁是谁。我曾经把 10 个 trace 都叫 camera_start,结果 Perfetto 里叠在一起,根本看不出哪个是哪个。
4.6 自动采集脚本 & 基线配置
工具链的最后一步,是把它自动化。我写了一个简单的 Gradle Task,每次 build 完成后自动跑一次 Macrobenchmark:
// app/build.gradle 中配置
android {
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
}
// 在 androidTest 目录下创建 CameraStartupBenchmark.kt
@RunWith(AndroidJUnit4::class)
class CameraStartupBenchmark {
@Test
fun cameraStartup() {
val rule = MacrobenchmarkRule()
rule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric(), FrameTimingMetric()),
iterations = 10,
startupMode = StartupMode.COLD,
) {
startActivityAndWait()
}
}
}
跑完之后,结果会输出在 build/outputs/benchmark 目录下。我一般用 Excel 拉个 P50、P95 表格,贴在项目 Wiki 上做基线。
4.7 检查清单
最后,给你一个自检清单,动手前过一遍,能省很多 debug 时间:
- Android Studio 版本是否满足最低要求?
- 设备是否 Android 10+?(Perfetto 支持)如果不是,降级用 Systrace?
- CameraX 依赖是否 1.3+?是否开启了 debug 模式?
- 自定义 Trace 的 beginSection / endSection 是否成对?async 是否 id 唯一?
- 是否在 CI 上配置了 Macrobenchmark 任务?