Baseline Profiles overview

Baseline Profiles improve code execution speed by about 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 specified code paths through Ahead-of-Time (AOT) compilation, providing performance enhancements for every new user and every app update. This Profile Guided Optimization (PGO) lets apps optimize startup, reduce interaction jank, and improve overall runtime performance for users from the first launch.

These performance enhancements 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

Baseline Profiles make all user interactions—such as app startup, navigating between screens, or scrolling through content—smoother from the first time they run. By increasing the speed and responsiveness of an app, Baseline Profiles can lead 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 either JIT-compiled in memory after being interpreted, or written to an odex file in the background when the device is idle. After installing or updating an app, users have a suboptimal experience from the first time they run it until new code paths are optimized. Many apps measure performance boosts of about 30% after optimizing.

Startup profiles

Startup profiles are similar to Baseline Profiles, but the difference is they are used at compile time rather than for on-device optimization. A startup profile is used to optimize the layout of the DEX file to improve startup times. The code identified in the startup profile is put into the primary classes.dex file, and other code is put into separate DEX files. This improves startup times by reducing the number of page faults during app startup. To learn more about how startup profiles and DEX layout optimizations can improve app startup times, see DEX layout optimizations and startup profiles.

Get started

To start optimizing performance in your existing app, see Create Baseline Profiles.

The dependency chain provides stable and developmental release versions. To generate and install a Baseline Profile, use the following supported versions or higher of Android Gradle plugin, Macrobenchmark library, and 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:8.0.0
  • Macrobenchmark library: androidx.benchmark:benchmark-macro-junit4:1.2.3
  • Profile Installer: androidx.profileinstaller:profileinstaller:1.3.1

We recommend using the latest version of AGP to create and manage Baseline Profiles. Here are the major functionalities that come with different versions of AGP:

AGP version Features
8.3
  • Full source set directory support (library modules): declare multiple Baseline Profile source files, and use variant-aware directories, such as src/free/generated/baselineProfiles/baseline-prof1.txt, now for library modules as well as app modules.
  • Baseline Profiles include desugared classes.
8.2
  • R8 rewriting of rules: D8 and R8 can transform the human-readable Baseline and Startup Profile rules to fully capture all the rules you need to optimize app performance. Increases Baseline Profile coverage of methods by ~30% and increases app performance by ~15%.
  • Startup Profiles: generate this new type of Baseline Profile to inform layout of code within DEX. Increases startup performance by an additional ~15%, or significantly more for large apps.
8.0 Minimum recommended version: use the Baseline Profile Gradle plugin to generate Baseline Profiles with a single Gradle task.
  • Full source set directory support (app modules): declare multiple Baseline Profile source files, and use variant-aware directories, such as src/free/generated/baselineProfiles/baseline-prof1.txt.
7.4 Minimum supported version: apps can consume Baseline Profiles from libraries, and provide their own Baseline Profile in the src/main/baseline-prof.txt file.
  • Baseline Profiles are correctly packaged when building the APK from an app bundle (issue #230361284).
  • For apps with more than one .dex file, Baseline Profiles are correctly packaged for the primary .dex file.

Profile generation example

The following 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.collect(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. Any user journeys that you deem critical can benefit from Baseline Profiles by improving their runtime performance.

If you are experimenting with different approaches to improve performance, consider including Baseline Profiles for both arms of your experiment. By doing this, you can make your results easier to interpret by ensuring all of your users are consistently running compiled code.

Libraries can provide their own Baseline Profiles and ship them with releases to improve app performance. For example, see the Use a Baseline Profile section in Jetpack Compose performance.

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. Here's how they work:

  1. Human-readable profile rules are generated for your app and compiled into binary form in the app. You can find them in assets/dexopt/baseline.prof. You can then upload the AAB to Google Play as usual.

  2. Google Play processes the profile and ships it directly to users along with the APK. During installation, ART performs AOT compilation of the 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 might experience faster launch times and reduced jank.

  3. This flow cooperates with Cloud Profiles aggregation to fine-tune performance based on actual usage of the app over time.

Figure 1. This diagram demonstrates the Baseline Profile workflow from upload through end-user delivery, and how that workflow relates to Cloud Profiles.

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 hours to days after an update to be distributed, limiting their availability. Until profiles are fully distributed, app performance is suboptimal for users of new or updated apps. Further, Cloud Profiles only support Android devices running Android 9 (API level 28) or higher, and only scale well for apps that have a sufficiently large user base.

Compilation behavior across Android versions

Android Platform versions use 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 can 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, aggregated, and then provided as Cloud Profiles to other users when they install or update the app.

Known issues

The following are possible issues and solutions, or issues for which there are ongoing developments for workarounds:

  • Baseline Profile generation isn't supported on Firebase Test Lab devices, including Gradle-managed Test Lab devices (issue #285187547).

  • To provide Baseline Profiles for libraries successfully, use Baseline Profile Gradle plugin 1.2.3 or AGP 8.3, at minimum (issue #313992099).

  • If you generate Baseline Profiles with the command ./gradlew app:generateBaselineProfile, the benchmarks in the test module also run, and the results are discarded. If this happens, you can generate only the Baseline Profiles by running the command with -P android.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile. This issue has been fixed in AGP 8.2.

  • The command to generate Baseline Profiles for all build types— ./gradlew app:generateBaselineProfile—only generates Baseline Profiles for the release build type. This issue has been fixed in AGP 8.1.

  • Non-Google-Play-Store app distribution channels might not support using Baseline Profiles at installation. Users of apps installed through these channels don't see the benefits until background dexopt runs—which is likely overnight.

  • Play Store internal app sharing doesn't support Baseline Profiles; however, the internal testing track does.

  • Battery optimizations on some devices, such as Huawei devices, can interfere with profile installation. To help ensure that your profiles are installed effectively, disable any battery optimizations in your benchmark devices.

Additional resources