Create Startup Profiles

Startup Profiles are a subset of Baseline Profiles. Startup Profiles are used by the build system to further optimize the classes and methods they contain by improving the layout of code in your APK's DEX files. With Startup Profiles, your app startup is usually between 15% and 30% faster than with Baseline Profiles alone.

Figure 1. Code locality improvement from DEX layout optimization.

Requirements

We recommend using Startup Profiles with the following tools:

  • Jetpack Macrobenchmark 1.2.0 or higher
  • Android Gradle Plugin 8.2 or higher
  • Android Studio Iguana or higher

In addition, you need the following settings in your app:

  • R8 enabled. For your release build, set isMinifyEnabled = true.
  • DEX layout optimizations enabled. In the baselineProfile {} block of the app module's build file, set dexLayoutOptimization = true.

Create a Startup Profile

Android Studio creates a Startup Profile alongside a Baseline Profile when you use the default Baseline Profile Generator template.

The general steps to create and generate a Startup Profile are the same as those to create a Baseline Profile.

The default way to create a Startup Profile is by using the Baseline Profile Generator module template from within Android Studio. This includes startup interactions that form a basic Startup Profile. To augment this Startup Profile with more Critical User Journeys (CUJs), add your app startup CUJs to a rule block with includeInStartupProfile set to true. For simple apps, launching the app's MainActivity might be sufficient. For more complex apps, consider adding the most common entry points into your app, such as starting the app from the home screen or launching into a deep link.

The following code snippet shows a Baseline Profile generator (by default the BaselineProfileGenerator.kt file) that includes starting your app from the home screen and launching into a deep link. The deep link goes directly to the app's news feed, not the app's home screen.

@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {

    @get:Rule
    val rule = BaselineProfileRule()

    @Test
    fun generate() {
        rule.collect(
            packageName = "com.example.app",
            includeInStartupProfile = true
        ) {
            // Launch directly into the NEWS_FEED.
            startActivityAndWait(Intent().apply {
                setPackage(packageName)
                setAction("com.example.app.NEWS_FEED")
            })
        }
    }
}

Run the Generate Baseline Profile for app configuration and find the Startup Profile rules at src/<variant>/generated/baselineProfiles/startup-prof.txt.

Confirm Startup Profiles optimization

To confirm DEX layout optimization, use Android Studio to open the APK and verify the classes in the DEX files. Make sure the primary classes.dex isn't completely filled. If your app consists of a single DEX file, you can check whether the app contains two DEX files after enabling the Startup Profile.

Android Studio warns you if the startup classes don't fit in a single DEX file. To get diagnostic information that includes the amount of non-startup methods in the startup classes, make sure the R8 compiler is updated to at least version 8.3.36-dev by making the following changes to the settings.gradle file when you apply the Startup Profile:

Kotlin

pluginManagement {
    buildscript {
        repositories {
            mavenCentral()
            maven {
                url = uri("https://storage.googleapis.com/r8-releases/raw")
            }
        }
        dependencies {
            classpath("com.android.tools:r8:8.3.6-dev")
        }
    }
}

Groovy

pluginManagement {
    buildscript {
        repositories {
            mavenCentral()
            maven {
                url uri('https://storage.googleapis.com/r8-releases/raw')
            }
        }
        dependencies {
            classpath 'com.android.tools:r8:8.3.6-dev"
        }
    }
}

Make sure you add --info after assembleRelease in the following command when building with Gradle.

./gradlew assembleRelease --info

The diagnostic is then printed to the terminal.

If your app or any libraries reference any desugared APIs, the bundled compatibility implementations of these classes are always contained in the last DEX file. This desugared last DEX file doesn't participate in DEX layout optimizations.

Considerations to creating startup profiles

The output of a startup profile's classes and methods is limited by the size of the first classes.dex file. This means that not all baseline profile journeys should also be startup profile journeys.

To decide which user journeys to cover when creating a startup profile, consider where most users start the application. Usually that is from the launcher and after they have been logged in. This is also the most basic baseline profile journey.

After the first use case has been covered, follow the user funnel for app startup. In many cases, app startup funnels follow this list:

  1. Main launcher activity
  2. Notifications that trigger app startup
  3. Optional launcher activities

Work this list from the top and stop before classes.dex is full. To cover more journeys afterwards, move code out of the startup path and add more journeys. To move code out of the startup path, inspect Perfetto traces during app startup and look for long running operations. You can also use a macrobenchmark with method tracing enabled for an automatable and complete view of method calls during app startup.