Create Baseline Profiles

You can automatically generate profiles for every app release using the Jetpack Macrobenchmark library and BaselineProfileRule. We recommend that you use com.android.tools.build:gradle:8.0.0 or higher, which comes with build improvements when using Baseline Profiles.

Define the Baseline Profile generator

To create Baseline Profiles using the Macrobenchmark library, perform the following steps:

Android Studio Hedgehog Canary 1

Baseline Profile Generator module template

The Android Studio Baseline Profile Generator module template automates the creation of a new module to generate and benchmark Baseline Profiles. Running the template generates most of the typical build configuration, Baseline Profile generation, and verification code. The template creates code to generate and benchmark Baseline Profiles to measure app startup.

You need to manually define the Critical User Journeys (CUJs) within your app so that the generated Baseline Profiles provide the required optimizations for those CUJs.

Create a Baseline Profile Generator module using the template

To run the Baseline Profile module template, perform the following steps:

  1. Select File > New... > New Module...
  2. Select the Baseline Profile Generator template in the Templates panel and configure it:
    Figure 1. Baseline Profile Generator module template.

    The fields in the template are the following:

    • Target application: this drop-down contains a list of the app modules in your project and defines which app the baseline profile is generated for. When you have only a single app module in your project, there is only one item in this list.
    • Module name: the name you want for the Baseline Profile module being created.
    • Package name: the package name you want for the Baseline Profile module.
    • Language: whether you want the generated code to be Kotlin or Java.
    • Build configuration language: whether you want to use Kotlin Script (KTS) or Groovy for your build configuration scripts.
  3. Click Finish and the new module is created. If you are using source control, you might be prompted to add the newly created module files to source control.

The newly created module contains code to both generate and benchmark the Baseline Profile and test only basic app startup times. We recommend that you augment these to include CUJs. It helps maintainability if you abstract these CUJs outside of the generated Baseline Profile and benchmark code so that they can be used for both. This means that changes to your CUJs are used consistently.

Generate the Baseline Profile

The Baseline Profile module template adds a new Run Configuration to generate the Baseline Profile:

Figure 2. Running this configuration generates the Baseline Profile.

To do this from the command-line interface, you can run the :app:generaterBaselineProfile or :app:generateBaselineProfile Gradle tasks. This both generates the Baseline Profile and installs it to the app being profiled.

Install the Baseline Profile

When the "Generate Baseline Profile" run configuration completes, it copies the generated Baseline Profile to src/release/generated/baselineProfiles/baseline-prof.txt in the module that is being profiled.

The generated Baseline Profile is created in build/outputs. However, the full path is dictated by the variant or flavor of the app being profiled and whether you use a Gradle Managed Device or a connected device for profiling.

If you use the names used by the code and build configurations generated by the template, it is created in build/outputs/managed_device_android_test_additional_output/nonminifiedrelease/pixel6Api31/BaselineProfileGenerator_generate-baseline-prof.txt.

Android Studio Giraffe and older

  1. Set up a Macrobenchmark module in your Gradle project.
  2. Define a new test called BaselineProfileGenerator:
            class BaselineProfileGenerator {
             @get:Rule
                val baselineProfileRule = BaselineProfileRule()
    
                @Test
                fun startup() = baselineProfileRule.collectBaselineProfile(
                    packageName = "com.example.app",
                    profileBlock = {
                        startActivityAndWait()
                    }
                )
            }
    

    The generator can contain interactions with your app beyond app startup. This lets you optimize the runtime performance of your app, such as scrolling lists, running animations, and navigating within an Activity. See other examples of tests that use @BaselineProfileRule to improve critical user journeys.

  3. (Optional) Turn off obfuscation when generating Baseline Profiles. You can do this by creating another ProGuard file in your app module and adding -dontobfuscate for only your benchmark build type that is responsible for generating the profiles.

    Kotlin

    buildTypes {
        val benchmark by creating {
            // Only use benchmark Proguard rules.
            proguardFiles("benchmark-rules.pro")
            // ...
        }
    }
    

    Groovy

    buildTypes {
        benchmark {
            // Only use benchmark Proguard rules.
            proguardFiles 'benchmark-rules.pro'
            // ...
        }
    }
    

