App startup analysis and optimization

Stay organized with collections Save and categorize content based on your preferences.

During app startup you make the first impression on users. App startup should take as little time as neccessary to load and display information the user needs to start using your app.

Tooling overview

We recommend using the Macrobenchmark library to measure startup. The library provides you with big picture information and detailed system traces to see exactly what's happening during the startup.

System traces provide useful information about what's happening on your device, which lets you understand what your app is doing during startup and helps you identify potential areas for optimization.

Steps to analyze and optimize startup

Apps often need to load specific resources during startup that are critical to end users. Other times, you can wait to load non-essential resources until after startup completes. Consider the following list to help you make the right performance tradeoffs:

  1. Use the Macrobenchmark library to measure the time taken by each operation, and identify blocks that take a long time to complete.
  2. Confirm that the resource-intensive operation is critical to app startup. If the operation can wait until the app is fully drawn, it can help minimize resource constraints at startup.
  3. Ensure that you expect this operation to run at app startup. Often times, unnecessary operations can be called from legacy code or third-party libraries.
  4. Try to move long-running operations to the background, if possible. Note that background processes can still affect CPU usage during startup.
  5. Now that you have fully investigated the operation, you can make a decision on the tradeoff between the time it takes to load and the necessity of including it in app startup. Remember to include the potential for regression or breaking changes when altering the workflow of your app.
  6. Optimize and re-measure until you're satisified with the startup time for your app. For more information, see Use metrics to detect and diagnose problems.

Measure and analyze time spent in major operations

Once you have a complete app startup trace, look at the trace and measure time taken for major operations like bindApplication or activityStart. We recommend using Perfetto or the Android Studio Profiler to analyze these traces.

Look at the overall time spent during app start to identify any operations that:

  • Occupy large time frames and can be optimized. Every millisecond counts in performance. For example, look for choreographer draw times, layout inflation times, library load times, binder transactions, or resource load times. For a general start, you could look at all operations that take longer than 20ms.
  • Block the main thread. For more information, see Navigate a systrace report
  • Aren’t supposed to run during startup.
  • Can wait until after your first frame is drawn.

Further investigate each of these traces to find performance gaps.

Analyze overall thread state

Select the app startup time and look at overall thread slices. ools such as Studio Profiler traceviewer and Perfetto provide a detailed overview of the main thread and how much time is spent in each stage. For more information on visualizing perfetto traces, see the Perfetto UI documentation. The main thread should be responsive at all times.

Identify major chunks of main thread sleeping state

If there's a lot of time spent sleeping, that's likely a result of your app's main thread waiting for work to complete. If you have a multithreaded app, identify the thread that your main thread is waiting on, and consider optimizing those operations. It can also be useful to ensure there's no unnecessary lock contention causing delays in your critical path.

Reduce main thread blocking and uninterruptible sleep

Look for every instance of the main thread going into a blocked state. Perfetto and Studio Profiler show this with an orange indicator on the thread state timeline. Identify the operations, explore if these are expected or can be avoided, and optimize where necessary.

IO-related interruptible sleep can be a really good opportunity for improvement. Other processes doing IO, even if they're unrelated apps, can contend with the IO that the top app is doing.

Improve startup time

After you identify an opportunity for optimization, you can explore some possible solutions to help improve startup times:

  • Load content lazily and asynchronously to speed up time to initial display.
  • Minimize calling functions that make binder calls. If they're unavoidable, ensure that you're optimizing those calls by caching values instead of repeating calls or moving non-blocking work to background threads.
  • To make your app startup appear faster, you could display something that requires minimal rendering to the user as quickly as possible, until the rest of the screen has finished loading.

Analyze UI performance

App startup includes a splash screen and the loading time of your home page. To optimize app startup, you can inspect traces to understand the time taken for your UI to be drawn.

Limit work on initialization

Certain frames may take longer amounts of time to load than others. These are considered expensive draws for the app.

  • Prioritize slow layout passes and pick these for improvements.
  • Each warning from Perfetto and alert from Systrace can be investigated by adding custom trace events to reduce expensive draws and delays.

Measure frame data

There are multiple ways to measure frame data. The four main collection methods are:

  • Local collection using dumpsys gfxinfo
    • Note that not all frames observed in the dumpsys data may be responsible for the slow rendering of your app or have any impact to end-users. However, this is a good measure to look at across different release cycles to understand the general trend of performance. To learn more about using gfxinfo and framestats to integrate UI performance measurements into your testing practices, go to Testing UI performance
  • Field collection using JankStats
    • Collect frame render times from specific parts of your app with JankStats library and record and analyze the data using.
  • In tests using Macrobenchmark (Perfetto under the hood)
  • Perfetto FrameTimeline
    • On Android 12 (API level 31), you can collect Frame timeline metrics from a Perfetto trace to what work was causing the frame drop. This could be the first step to diagnosing why frames are dropped.
  • Android Studio Profiler for jank detection

Check main activity load time

Your app's main activity might contain a large amount of information that is loaded from multiple sources. Check the home Activity layout and specifically look at the Choreographer.onDraw method of the home activity.

  • Use reportFullyDrawn to report to the system that your app is now fully drawn for optimization purposes.
  • Measure activity and app launches using StartupTimingMetric with the Macrobenchmark library.
  • Look at frame drops.
  • Identify layouts taking a long time to render or measure.
  • Identify assets taking a long time to load.
  • Identify unnecessary layouts that are inflated during startup.

Here are some additional possible solutions to explore:

  • Make your initial layout as simple as possible. For more information, see Optimizing Layout Hierarchies.
  • Use ViewStub where layouts aren't immediately VISIBLE. A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime. For more information, see ViewStub.
  • Add custom tracepoints to provide more information about dropped frames and complex layouts.
  • Minimize the number and size of bitmap resources loaded during startup.