What’s new in Android Performance — Google I/O 2023 edition

Ben Weiss
Android Developers
Published in
9 min readMay 10, 2023

--

Over the past years we have worked to make working with performance more approachable and rewarding. In this article we share the latest developments in that area. We’ll cover Baseline Profiles, tooling improvements within Android Studio, libraries and how we made the technology work better for you behind the scenes. We’re also very excited to share new experimental technology, working on top of Baseline Profiles, to provide you with even bigger startup performance improvements. Read on for a full tour of what’s new in Android Performance during Google I/O 2023, or jump directly to the end for actionable steps in your performance journey.

Updates on Baseline Profiles

Baseline Profiles improve code execution speed by about 30 %, for both app startup and runtime by avoiding just-in-time (JIT) compilation. We built several tools to help you streamline Baseline Profile creation and maintenance, including a new Android Studio Template and the Baseline Profile Gradle plugin. You can get started with both today, using Android Studio Hedgehog and the Android Gradle Plugin 8.0.0 or newer.

Streamline profile generation with the Baseline Profile Gradle Plugin

The Baseline Profile Gradle Plugin makes it easier to generate and maintain Baseline Profiles both during local development as well as CI. It performs all the 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’s source-set.

After applying the plugin, it can be configured with a new baselineProfile block in your build script. The generateBaselineProfile Gradle task runs all baseline profile tests for you. The resulting profile files are stored in a generated folder and can be accessed from there. These features remove friction from automating Baseline Profile generation, both locally and on a remote CI server. And by specifying a Gradle Managed Device to use when generating a profile, you don’t even need an attached physical device. The plugin’s DSL enables a highly configurable setup and enables you to automate and reproduce Baseline Profile generation.

Check out the code sample (currently on a separate branch) and guiding documentation to get started.

Create and manage multiple Baseline Profile source files with AGP 8+

AGP 8 onwards supports easier generation of Baseline Profile with support for multiple source files, variant specific profiles, and support for the new Gradle plugin mentioned above. The default location for Baseline Profiles now is src/main/baselineProfiles/. Baseline Profile source files stored in this directory will be picked up and merged into your application. This enables you to store separate profile files for app startup and each distinct user journey.

Multiple Baseline Profile source files in the Macrobenchmark Sample

Easier onboarding with the Android Studio Baseline Profile Generator Template

To assist you getting started with Baseline Profiles, Android Studio Hedgehog (2023.1.1) adds the Baseline Profile Generator module wizard template. By using this template, your app can be set up with Baseline Profiles in a visually assisted way.

Get started by navigating to File > New > New Module and select Baseline Profile Generator from the list of templates.

Baseline Profile Generator Wizard

When you’re finished, the template will have made several changes for you. It creates a new :baselineprofile test module containing basic generators and benchmarks. The BaselineProfileGenerator class creates a basic baseline profile for you and StartupBenchmarks can verify everything works as intended. Also, Baseline Profile Gradle plugin will be applied in relevant modules. Lastly, a dependency on androidx.profileinstaller will be added, to aid local verification and backwards compatibility.

From here, all you need to do is execute the Generate Baseline Profile run configuration, which runs included Baseline Profile generators and copies the generated profiles to src/release/generated/baselineProfile.

Generate Baseline Profile run configuration

The run configuration calls the :app:generateBaselineProfile task, looks for all Baseline Profiles generators and only runs these.

The BaselineProfileGenerator is very basic and does only start your app and wait for the app startup to complete. We recommend creating a Baseline Profile for each critical user journey through your app. As user journeys vary between apps, it’s up to you to decide what to optimize. A good starting point is anything that’s directly tied to business results, such as sign up, login, checkout or other major actions your app offers. You can get inspiration from our code samples.

To get started, download Android Studio Hedgehog Canary today.

And for a guided tour through the whole onboarding process check out the updated codelab: Improve app performance with Baseline Profiles.

Introducing Startup Profiles and Dex layout optimizations

Starting with version 8.1, the Android Gradle Plugin (AGP) can pull code that’s required for app startup into the primary dex file of your app. This optimization is called dex layout optimization and helps to reduce dex page faults during app startup. This can significantly speed up app startup as only a single dex file needs to be loaded until the app has completed startup.

Before and after dex layout optimization

While AGP can create separate dex files for your app, it doesn’t know what fully defines startup for your app without your help. This is where Startup Profiles come in. You can think of Startup Profiles as a subset of Baseline Profiles that are specifically tailored to app startup. Both share the same format and use the same underlying technology. Since app startup differs for every application, libraries do not contribute to the Startup Profile.