Generate the Baseline Profile

Run the generator as an instrumented test on a rooted physical device, emulator, or Gradle Managed Device. To set up a managed device, open your build.gradle.kts file. In the testOptions configuration block, add managedDevices and devices and create an emulator definition. Use aosp as the systemImageSource, because you need root access for the Baseline Profile generator.

Kotlin

testOptions {
    managedDevices {
        devices {
            create ("pixel6Api31", ManagedVirtualDevice::class) {
                device = "Pixel 6"
                apiLevel = 31
                systemImageSource = "aosp"
            }
        }
    }
}

Groovy

testOptions {
    managedDevices {
        devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device = "Pixel 6"
                apiLevel = 31
                systemImageSource = "aosp"
            }
        }
    }
}

Gradle creates the required tasks based on the selected device name and the build variants available in the module. It is formatted as [emulator_name][flavor][build type]AndroidTest. You can execute this task from a terminal:

./gradlew :benchmark:pixel6Api31BenchmarkAndroidTest

Benchmark the Baseline Profile

To benchmark your Baseline Profile, create a new Android Instrumented Test Run configuration from the gutter action that executes the benchmarks defined in StartupBenchmarks.kt or StartupBencharks.java. To learn more about benchmark testing, see Create a Macrobenchmark class and Automate measurement with the Macrobenchmark library.

Figure 3. Run Android Tests from the gutter action.

When you run this within Android Studio, the build output contains details of the speed improvements that the Baseline Profile provides:

StartupBenchmarks_startupCompilationBaselineProfiles
timeToInitialDisplayMs   min 161.8,   median 178.9,   max 194.6
StartupBenchmarks_startupCompilationNone
timeToInitialDisplayMs   min 184.7,   median 196.9,   max 202.9

Capture all required code paths

The two key metrics for measuring app startup times are time to initial display (TTID) and time to full display (TTFD). TTID is the time it takes to display the first frame of the application UI. TTFD also includes the time to display content that is loaded asynchronously after the initial frame is displayed.

TTFD is reported once the reportFullyDrawn() method of the ComponentActivity is called. If reportFullyDrawn() is never called, the TTID is reported instead. You might need to delay when reportFullyDrawn() is called until after the asynchronous loading is complete. For example, if the UI contains a dynamic list such as a RecyclerView or lazy list, this might be populated by a background task that completes after the list is first drawn and, therefore, after the UI is marked as fully drawn. In such cases, code that runs after the UI reaches fully drawn state isn't included in the Baseline Profile.

To include the list population as part of your Baseline Profile, get the FullyDrawnReporter by using getFullyDrawnReporter() and add a reporter to it in your app code. Release the reporter once the background task finishes populating the list. The FullyDrawnReporter doesn't call the reportFullyDrawn() method until all reporters are released. By doing this, Baseline Profile includes the code paths required to populate the list. This doesn't change the app's behavior for the user, but it lets the Baseline Profile include all the necessary code paths.

If your app uses Jetpack Compose, use the following APIs to indicate fully drawn state:

  • ReportDrawn indicates that your composable is immediately ready for interaction.
  • ReportDrawnWhen takes a predicate, such as list.count > 0, to indicate when your composable is ready for interaction.
  • ReportDrawnAfter takes a suspending method that, when it completes, indicates that your composable is ready for interaction.

Baseline Profile Gradle plugin

The Baseline Profile Gradle plugin makes it easier to generate and maintain Baseline Profiles. It performs necessary steps to generate and install a Baseline Profile into your application module.

To use the plugin, add an instrumented test module to your project and define a set of tests that navigate through your app to simulate critical user journeys. When you run the instrumented test, the Baseline Profile Gradle plugin tracks all classes and methods that are executed during these user journeys and generates a baseline profile based on these classes and methods. It then copies the generated baseline profile into the application module.

