UI jank detection

Android renders UI by generating a frame from your app and displaying it on the screen. If your app suffers from slow UI rendering, then the system is forced to skip frames. When this happens, the user percieves a recurring flicker on their screen, which is referred to as jank.

When jank occurs, it's usually because of some deceleration or blocking async call on the UI thread (in most apps, it's the main thread). You can use system traces to identify where the problem is.

Detect jank on Android 10 and lower

Android 10 (API level 29) and lower displays relevent OS graphics pipeline information in a single section on the CPU Profiler system trace called Display.

The display UI window

Figure 1. The Display section shows the following graphics pipeline information: Frames, SurfaceFlinger, VSYNC, and BufferQueue.

  • Frames: This section shows the UI thread and RenderThread trace events in your app. Events that are longer than 16ms are colored red to highlight potential janky frames because they exceed the deadline to render at 60 frames per second (fps).
  • SurfaceFlinger: This section shows when the SurfaceFlinger processes the frame buffers. SurfaceFlinger is a system process that is responsible for sending buffers to display.
  • VSYNC: This section displays the VSYNC, a signal that synchronizes the display pipeline. The track displays the VSYNC-app signal, which shows when your app is starting too late. Typically, this occurs because the UI thread is busy. It causes a visible flicker to appear on your screen during an animation and adds extra input latency until the animation or scroll completes. This is especially important to view for high-refresh-rate displays, as they may occur more frequently than 60 times per second or at a variable rate.
  • BufferQueue: This section shows how many frame buffers are queued up and are waiting for SurfaceFlinger to consume. For apps deployed to devices running Android 9 (API level 28) or higher, this track shows the buffer count of the app's surface BufferQueue (0, 1, or 2). BufferQueue can help you understand the state of image buffers as they move between the Android graphics components. For example, a value of 2 means that the app is currently triple-buffered, which results in extra input latency.

The Display section provides useful signals to detect potential jank—for example, when the UI thread or RenderThread takes longer than 16 ms. To investigate exact details of what caused the jank, you can probe the Threads section, which shows the threads relevant to UI rendering.

The Threads section under Display

Figure 2. The Threads section under Display.

In figure 2, the Threads section shows the UI thread (java.com.google.samples.apps.iosched), RenderThread, and the GPU completion thread. These are the threads relevant to UI rendering and may contribute to jank.

How to detect jank

To detect jank on Android 10 or lower, follow these steps:

  1. Look at the Frames track in Display. The red frames are candidates for investigation.

    The Frames section under Display

    Figure 3. The Frames track under Display.

  2. Once you find a potentially janky frame, zoom in by pressing W or scrolling the mouse wheel while holding Control (Command on macOS). Continue zooming in until you start to see the trace events in the UI thread and RenderThread.

    Trace events in the UI thread and RenderThread

    Figure 4. Trace events in the UI thread and RenderThread.

    In figure 4, Choreographer#doFrame shows when the UI thread is calling Choreographer to coordinate animation, view layout, image drawing, and related processes. DrawFrames shows when RenderThread forms and issues actual drawing commands to the GPU.

  3. If you see a particularly long trace event, you can zoom in further and find out what may have contributed to the slow rendering. Figure 4 shows inflate in the UI thread, which means the app is spending time on inflating the layout. When you zoom into one of the inflate events, you can find out exactly how long each UI component is taking, as shown in figure 5.

    Menu showing precise duration of a UI component

    Figure 5. You can zoom into a single UI event to see exactly how long each component takes.

Detect jank on Android 11 and higher

On Android 11 (API level 30) and higher, you have access to the frame lifecycle data in the system trace, so Android Studio will show the Frame Lifecycle section when a trace is captured on a supported device.

Frame Lifecycle section with different tracks

Figure 6. The Frame Lifecycle section contains different tracks.

The Frame Lifecycle section shown in figure 6 contains the layer name and four tracks. Each track represents one stage in the frame rendering pipeline. The Frame Lifecycle elements are as follows:

  1. Frame Lifecycle (Layer name): The section title contains the layer name in parentheses. A layer is a single unit of composition.
  2. Application: This track shows the time from when the buffer was dequeued by the app to when it was enqueued back. This usually corresponds to the trace events in RenderThread.
  3. Wait for GPU: This track shows how long the buffer was owned by the GPU. This is the time from when the buffer is sent to the GPU to when the GPU finishes its work on the buffer. This does not indicate that the GPU was working only on this buffer during this time. For detailed info on what the GPU works on during a given time, you may want to use Android GPU Inspector.

  4. Composition: This track shows the time starting from when SurfaceFlinger latches on to the buffer and sends it for composition, to when the buffer is sent to the display.

  5. Frames on display: This track shows how long the frame was on the screen.

The Frame Lifecycle section illustrates how a frame buffer moves between different stages of the rendering pipeline. The frames are color coded by frame number so that it's easier to track a particular frame.

Android Studio also shows all frames in the trace in a table format in the Frames tab.

A table of all the frames in the trace in the Frames tab

Figure 7. The Frames tab shows a table of all the frames in the trace.

In figure 7, the columns Frame #, Application, Wait for GPU, and Composition represent the same data as the tracks in figure 6. The column Frame Duration represents the time from the start of Application to the start of Frames on Display. This is essentially how long it takes to render a frame end-to-end.

You can sort the frames table by any column to quickly find the shortest or longest frame. The table also supports pagination controls that help you navigate through hundreds of frames.

How to detect jank

To understand these steps, it helps to be familiar with the tools and views described in the how-to section for Android 10 and lower. On Android 11, you still have the Display section, but because there is more granular frame timing, the Frames track is hidden. To detect and investigate jank on Android 11, follow these steps:

  1. Sort the Frames table by the Application column in descending order, so that the frames that take the longest appear first.

    Application column sorted in descending order

    Figure 8. The Application column in the Frames table sorted in descending order.

  2. Find the longest running frames and select the table row. This will zoom in on the selected frame in the timeline view to the left.

    Timeline view alongside Frames table

    Figure 9. The timeline view shows details about the frame selected in the Frames table.

  3. Look for relevant threads in the Frame Lifecycle and Threads sections.

    Frame Lifecycle and Threads sections

    Figure 10. The Frame Lifecycle and Threads sections.

Learn more

To learn more about how to reduce jank, see Common sources of jank.