Custom Baseline Profiles Optimization for Android Apps: Design, Implementation, and Evaluation
This article describes the background of Android code execution, the evolution from full AOT to JIT+AOT and Cloud Profiles, the limitations of Google Baseline Profiles, and presents a custom Gradle‑based solution that generates baseline.prof files for all AGP versions, integrates with the installation pipeline, collaborates with OEMs, and demonstrates measurable cold‑start improvements.
Background
On Android, Java/Kotlin code is compiled to DEX bytecode and interpreted at runtime, which is slow. Android 5 introduced full AOT compilation during installation, but it caused long install times and large disk usage. Starting with Android 7, a hybrid JIT+AOT model was adopted, and Android 9 added Cloud Profiles to collect hot methods from early adopters. In 2022 Google released Baseline Profiles, allowing developers to ship their own hot‑method lists for install‑time compilation, but the official solution requires AGP 7+, depends on Google Play, and cannot be used in many Chinese devices.
Solution Exploration and Implementation
The custom solution reproduces the official Baseline Profile workflow and adds two main stages:
Hot‑method collection: either run the app on a device or manually create a baseline-prof.txt file.
Compile‑time processing: convert the text file into binary baseline.prof and baseline.profm using the CompileArtProfileTask.kt logic.
Installation‑time processing: embed the binary files into the APK assets and let the system’s ArtManagerService handle them during install.
Hot‑method collection
The official approach uses the Jetpack Macrobenchmark library and BaselineProfileRule . The article shows that the same result can be achieved by invoking the profman command directly:
adb shell profman --dump-classes-and-methods \
--profile-file=/data/misc/profiles/cur/0/com.example.app/primary.prof \
--apk=/data/app/com.example.app-XXXX/base.apk > baseline-prof.txtThe generated baseline-prof.txt contains entries such as:
PLcom/example/MyClass;->a(Lcom/example/MyClass;)Ljava/lang/String;
HSPLorg/android/spdy/SpdyAgent;->initSo(Ljava/lang/String;I)ZEach line follows the [FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE] format, where flags H , S , P indicate Hot, Startup, or Post‑Startup methods.
Compile‑time processing
The text file is merged with any baseline‑prof.txt files from AndroidX libraries, then transformed into binary form by the CompileArtProfileTask (implemented in CompileArtProfileTask.kt ). The core steps are:
Read the human‑readable profile.
Apply ProGuard mapping if the APK is obfuscated.
Create ArtProfile and serialize it to baseline.prof and baseline.profm using ArtProfileSerializer .
Installation‑time processing
During install, the system calls ArtManagerService.prepareAppProfiles , which eventually invokes dexopt.cpp#prepare_app_profile . This forks a process that runs profman with file descriptors for the reference profile, the new profile, and the APK:
./profman --reference-profile-file-fd=9 \
--profile-file-fd=10 --apk-fd=11 \
--dex-location=/data/app/com.example.app-XXXX/base.apk \
--copy-and-update-profile-keyThe reference profile ( /data/misc/profile/ref/…/primary.prof ) stores the accumulated hot methods for the package; the new baseline.prof is merged into it.
Dex optimization
After profile merging, the PackageDexOptimizer triggers dex2oat with the --profile-file-fd argument. The compiler loads the profile via LoadProfile() , checks hot‑method flags, and only compiles methods marked as hot or startup. The decision is made in ShouldCompileBasedOnProfile :
bool result = profile_compilation_info->IsHotMethod(profile_index, method_ref.index);
return result;Compiled methods are emitted by CodeGenerator::Compile , and the OatWriter uses the hotness bits to place hot methods early in the OAT file, improving page‑level I/O.
Vendor cooperation
Because install‑time Baseline Profile requires Google Play, the team worked with domestic OEMs (Xiaomi, Huawei, etc.) to enable the feature without Play services. They provided APKs containing the binary profiles, and OEMs adopted strategies such as background compilation after install.
Compression handling
The binary baseline.prof must be stored uncompressed in the APK. The article shows how to write a JarEntry with STORED method, set size and CRC, and verify with unzip -v . The file size impact is negligible (≈62 KB for 70 k hot methods, < 1 % compression).
Optimization results
Testing on devices (Honor Android 11, Xiaomi Android 13) showed cold‑start time reductions of 6.9 % to 12.3 % (e.g., 950 ms → 884 ms). The improvement is measured via the TTID metric using adb shell am start-activity -W .
References & Team
Links to Android documentation, source code, and the ByteDance Xigua Video client team are provided.
Watermelon Video Tech Team
Technical practice sharing from Watermelon Video
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.