The instrumented test module is the profile producer. The app module is the profile consumer.

The main areas that you need to focus on are the initial setup and creating the tests to simulate the critical user journeys.

What you need to use the plugin

Use the plugin

The following example assumes the existence of an application module named :app.

There are 2 modules in the following example:

  • Profile consumer: the application module to generate the profile for. In the following example, it's :app.
  • Profile producer: the Baseline Profile test module that contains the instrumentation tests to generate the profile. In the following example, it's named :baseline-profile.

To use the plugin, perform the following steps:

  1. Create a new com.android.test module—for example, :baseline-profile.
  2. Configure build.gradle for :baseline-profile:
    1. Apply the androidx.baselineprofile plugin.
    2. Ensure the targetProjectPath points to the :app module.
    3. Optionally, add GMD. In the following example, it's pixel6Api31. If not specified, the plugin uses a connected device, either emulated or physical.
    4. Apply the configuration you want, as shown in the following example.

    Kotlin

    plugins {
        id("com.android.test")
        id("androidx.baselineprofile")
    }
    
    android {
    
        // There are no changes here. It's documented for completeness.
        defaultConfig {
            ...
        }
    
        // This must point to the app module.
        targetProjectPath = ":app"
    
        // This is the optional managed device.
        testOptions.managedDevices.devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device = "Pixel 6"
                apiLevel = 31
                systemImageSource = "aosp"
            }
        }
    }
    
    // There are no changes here. It's documented for completeness.
    dependencies { ... }
    
    // This is the plugin configuration. Everything is optional. Defaults are in the
    // comments. In this example, you use the GMD added earlier and disable
    // connected devices.
    baselineProfile {
    
        // This specifies the managed devices to use that you run the tests on. The
        // default is none.
        managedDevices += "pixel6Api31"
    
        // This enables using connected devices to generate profiles. The default is
        // true. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices = false
    }
    

    Groovy

    plugins {
        id 'com.android.test'
        id 'androidx.baselineprofile'
    }
    
    android {
    
        // There are no changes here. It's documented for completeness.
        defaultConfig {
            ...
        }
    
        // This must point to the app module.
        targetProjectPath ':app'
    
        // This is the optional managed device.
        testOptions.managedDevices.devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device 'Pixel 6'
                apiLevel 31
                systemImageSource 'aosp'
            }
        }
    }
    
        // There are no changes here. It's documented for completeness.
    dependencies { ... }
    
    // This is the plugin configuration. Everything is optional. Defaults are in the
    // comments. In this example, you use the GMD added earlier and disable
    // connected devices.
    baselineProfile {
    
        // This specifies the managed devices to use that you run the tests on. The
        // default is none.
        managedDevices ['pixel6Api31']
    
        // This enables using connected devices to generate profiles. The default is
        // true. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices false
    }
    
  3. Create a Baseline Profile test in the :baseline-profile test module. The following example is a test that starts the app and waits for idle.
  4. Kotlin

    class BaselineProfileGenerator {
    
        @get:Rule
        val baselineRule = BaselineProfileRule()
    
        @Test
        fun startupBaselineProfile() {
            baselineRule.collectBaselineProfile("com.myapp") {
                startActivityAndWait()
            }
        }
    }
    

    Java

    public class BaselineProfileGenerator {
    
        @Rule
        Public BaselineProfileRule baselineRule = new BaselineProfileRule();
    
        @Test
        Public void startupBaselineProfile() {
            baselineRule.collectBaselineProfile(
                "com.myapp",
                (scope -> {
                    scope.startActivityAndWait();
                    Return Unit.INSTANCE;
                })
            }
        }
    }
    
  5. Update the configuration in build.gradle in the app module :app.
    1. Apply the plugin androidx.baselineprofile.
    2. Add a baselineProfile dependency to the :baseline-profile module.

    Kotlin

    plugins {
        id("com.android.application")
        id("androidx.baselineprofile")
    }
    
    android {
        // There are no changes to the `android` block.
        ...
    }
    
    dependencies {
        ...
        // Add a baselineProfile dependency to the :baseline-profile module.
        baselineProfile(project(":baseline-profile"))
    }
    

    Groovy

    plugins {
        id 'com.android.application'
        id 'androidx.baselineprofile'
    }
    
    android {
        // No changes to the `android` block.
        ...
    }
    
    dependencies {
        ...
        // Add a baselineProfile dependency to the :baseline-profile module.
        baselineProfile ':baseline-profile"'
    }
    
  6. Generate the profile by running the following code: ./gradlew :app:generateBaselineProfile.

