Baseline Profiles improve code execution speed by around 30% from the first launch by avoiding interpretation and just-in-time (JIT) compilation steps for included code paths. By shipping a Baseline Profile in an app or library, Android Runtime (ART) can optimize included code paths through Ahead of Time (AOT) compilation, providing performance enhancements for every new user and on every app update. This profile guided optimization (PGO) lets apps optimize startup, reduce interaction jank, and improve overall runtime performance for end users from the first launch.
These speed improvements directly result in improved business metrics such as user retention, transactions, and ratings. You can read more about how performance impacts business metrics in stories from Josh, Lyft, TikTok, and Zomato.
Benefits of Baseline Profiles
With a Baseline Profile, all user interactions (such as app startup, navigating between screens, or scrolling through content) are smoother from the first time they run. Increasing the speed and responsiveness of an app leads to more daily active users and a higher average return visit rate.
Baseline Profiles help guide optimization beyond app startup by providing common user interactions that improve app runtime from the first launch. Guided AOT compilation doesn't rely on user devices and can be done once per release on a development machine instead of a mobile device. By shipping releases with a Baseline Profile, app optimizations become available much faster than by relying on Cloud Profiles alone.
When not using a Baseline Profile, all app code is JIT compiled in memory after
being interpreted, or into an odex
file in the background when the device is
idle. Users have a less optimal experience for the first time they run an app
after installing or updating it, until the new paths have been optimized. This
performance boost has been measured at around 30% for many apps.
Get started
To get started with optimizing performance in your existing app, see Creating a Baseline Profile.
Minimum recommended stable versions
The dependency chain provides stable and developmental release versions. To generate and install a Baseline Profile, you need to use at least the minimally supported versions of the Android Gradle Plugin, Macrobenchmark library, and the Profile Installer. These dependencies are required at different times and work together as a toolchain to enable an optimal Baseline Profile.
- Android Gradle Plugin:
com.android.tools.build:7.4.1
- Macrobenchmark:
androidx.benchmark:benchmark-macro-junit4:1.1.1
- Profile Installer:
androidx.profileinstaller:profileinstaller:1.3.0
Profile generation example
Here is an example class to create a Baseline Profile for app startup, as well as several navigation and scroll events using the recommended Macrobenchmark library.
@OptIn(ExperimentalBaselineProfilesApi::class)
class BaselineProfileGenerator {
@get:Rule
val baselineProfileRule = BaselineProfileRule()
@Test
fun appStartupAndUserJourneys() {
baselineProfileRule.collectBaselineProfile(packageName = PACKAGE_NAME) {
// App startup journey
startActivityAndWait()
device.findObject(By.text("COMPOSE LAZYLIST")).clickAndWait(Until.newWindow(), 1_000)
device.findObject(By.res("myLazyColumn")).also {
it.fling(Direction.DOWN)
it.fling(Direction.UP)
}
device.pressBack()
}
}
}
You can see this code in full context and more detail as part of our performance samples on GitHub.
What to include
When using Baseline Profiles in an app, you can include app startup code and common user interactions, like navigation between screens or scrolling. You can also gather entire flows such as registration, login, or payment.
Libraries can provide their own Baseline Profile and ship it as part of a release to improve app performance. For example, take a look at Using a Baseline Profile with Compose.
How Baseline Profiles work
While developing your app or library, consider defining Baseline Profiles to cover common user interactions where rendering time or latency are important.
Profile rules are generated for your app in human readable form and compiled into a binary form in the app, which you can find in
assets/dexopt/baseline.prof
. You can then upload the AAB to Google Play as usual.Google Play processes the profile and ships it directly to users along with the APK. During installation, ART performs AOT compilation of methods in the profile, resulting in those methods executing faster. If the profile contains methods used in app launch or during frame rendering, the user may experience faster launch times and reduced jank.
This flow cooperates with Cloud Profiles aggregation to fine-tune performance based on actual usage of the app over time.

Cloud Profiles
Cloud Profiles offer an additional form of PGO, aggregated by Google Play Store and distributed for install time compilation, together with Baseline Profiles. While Cloud Profiles are driven by real world user interactions with the app, they take several days to weeks after an update to become distributed, limiting their availability. When only relying on a Cloud Profile, new and updating users experience apps in less than optimal performance until the profile is ready and distributed. Also, Cloud Profiles only support Android devices running Android 9 (API level 29) or higher and currently only scale well for apps that have a sufficiently large user base.
Compilation behavior across Android versions
Android Platform versions have used different app compilation approaches, each with a corresponding performance tradeoff. Baseline profiles improve upon the previous compilation methods by providing a profile for all installs.
Android version | Compilation method | Optimization approach |
---|---|---|
5 up to 6 (API level 21 up to 23) | Full AOT | The entire app is optimized during install, resulting in long wait times to use the app, increased RAM and disk space usage, and longer times to load code from disk, potentially increasing cold startup times. |
7 up to 8.1 (API level 24 up to 27) | Partial AOT (Baseline Profile) | Baseline Profiles are
installed by
androidx.profileinstaller
on the first run, when the
app module defines this
dependency. ART may improve
this further by adding
additional profile rules
during the app's use and
compiling them when the
device is idle. This
optimizes for disk space
and time to load code from
the disk, thereby reducing
wait time for the app. |
9 (API level 28) and higher | Partial AOT (Baseline + Cloud Profile) | Play uses Baseline Profiles during app installs to optimize the APK and Cloud profiles (if available). After installation, ART profiles are uploaded to Play and aggregated, then provided as Cloud Profiles to other users when they install or update the app. |
Known Issues
Currently, using Baseline Profiles has several known issues:
Baseline profiles are not packaged correctly when building the APK from an app bundle. To resolve this issue, apply
com.android.tools.build:gradle:7.3.0
and higher (issue).Baseline profiles are only correctly packaged for the primary
classes.dex
file. This affects apps with more than one.dex
file. To resolve this issue, applycom.android.tools.build:gradle:7.3.0
and higher.Resetting ART profile caches is not allowed on
user
(non-rooted) builds. To work around this,androidx.benchmark:benchmark-macro-junit4:1.1.0
includes a fix that reinstalls the app during the benchmark (issue).Android Studio Profilers don't install Baseline Profiles when profiling the app (issue).
Non-Gradle build systems (Bazel, Buck, etc.) don't currently support compiling Baseline Profiles into output APKs.
Non-Play Store app distribution channels may not support using Baseline Profiles at installation. Users of the app through these channels don't see the benefits until background dexopt runs (likely overnight).
Currently, the build compiler accepts only one
baseline-prof.txt
in thesrc/main
folder and doesn't reflect files in different flavors or build types. This is being actively improved.Battery optimizations may interfere with profile installation. To ensure that your profiles are installed effectively, disable any battery optimizations on your benchmark devices.
Performance improvements might differ between benchmarks and production. This happens because local benchmarks measure performance with Baseline Profiles enabled or disabled. In a production app, the measurement is incremental when adding a new part of the app to a Baseline Profile, where parts are already profiled through contributing libraries.