Baseline Profile 是什么?这个项目该怎么优化?
- 背景知识
Android 应用的 Java/Kotlin 代码在运行时有三种执行模式:
┌───────────────────────────────┬─────────────────┬───────────────────────────────┐ │ 模式 │ 速度 │ 何时使用 │ ├───────────────────────────────┼─────────────────┼───────────────────────────────┤ │ 解释执行(Interpreter/Nterp) │ 最慢(~10x 慢) │ 首次运行、未编译的方法 │ ├───────────────────────────────┼─────────────────┼───────────────────────────────┤ │ JIT 编译 │ 中等 │ 运行中热点方法被 JIT 即时编译 │ ├───────────────────────────────┼─────────────────┼───────────────────────────────┤ │ AOT 编译(dex2oat) │ 最快 │ 安装时或系统构建时预编译 │ └───────────────────────────────┴─────────────────┴───────────────────────────────┘
Baseline Profile 就是一个文本文件,列出应用启动路径上的热点类和方法,告诉 ART:「这些方法请在安装时就 AOT 编译好,别等运行时再 JIT」。
- 当前 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 等)在以解释模式运行
- 这意味着什么
当前 MiCarSettings 的编译状态是 「有 vdex 但缺少充分 AOT 编译」:
- 类已验证(vdex),省去了类验证时间
- 但方法体没有被编译为机器码,首次调用走解释器
- JIT 线程在启动期间拼命编译(147ms),但来不及——主线程已经在解释执行中等待了
这就是 bindApplication 中 273ms 空白区的根因:主线程在以 ~10x 慢的解释模式执行类初始化和静态方法。
- 怎么优化
有两条路径,从易到难:
方案 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 编译(增加安装体积),可以只编译启动路径的热方法:
- 在项目中添加 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;→**
-
添加 profileinstaller 依赖: implementation “androidx.profileinstaller:profileinstaller:1.3.1”
-
系统构建时使用 speed-profile 编译: LOCAL_DEX_PREOPT_FLAGS := —compiler-filter=speed-profile
-
快速验证
不改代码,直接在设备上验证 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 编译能带来多少收益。
- 总结
┌──────────┬───────────────────────────────────────────────────────────────────────┐ │ 项目 │ 说明 │ ├──────────┼───────────────────────────────────────────────────────────────────────┤ │ 当前状态 │ 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 │ └──────────┴───────────────────────────────────────────────────────────────────────┘