At the end of the generation task, the Baseline Profile is stored in app/src/release/generated/baselineProfiles.

Generate a Baseline Profile for a library

In the following example, the library module is named :library and the application module is named :sample-app, which contains an app that utilizes the library.

In this example, you need three modules:

  • App target: an application module that contains a sample app. In the following example, it's :sample-app.
  • Profile consumer: the library module to generate the profile for. In the following example, it's :library.
  • The profile producer: the Baseline Profile test module that contains the instrumentation tests to generate the module.

To generate a Baseline Profile for a library, perform the following steps:

  1. Create a new com.android.test module—for example, :baseline-profile.
  2. Configure build.gradle for :baseline-profile:
    1. Apply the androidx.baselineprofile plugin.
    2. Ensure the targetProjectPath points to the :sample-app module.
    3. Optionally, add a GMD. In the following example, it's pixel6Api31.
    4. Apply the configuration you want, as shown in the following example.

    Kotlin

    plugins {
        id("com.android.test")
        id("androidx.baselineprofile")
    }
    
    android {
    
        // There are no changes here. It's reported for completeness.
        defaultConfig {
            minSdkVersion 23
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    
        // This must point to the app module.
        targetProjectPath = ":app"
    
        // This is the optional managed device.
        testOptions.managedDevices.devices {
            create("pixel6Api31") {
                device = "Pixel 6"
                apiLevel = 31
                systemImageSource = "aosp"
            }
        }
    }
    
    // There's nothing to change here.
    dependencies { ... }
    
    // This is the plugin configuration. Everything is optional. Defaults are in the
    // comments. In this example, you use the GMD added earlier and disable
    // connected devices.
    baselineProfile {
    
        // This specifies the managed devices to use that you run the tests on. The
        // default is none.
        managedDevices += "pixel6Api31"
    
        // This enables using connected devices to generate profiles. The default is
        // true. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices = false
    }
    

    Groovy

    plugins {
        id 'com.android.test'
        id 'androidx.baselineprofile'
    }
    
    android {
    
        // There are no changes here. It's reported for completeness.
        defaultConfig {
            ...
        }
    
        // This must point to the app module.
        targetProjectPath ':app'
    
        // This is the optional managed device.
        testOptions.managedDevices.devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device 'Pixel 6'
                apiLevel 31
                systemImageSource 'aosp'
            }
        }
    }
    
    // There's nothing to change here.
    dependencies { ... }
    
    // This is the plugin configuration. Everything is optional. Defaults are in the
    // comments. In this example, you use the GMD added earlier and disable
    // connected devices.
    baselineProfile {
    
        // This specifies the managed devices to use that you run the tests on. The
        // default is none.
        managedDevices ['pixel6Api31']
    
        // This enables using connected devices to generate profiles. The default is
        // true. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices false
    }
    
  3. Create a Baseline Profile test in the :baseline-profile test module. This needs to be specific to the sample app and must use all the functionalities of the library.
  4. Update the configuration in build.gradle in the library module :library.
    1. Apply the plugin androidx.baselineprofile.
    2. Add a baselineProfile dependency to the :baseline-profile module.
    3. Apply the consumer plugin configuration you want, as shown in the following example.

    Kotlin

    plugins {
        id("com.android.library")
        id("androidx.baselineprofile")
    }
    
    // There are no changes to the android block.
    android { ... }
    
    dependencies {
        ...
        // Add a baselineProfile dependency to the :baseline-profile module.
        baselineProfile(project(":baseline-profile"))
    }
    
    // This is the plugin configuration.
    baselineProfile {
    
        // This filters the generated profile rules. In this example, you keep
        // all the classes in com.library and in all the subpackages.
        filter {
            include "com.mylibrary.**"
        }
    }
    

    Groovy

    plugins {
        id 'com.android.library'
        id 'androidx.baselineprofile'
    }
    
    // There are no changes to the android block.
    android { ... }
    
    dependencies {
        ...
        // Add a baselineProfile dependency to the :baseline-profile module.
        baselineProfile ':baseline-profile'
    }
    
    // This is the plugin configuration.
    baselineProfile {
    
        // This filters the generated profile rules. In this example, you keep
        // all the classes in com.library and in all the subpackages.
        filter {
            include 'com.mylibrary.**'
        }
    }
    
  5. Update the configuration in build.gradle in the app module :sample-app, adding the androidx.baselineprofile plugin.
  6. Kotlin

    plugins {
        ...
        id("androidx.baselineprofile")
    }
    // There are no other changes to the configuration.
    

    Groovy

    plugins {
        ...
        id 'androidx.baselineprofile'
    }
    // There are no other changes to the configuration.
    
  7. Generate the profile by running the following code: ./gradlew :library:generateBaselineProfile.

