Optimizing startup time with Baseline Profiles

  • Baseline Profiles eliminate the dependency on JIT compilation on the first release using AOT.
  • They allow precompiling critical code paths to reduce startup time and improve scrolling smoothness.
  • They are integrated through a Macrobenchmark module that automates the generation of profiles based on actual use.
  • Its implementation directly impacts user retention by offering an instant experience from minute one.

Optimizing startup time with Baseline Profiles

Today, nobody has the patience to wait for an app to load. In the mobile ecosystem, responsiveness is the difference between a user staying with the app or deleting it within seconds. Making a complex interface load instantly requires going beyond conventional code optimization, focusing on how the device processes instructions before they reach the screen.

To address startup delays, Google has introduced Baseline Profiles , a disruptive tool that allows developers to mark which code paths are vital. By doing this, we prevent the device from having to "discover" how to run the app the first time, providing smooth performance from the very first launch , whether it's a clean install or an update.

What exactly are Baseline Profiles and how do they work?

To understand them, you first need to know that Android uses the Android Runtime (ART). Traditionally, code has been executed using Just-In-Time (JIT) compilation , which translates the code as the app runs, or Ahead-Of-Time (AOT) compilation , which does it all beforehand. The problem with JIT is that it can cause minor stutters or initial slowness because the code isn't optimized from the start.

Baseline Profiles act as a master guide. They are essentially a list of classes and methods that the system must precompile using AOT before the user opens the app. This way, the runtime doesn't have to interpret the code on the fly, which can result in a speed improvement of up to 30% on initial execution.

Unlike Cloud Profiles, which rely on thousands of users using the app and Google Play adding that data (a process that takes days), Baseline Profiles are delivered directly in the Android App Bundle (AAB) . This means optimization is available immediately, eliminating the "sluggish" period that newly updated versions often experience.

When is it essential to implement this technique?

Not all applications require the same level of optimization, but there are scenarios where they're a lifesaver. Using profiles is crucial for reducing cold startup time , especially if your splash screen has heavy dependencies or complex rendering. If you notice the first launch is slow but the second is lightning fast, you have a compilation issue that profiles can resolve.

Furthermore, they're not just for startup. They're extremely useful for improving scrolling fluidity . By precompiling list logic and animations, you prevent dropped frames, making content navigation feel incredibly smooth. They're also ideal for optimizing recurring features , such as the checkout or registration flow, ensuring that the most frequently used paths are the fastest.

Step-by-step configuration of the generation module

The most modern way to implement this is through a dedicated module in Android Studio. To begin, you need to go to New Module and select the template Baseline Profile GeneratorHere you will define the target application, the module name (for example, baselineprofile) and the preferred language, either Kotlin or Java.

This process automates the creation of a test environment. The wizard will configure the plugin. androidx.baselineprofile and will add the library profileinstaller in the application module. The latter is responsible for ensuring that the profile is correctly installed on users' devices, even on older versions of Android that do not support cloud profiles.

An important technical detail is obfuscation management. For the profile to be valid, it must be generated on a variant where `isMinifyEnabled` is set to `false` . However, don't worry about the final version: R8 is able to rewrite the profile rules to match the obfuscated code of the production APK, thus maintaining maximum security and size optimization.

Creation of critical user journeys (CUJ)

A basic profile that only launches the app is useful, but to get the most out of its performance we need to define the Critical User JourneysThis is done within the class BaselineProfileGenerator using the rule BaselineProfileRule. Inside the block collectWe must simulate the real actions that a user would take.

Automation of Visual and Functional Regression Testing
Related article:
Complete Guide to Automating Visual and Functional Regression Testing

For example, if your app has an asynchronous load, it's not enough to just call startActivityAndWait()You must implement smart waits so that the system registers the code that executes when the content finally appears. This is achieved by interacting with the interface through UiAutomator, looking for specific elements and waiting for them to become visible before the test ends.

For an advanced workflow, you could program the generator scroll lists vertically using method flingNavigate to detailed screens or even manage system permission dialogs. The more accurate the simulated walkthrough, the more accurate the generated profile will be, and therefore, The smoother the experience will be actual end user.

Performance generation and validation

Once the generator is written, it's time to run it. Ideally, you should use a Gradle-managed device (GMD) or an emulator with an image aosp to have root permissions, although recent versions of the library already allow generating profiles on physical devices with Android 13 or higher without complications.

When running the Gradle task :app:generateBaselineProfileThe system launches the app several times, collects the invoked classes and methods, and creates a file baseline-prof.txtThis file is automatically placed in the app's assets folder, ready to be packaged in the AAB.

To find out if it really worked, we used Jetpack MacrobenchmarkWe created a test that compares two scenarios: one with CompilationMode.None() (without optimization) and another with CompilationMode.Partial() (using the profile). When analyzing the metric timeToFullDisplayIt is common to observe drastic reductions in milliseconds, validating that critical code no longer needs to be compiled in real time.

In real-world scenarios, such as with large-scale apps, it has been observed that the Just-in-Time (JIT) thread goes from being busy 25% of the time to just 3%. This frees up CPU resources and reduces the device's thermal load, resulting in a more stable and efficient app , especially on low-end devices.

Implementing Baseline Profiles is one of the most cost-effective investments in user experience, as it allows software to feel lightweight and responsive from the very first second. By combining the use of benchmark modules for generating and constantly validating boot times, any developer can transform a slow application into an instant, professional tool that retains users.


Add as preferred source in Google