4. 准备开发环境与性能工具链

做性能监控,第一步不是写代码,而是搭好环境、选对工具。我见过不少团队花了两周优化代码,结果发现是 profiling 工具没配好——测出来的数据本身就有问题。嗯,这一章我们就踏踏实实把工具链磨利,后面才能砍柴不费功。

4.1 开发环境基础要求

CameraX 本身是 Jetpack 库,依赖不算多,但性能监控需要一些额外配置。我个人习惯用 Android Studio 最新稳定版(目前是 Hedgehog 或 Iguana),Gradle 8.x + AGP 8.x。你想想看,Profiler 和 AGP 版本绑得很紧,老版本可能连 CPU 采样都做不了。

最低环境版本清单

Android StudioFlamingo (2022.2.1) 及以上
Gradle8.2+
AGP8.1+
minSdk26(Android 8.0)
compileSdk34

我在项目里遇到过一个问题:用了太旧的 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

工具链我分三层来说:快速定位层、深度分析层、自动化监控层。下面这张图帮你理清脉络——

性能工具链与开发环境 开发环境:Android Studio + Gradle + AGP 最新版 📱 CameraX SDK 1.3+(含内建 Trace) 🔍 Android Studio Profiler ⏱️ Systrace / Perfetto 📊 Macrobenchmark 📸 CameraX 启动 Trace 段 🧵 UI线程 + 相机线程 📈 启动时间 / 帧耗时 / 内存 & CPU 采样 建议:优先用 Perfetto 替代 Systrace(Android 10+),获取更细粒度的启动 Trace

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 时间:

  1. Android Studio 版本是否满足最低要求?
  2. 设备是否 Android 10+?(Perfetto 支持)如果不是,降级用 Systrace?
  3. CameraX 依赖是否 1.3+?是否开启了 debug 模式?
  4. 自定义 Trace 的 beginSection / endSection 是否成对?async 是否 id 唯一?
  5. 是否在 CI 上配置了 Macrobenchmark 任务?