At the end of the generation task, the Baseline Profile is stored in library/src/main/generated/baselineProfiles.

DSL

While this documentation refers to the Baseline Profile Gradle plugin as a single plugin, there are actually three plugins that perform different tasks according to which module they're applied to. The plugin ID in this documentation is androidx.baselineprofile, and it's a shortcut for the three plugins.

To better understand this concept, see the following modules you need to generate a Baseline Profile:

  • An application to run the Baseline Profile tests against. This is an Android application module with com.android.application applied. When generating a profile for a library, this can be a sample app. When generating a profile for an application, it's the application itself. In the following example, androidx.baselineprofile plugin internally applies androidx.baselineprofile.apptarget.
  • A Baseline Profile test module that contains the tests to run. This is an Android test module with com.android.test applied. In the following example, androidx.baselineprofile plugin internally applies androidx.baselineprofile.producer.
  • A module that ultimately consumes the Baseline Profile in the build process. This is an android application com.android.application or library com.android.library module. In the following example, androidx.baselineprofile plugin internally applies androidx.baselineprofile.consumer.

App target (androidx.baselineprofile.apptarget)

This doesn't have any configuration.

Profile producer (androidx.baselineprofile.producer)

Support for Gradle-managed devices

To utilize a Gradle-managed device, add one in the build.gradle configuration of the profile producer module, as shown in the following example:

Kotlin

android {
   testOptions.managedDevices.devices {
       create("pixel6Api31") {
           device = "Pixel 6"
           apiLevel = 31
           systemImageSource = "aosp"
       }
   }
}

Groovy

android {
   testOptions.managedDevices.devices {
       pixel6Api31(ManagedVirtualDevice) {
           device 'Pixel 6'
           apiLevel = 31
           systemImageSource 'aosp'
       }
   }
}

You can then use the created GMD to generate Baseline Profiles by adding it to the following:

Kotlin

baselineProfile {
    managedDevices += "pixel6Api31"
}

Groovy

baselineProfile {
    managedDevices = ['pixel6Api31']
}

The following examples are additional options available to enable or disable the connected devices to generate Baseline Profiles.

Kotlin

baselineProfile {
    ...
    useConnectedDevices = true
}

Groovy

baselineProfile {
    ...
    useConnectedDevices true
}

Profile consumer (androidx.baselineprofile.consumer)

Generate profiles per flavor and one for all variants

You can generate profiles per variant, per flavor, or as a single file to utilize for all the variants. You can control this behavior through the merge setting, as shown in the following example.

Kotlin

baselineProfile {
    mergeIntoMain = true / false
}

Groovy

