On this page
On a fresh install, ART hasn't yet learned which code your app runs most. It interprets or JIT-compiles hot paths, so the first launches and first scrolls are slower than later ones. A Baseline Profile ships that knowledge with your app.
How it works
Setup with the Gradle plugin
In Android Studio, add a module from the Baseline Profile Generator template. It creates a test module and applies the androidx.baselineprofile plugin. The resulting configuration looks like this:
plugins {
id("com.android.application")
id("androidx.baselineprofile")
}
dependencies {
implementation("androidx.profileinstaller:profileinstaller:<version>") // installs profiles for sideloaded/non-Play installs
"baselineProfile"(project(":baselineprofile"))
}Write the generator
@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {
@get:Rule val rule = BaselineProfileRule()
@Test
fun generate() = rule.collect(
packageName = "com.example.app",
includeInStartupProfile = true, // also generate a startup profile for DEX layout
) {
// 1. Startup
pressHome()
startActivityAndWait()
// 2. Most important journey: scroll the feed, open an item
val feed = device.findObject(By.res("feed_list"))
feed.setGestureMargin(device.displayWidth / 5)
feed.fling(Direction.DOWN)
device.waitForIdle()
device.findObject(By.res("feed_item_0"))?.click()
device.waitForIdle()
}
}Scaffold(modifier = Modifier.semantics { testTagsAsResourceId = true }) { /* ... */ }
LazyColumn(Modifier.testTag("feed_list")) { /* ... */ }./gradlew :app:generateBaselineProfile
# Writes the profile into the app module's source set; commit it to version control.Verify the improvement
@Test fun startupNoProfile() = startup(CompilationMode.None())
@Test fun startupWithProfile() = startup(CompilationMode.Partial(BaselineProfileMode.Require))
private fun startup(mode: CompilationMode) = benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
compilationMode = mode,
startupMode = StartupMode.COLD,
iterations = 10,
) { pressHome(); startActivityAndWait() }Compare the median timeToInitialDisplayMs between the two. Add a FrameTimingMetric benchmark for scrolling journeys too.
Choosing journeys
- Startup, always.
- The first screen's main interaction: scrolling the feed, opening search.
- High-value flows where jank hurts: checkout, the player screen.
Keep journeys deterministic. Use test accounts or fake data so they don't depend on live content.
Libraries ship profiles too
Jetpack libraries such as Compose include their own Baseline Profile rules, which are merged into your app. Your profile adds your code paths on top.
Keeping profiles fresh
- Regenerate when critical journeys or major code paths change, for example before each release.
- Automate generation on CI with Gradle Managed Devices where feasible.
- Track startup benchmarks over time to catch regressions.
Where they help most
Compose-heavy apps
Compose is a large library executed at startup. Profiles reduce first-frame and first-scroll cost.
Apps with frequent updates
Each update resets learned profiles on devices, and shipping a profile restores fast performance immediately.
Mid-range devices
The slower the device, the more noticeable the difference.
Frequently asked questions
Do Baseline Profiles work outside Google Play?
With the profileinstaller library, profiles can also be installed for sideloaded builds and other distribution channels, as described in the documentation.
Do they increase APK size?
Only slightly: the profile is a text-based list compiled into a compact binary format.
Baseline Profile vs startup profile?
Baseline Profiles guide AOT compilation. Startup profiles guide DEX layout so startup code is packed together. The plugin can generate both from the same journeys.
Conclusion
Baseline Profiles pre-compile your critical code paths so users get fast startup and smooth first interactions from the first launch. Generate them from deterministic journeys, commit them, verify the gain with Macrobenchmark, and regenerate as the app evolves.
Next step: shrink and optimise your release build with ProGuard and R8 Explained.
Official references
๐ฑ Apps built by Yunok Tech
Real Android apps on Google Play, free to download.
Walzi4K wallpapers for lock and home screenGet it โธ
NotiVaultNotification history: recover dismissed notificationsGet it โธ
Ready to build real Android applications?
Performance work starts with understanding how Android apps are built and how they behave at runtime. Strengthen those fundamentals and the profiling tools start to make sense.
Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.
Explore the Android course and take your next step as an Android developer.