Baseline Profiles provide performance gains of around 30 %, compared to an app that requires interpretation and JIT compilation, for example right after an update is pushed. Our early tests with Dex layout optimizations have shown an additional 30% performance improvement on top of Baseline Profile gains for app startup. This is especially beneficial since these gains are always seen in cold startups, even if your production app already has a well functioning cloud profile.

To make the most of Dex layout optimizations and Startup Profiles, you need to let the Android Framework know when your app is done with startup. If you don’t do anything, app startup will be considered done when the first frame is drawn. To make sure the Startup Profile contains information up to the point where your user can take over, use the reportFullyDrawn APIs. You can do this via the FullyDrawnReporter or the Compose ReportDrawn APIs. Additionally, you need to define the end point for the startup benchmark at a point where you deem startup complete. Match the call to reportFullyDrawn with what you’re expecting to be displayed on screen at the point where the app is ready to be used.

You can read more about Dex layout optimizations and Startup profiles in the guiding documentation.

New developments in the Macrobenchmark library

The Macrobenchmark library enables you to measure app performance, create baseline profiles and monitor whether changes to your app make a difference to app performance. The 1.2.0 will graduate to a beta release soon. Here are some feature highlights.

Utilizing new Android platform features in benchmarks

From Android 13 and newer you can generate a Baseline Profile with the BaselineProfileRule on non-rooted devices or emulators.

From Android 14 and newer, target apps no longer need to be reinstalled between benchmark runs. This enables apps to save state, such as cache, session state or login tokens between runs. This change removes the need to inject these states manually before benchmarking, which would have required a rooted device.

New APIs

✨ Baseline Profile generation is no longer considered experimental ✨

You can remove the opt-in to experimental API annotation from your code when creating a baseline profile using the collectBaselineProfile method. But if you like to stay on experimental APIs, we have a new API for your consideration.

The newly introduced collectStableBaselineProfile runs and waits until a profile is considered stable for a given amount of iterations. This means that your app’s Baseline Profile will better reflect what’s going on in your app as a code path is executed.

More powerful metrics with custom trace processing

PerfettoTraceRule enables custom trace collection in tests other than benchmarks (requires API 23+). This is a powerful feature that will allow users to collect performance and timing data about tests.

PerfettoTraceProcessor enables querying trace contents, and is the engine behind all of the existing Macrobenchmark Metric APIs. Now it’s possible to use it with TraceMetric to define fully custom metrics in the same way Macrobenchmark does from anything information in a Perfetto system trace.. This is another powerful feature that will allow users to customize their benchmarks even further.

Attributing Power consumption from benchmarks

The new PowerMetric API can be used to measure energy consumption and power states. This is a useful feature that will allow users to track the energy consumption of their benchmarks.

Bug fixes and other improvements

The team behind Macrobenchmark also made a variety of other improvements to ergonomics, fixed bugs and improved overall behavior. To learn more, check out the documentation. If you want to get more detail, you can find a full list of release notes with attached code and tracking issues here.

Android Studio Power Profiler

Android Studio Hedgehog features a new Profiler which shows power consumption on physical devices, segmented by each sub-system (such as: Camera, GPS, and more). This data is made available when recording a System Trace and helps you to visually correlate power consumption of the device to the actions happening in your app. For example, you can A/B test batching API calls vs making individual API calls to optimize power consumption in the Cellular power rail.

The new Power Profiler in Android Studio Hedgehog

To get started, use a Pixel 6+ device to record a System trace and load it into Android Studio, or use the profiler to capture a System trace directly from the attached device.

Why you should focus on performance

When working on application performance, finding the right starting point can be a challenge. Working with the Android developer community, we found that engineers sometimes lack the right information to justify working on app performance.

Improving performance has a number of benefits, both for your users and for your business. For users, a fast and responsive app means a better user experience. Your users will be able to get the information they need quickly and easily, and they’ll be more likely to come back to your app.

For your business, improved performance can lead to increased revenue and decreased costs. When users are happy with your app, they’re more likely to make purchases or take other actions that benefit your business. Additionally, a well-performing app can help you save money on development and maintenance costs.

Next steps

  1. Set your app up to use Baseline Profiles with the new Gradle plugin
  2. Upgrade to Android Gradle Plugin 8+
  3. Move existing Baseline Profiles into the new default directory src/main/baselineProfiles/
  4. Download the Android Studio Hedgehog Canary to check out the Baseline Profile template and power profiler
  5. Check out our updated codelab for a guided tour
  6. Use the Fully Drawn and collectStableBaselineProfile APIs for better Baseline Profiles
  7. Get started with Dex layout optimizations for even more performance gains
  8. Implement your own Macrobenchmark tests to measure how performance moves over time
  9. Record a System trace on a Pixel 6+ device to view power consumption of different subsystems (Camera, GPS, CPU, etc)
  10. 👏 and share this article to help improve app performance for everyone

--

--