baselineProfile {
    mergeIntoMain true / false
}
  • Set mergeIntoMain to true to merge all the generated profiles for each variant in a single profile. It isn't possible to generate per-variant Baseline Profiles when this setting is true, so only a single generation task named generateBaselineProfile exists. The profile output is src/main/generated/baselineProfiles.
  • Set mergeIntoMain to false to disable merging and to have one profile per variant. It's possible to generate per-variant Baseline Profiles in the following example so multiple generation tasks exist—one per variant. For example, when there are two flavors—such as free and paid—and one release build type, the generated tasks are the following:
    • generateFreeReleaseBaselineProfile
    • generatePaidReleaseBaselineProfile
    • generateReleaseBaselineProfile

By default, this setting is true for libraries and false for applications.

You can also specify this behavior per variant:

Kotlin

baselineProfile {
    variants {
        freeRelease {
            mergeIntoMain = true / false
        }
    }
}

Groovy

baselineProfile {
    variants {
        freeRelease {
            mergeIntoMain true / false
        }
    }
}

In the preceding example, the variants where the flag is set to true are all merged into src/main/generated/baselineProfiles, while the profiles for the variants where the flag is set to false are kept in the folder src/<variant>/generated/baselineProfiles.

Automatically generate Baseline Profile when assembling a new release

You can manually trigger Baseline Profile generation through the task generateBaselineProfile or automatically when building a release. This is controlled by the following flag:

Kotlin

baselineProfile {
    automaticallyGenerateDuringBuild = true / false
}

Groovy

baselineProfile {
    automaticallyGenerateDuringBuild true / false
}

Setting this flag to true triggers a new Baseline Profile to be generated for each assembly. This way, the most updated profile is included in the build. This means that running an assemble release build task—such as ./gradlew:app:assembleRelease—also triggers :app:generateReleaseBaselineProfile. This also starts the Baseline Profile instrumentation tests and builds the Baseline Profile build on which they run. While this helps ensure that users gain the best performance benefit, it also increases the build time because of the double build and instrumentation tests.

You can also specify this behavior per variant, as shown in the following example:

Kotlin

baselineProfile {
    variants {
        freeRelease {
            automaticallyGenerateDuringBuild = true / false
        }
    }
}

Groovy

baselineProfile {
    variants {
        freeRelease {
            automaticallyGenerateDuringBuild true / false
        }
    }
}

In the preceding example, the task generateFreeReleaseBaselineProfile runs when starting assembleFreeRelease. This helps when the user wants to have, for example, a release for distribution build that always generates the profile when building, and a releaseWithoutProfile build for internal testing.

Store Baseline Profiles into sources

You can store Baseline Profiles in the source directory through the saveInSrc flag:

  • true: the Baseline Profile is stored in src/<variant>/generated/baselineProfiles. This lets you commit the latest generated profile with your sources.
  • false: the Baseline Profile is stored in the intermediate files in the build directory. This way, when committing your code, you don't save the latest generated profile.

Kotlin

baselineProfile {
    saveInSrc = true / false
}

Groovy

baselineProfile {
    saveInSrc true / false
}

You can also specify this behavior per variant:

Kotlin

baselineProfile {
    variants {
        freeRelease {
            saveInSrc = true / false
        }
    }
}

Groovy

baselineProfile {
    variants {
        freeRelease {
            saveInSrc true / false
        }
    }
}
Filter profile rules

You can filter the Baseline Profile rules generated through plugin configuration. This is particularly helpful for libraries if you want to exclude profile rules for classes and methods that are part of other dependencies of the sample app or the library itself. The filters can specify, include, and exclude for packages and classes. When you only specify excludes, only matching Baseline Profile rules are excluded and everything else is included.

The filters specification can be any of the following:

  • Package name ending with double wildcards to match the specified package and all subpackages. For example, com.example.** matches com.example.foo and com.example.foo.bar.
  • Package name ending with wildcard to match specified package only. For example, com.example.* matches com.example.foo but doesn't match com.example.foo.bar.
  • Class names to match a specific class—for example, com.example.MyClass.

The following examples show how to include and exclude specific packages:

Kotlin

