Baseline Profile 是什么?这个项目该怎么优化?

  1. 背景知识

Android 应用的 Java/Kotlin 代码在运行时有三种执行模式:

┌───────────────────────────────┬─────────────────┬───────────────────────────────┐ │ 模式 │ 速度 │ 何时使用 │ ├───────────────────────────────┼─────────────────┼───────────────────────────────┤ │ 解释执行(Interpreter/Nterp) │ 最慢(~10x 慢) │ 首次运行、未编译的方法 │ ├───────────────────────────────┼─────────────────┼───────────────────────────────┤ │ JIT 编译 │ 中等 │ 运行中热点方法被 JIT 即时编译 │ ├───────────────────────────────┼─────────────────┼───────────────────────────────┤ │ AOT 编译(dex2oat) │ 最快 │ 安装时或系统构建时预编译 │ └───────────────────────────────┴─────────────────┴───────────────────────────────┘

Baseline Profile 就是一个文本文件,列出应用启动路径上的热点类和方法,告诉 ART:「这些方法请在安装时就 AOT 编译好,别等运行时再 JIT」。

  1. 当前 MiCarSettings 的实际状态

从 trace 中检测到:

有 OAT 文件,但只是 speed 模式(非 speed-profile):

  • 路径 /data/dalvik-cache/arm64/system@priv-app@MiCarSettings@MiCarSettings.apk@cla… 说明系统对 MiCarSettings 做了 dalvik-cache 级别的 dex2oat
  • 但 DexChecksumUpToDate(vdex) + Mapped=true Extracted=false 说明使用的是 vdex(verified dex)而非全量 oat

JIT 编译器在启动期间非常活跃:

  • 97 次 “Compiling baseline” 共 147ms——这正是 JIT 在启动期间紧急编译热点方法
  • ConstraintLayout 的 applyConstraints 单次 JIT 编译就花了 15ms
  • Gson 的 getBoundFields JIT 编译 11.5ms

解释执行占比高:

  • bindApplication 期间主线程采样中,解释器采样 244 次 vs 编译代码 20 次
  • 大量方法(NterpCommonInvokeStatic 13ms、NterpCommonInvokeInstance 5.5ms 等)在以解释模式运行
  1. 这意味着什么

当前 MiCarSettings 的编译状态是 「有 vdex 但缺少充分 AOT 编译」:

  • 类已验证(vdex),省去了类验证时间
  • 但方法体没有被编译为机器码,首次调用走解释器
  • JIT 线程在启动期间拼命编译(147ms),但来不及——主线程已经在解释执行中等待了

这就是 bindApplication 中 273ms 空白区的根因:主线程在以 ~10x 慢的解释模式执行类初始化和静态方法。

  1. 怎么优化

有两条路径,从易到难:

方案 A:系统构建时指定 speed-profile 编译(推荐,改动最小)

MiCarSettings 是 /system/priv-app/ 下的系统应用。在系统 makefile 中可以指定编译模式:

在 MiCarSettings 的 Android.mk 或 Android.bp 中

LOCAL_DEX_PREOPT := true LOCAL_DEX_PREOPT_FLAGS := —compiler-filter=speed

或在 BoardConfig.mk 中: PRODUCT_DEX_PREOPT_BOOT_FLAGS += —compiler-filter=speed PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER := speed

speed 模式会 AOT 编译所有方法,启动时直接执行机器码,不再需要解释执行。

可以先在设备上验证效果: adb shell cmd package compile -m speed -f com.android.car.settings

重启后测试冷启动

预期收益:273ms 空白区可缩减 50-70%(~130-190ms),因为所有方法在首次调用时直接走 AOT 编译后的机器码。

方案 B:添加 Baseline Profile(更精细)

如果不想全量 speed 编译(增加安装体积),可以只编译启动路径的热方法:

  1. 在项目中添加 app/src/main/baseline-prof.txt:

启动热路径类

HSPLcom/android/car/settings/miauto/SettingsApplication;onCreate()V HSPLcom/android/car/settings/miauto/MainThreadStartTask;execute()V HSPLcom/android/car/settings/miauto/VehiclePermanentListener;init()V HSPLcom/android/car/settings/miauto/GlobalCarPropertyManager;init(Landroid/content/Context;)V HSPLcom/android/car/settings/common/BaseCarSettingsActivity;onCreate(Landroid/os/Bundle;)V HSPLcom/android/car/settings/miauto/HomePageActivityReal;onCreate(Landroid/os/Bundle;)V

ConstraintLayout(JIT 编译热点 Top1)

HSPLandroidx/constraintlayout/widget/ConstraintLayout;** HSPLandroidx/constraintlayout/solver/;

Gson 反序列化

HSPLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory;**

  1. 添加 profileinstaller 依赖: implementation “androidx.profileinstaller:profileinstaller:1.3.1”

  2. 系统构建时使用 speed-profile 编译: LOCAL_DEX_PREOPT_FLAGS := —compiler-filter=speed-profile

  3. 快速验证

不改代码,直接在设备上验证 speed 编译的效果:

强制 speed 编译

adb shell cmd package compile -m speed -f com.android.car.settings

重启设备

adb reboot

对比冷启动时间

adb shell am force-stop com.android.car.settings adb shell am start-activity -W com.android.car.settings/.common.CarSettingActivities$HomepageActivity

对比编译前后的 TotalTime 差异,就能知道 AOT 编译能带来多少收益。

  1. 总结

┌──────────┬───────────────────────────────────────────────────────────────────────┐ │ 项目 │ 说明 │ ├──────────┼───────────────────────────────────────────────────────────────────────┤ │ 当前状态 │ vdex(已验证)但未 AOT 编译方法体,主线程大量解释执行 │ ├──────────┼───────────────────────────────────────────────────────────────────────┤ │ 根因 │ bindApplication 273ms 空白区中,方法以 ~10x 慢的解释模式运行 │ ├──────────┼───────────────────────────────────────────────────────────────────────┤ │ JIT 补救 │ JIT 线程在启动期间编译了 97 个方法(147ms),但来不及覆盖主线程热路径 │ ├──────────┼───────────────────────────────────────────────────────────────────────┤ │ 推荐方案 │ 系统 makefile 中设 compiler-filter=speed,全量 AOT │ ├──────────┼───────────────────────────────────────────────────────────────────────┤ │ 预期收益 │ 273ms 空白区缩减 50-70%,即省 ~130-190ms │ ├──────────┼───────────────────────────────────────────────────────────────────────┤ │ 验证命令 │ adb shell cmd package compile -m speed -f com.android.car.settings │ └──────────┴───────────────────────────────────────────────────────────────────────┘