baselineProfile {
    filter {
        include("com.somelibrary.widget.grid.**")
        exclude("com.somelibrary.widget.grid.debug.**")
        include("com.somelibrary.widget.list.**")
        exclude("com.somelibrary.widget.list.debug.**")
        include("com.somelibrary.widget.text.**")
        exclude("com.somelibrary.widget.text.debug.**")
    }
}

Groovy

baselineProfile {
    filter {
        include 'com.somelibrary.widget.grid.**'
        exclude 'com.somelibrary.widget.grid.debug.**'
        include 'com.somelibrary.widget.list.**'
        exclude 'com.somelibrary.widget.list.debug.**'
        include 'com.somelibrary.widget.text.**'
        exclude 'com.somelibrary.widget.text.debug.**'
    }
}

Filters also support variants and you can express them as follows:

Kotlin

// Non-specific filters applied to all the variants.
baselineProfile {
    filter { include("com.myapp.**") }
}

// Flavor-specific filters.
baselineProfile {
    variants {
        free {
            filter {
                include("com.myapp.free.**")
            }
        }
        paid {
            filter {
                include("com.myapp.paid.**")
            }
        }
    }
}

// Build-type-specific filters.
baselineProfile {
    variants {
        release {
            filter {
                include("com.myapp.**")
            }
        }
    }
}

// Variant-specific filters.
baselineProfile {
    variants {
        freeRelease {
            filter {
                include("com.myapp.**")
            }
        }
    }
}

Groovy

// Non-specific filters applied to all the variants.
baselineProfile {
    filter { include 'com.myapp.**' }
}

// Flavor-specific filters.
baselineProfile {
    variants {
        free {
            filter {
                include 'com.myapp.free.**'
            }
        }
        paid {
            filter {
                include 'com.myapp.paid.**'
            }
        }
    }
}

// Build-type specific filters.
baselineProfile {
    variants {
        release {
            filter {
                include 'com.myapp.**'
            }
        }
    }
}

// Variant-specific filters.
baselineProfile {
    variants {
        freeRelease {
            filter {
                include 'com.myapp.**'
            }
        }
    }
}

(Optional) Apply the generated rules manually

The Baseline Profile generator creates a Human Readable Format (HRF) text file on the device and copies it to your host machine. To apply the generated profile to your code, follow these steps:

  1. Locate the HRF file in the build folder of the module you generate the profile in: [module]/build/outputs/managed_device_android_test_additional_output/[device].

    Profiles follow the [class name]-[test method name]-baseline-prof.txt naming pattern, which looks like this: BaselineProfileGenerator-startup-baseline-prof.txt.

  2. Copy the generated profile to src/flavor/baselineProfiles in your app module for any given flavor. To apply the profile to all flavors, copy it to src/main/baselineProfiles.

  3. Add a dependency to the ProfileInstaller library in your app's build.gradle.kts file to enable local Baseline Profile compilation where Cloud Profiles aren't available. This is the only way to sideload a Baseline Profile locally.

    dependencies {
         implementation("androidx.profileinstaller:profileinstaller:1.3.1")
    }
    
  4. Build the production version of your app while the applied HRF rules are compiled into binary form and included in the APK or AAB. Then distribute your app as usual.

Additional notes

When creating Baseline Profiles, here are some additional things to be aware of:

  • Compiled Baseline Profiles must be smaller than 1.5 MB. This doesn't apply to the text format in your source files, which are typically much larger prior to compilation. Verify the size of your binary Baseline Profile by locating it in the output artifact under assets/dexopt/baseline.prof for APK or BUNDLE-METADATA/com.android.tools.build.profiles/baseline.prof for AAB.

  • Broad rules that compile too much of the application can slow down startup due to increased disk access. If you're just starting with Baseline Profiles, don't worry about this. However, depending on your app and the size and number of journeys, adding a lot of journeys can result in suboptimal performance. Test the performance of your app by trying different profiles and verifying that the performance doesn't regress after the additions.

Codelabs

Dive into macrobenchmarking to measure performance.
Generate a custom Baseline Profile tailored to an Android app and verify its effectiveness.