The Anatomy of Jank
"Jank" is the visual stuttering experienced by a user when an Android device fails to render frames at a consistent rate. For a smooth 60Hz display, the system must produce a new frame every 16.6 milliseconds. If a frame takes 20ms to produce, it misses its display window, resulting in a dropped frame and a visible stutter.
Analyzing jank in AOSP requires a comprehensive understanding of the UI rendering pipeline, from the application's Java code down to the hardware composer.
Identifying Dropped Frames in Perfetto
Perfetto is the definitive tool for identifying exactly when and why a frame was dropped.
- Open a Trace: Load your trace into
ui.perfetto.dev. - Locate the Frame Timeline: Find the
Frame Timelinetrack for the specific application experiencing jank. - Spot the Red Blocks: The timeline shows
ExpectedvsActualrendering times. TheActualblocks turn red if they exceed the expected deadline. - Follow the Arrows: Clicking on a red
Actualblock draws arrows connecting the UI Thread, the RenderThread, and SurfaceFlinger. This visually isolates the three phases of rendering for that specific dropped frame.
Main Thread vs RenderThread Jank
When analyzing a dropped frame, the first step is to determine which thread is at fault.
Main Thread (UI Thread) Jank
If the Choreographer#doFrame slice on the main thread is long, the application logic is too heavy. The main thread is responsible for handling input, executing animations, measuring views, and inflating layouts.
- Heavy Inflation: Are you inflating complex XML layouts inside
RecyclerView.Adapter#onCreateViewHolder? - Garbage Collection (GC): Is the thread paused due to a heavy GC run? (Look for
GCslices nearby). - Blocking I/O: Is the thread reading from disk (
SharedPreferences) or waiting on a slow Binder call?
RenderThread Jank
If the main thread finishes quickly, but the DrawFrame slice on the RenderThread is long, the GPU is struggling to render the display list.
- Complex Paths: Drawing custom
Canvaspaths or large numbers of text glyphs can be very expensive. - Hardware Layer Updates: Using
View.setLayerType(LAYER_TYPE_HARDWARE, ...)can improve performance, but updating the content of that layer forces the GPU to redraw it completely, which is costly. - Bitmap Uploads: Loading massive, unscaled bitmaps into memory forces the RenderThread to upload them to the GPU texture memory, pausing rendering.
GPU Overdraw Analysis
Overdraw occurs when the system draws pixels on top of each other in a single frame. For example, drawing a white background, then a red background on top of it, and finally a button on top of that means the pixels were drawn three times.
Excessive overdraw forces the GPU to waste cycles rendering pixels that the user will never see, leading directly to RenderThread jank.
Debugging Overdraw
Android provides a built-in developer option to visualize overdraw: Settings > Developer Options > Debug GPU overdraw > Show overdraw areas.
The screen will tint colors based on the severity of overdraw:
- True Color: No overdraw (1x draw).
- Blue: 1x overdraw (2x draw).
- Green: 2x overdraw.
- Pink/Red: 3x overdraw or more (Critical).
Fixing Overdraw
To fix overdraw, systematically remove unnecessary backgrounds from layouts. If an Activity has a solid background, and its root layout also defines a solid background, remove one of them.
HWC Composition Type Analysis
Once the RenderThread has generated a buffer, it sends it to SurfaceFlinger. SurfaceFlinger must then combine buffers from the app, the status bar, and the navigation bar into a single image.
It can do this in two ways:
- Client Composition (GPU):
SurfaceFlingeruses the GPU (via OpenGL or Vulkan) to composite the layers. This is power-hungry and uses CPU/GPU cycles. - Device Composition (HWC):
SurfaceFlingerhands the individual buffers directly to the Hardware Composer (HWC) display controller. The display hardware composites the layers on the fly as it scans them out to the screen. This is highly efficient.
Identifying Composition Issues
If a device is dropping frames, it might be relying too heavily on Client Composition.
You can inspect the composition type using dumpsys SurfaceFlinger or by looking at a Winscope trace.
- Look at the
CompositionTypefor each layer. - Ideally, most layers should be marked as
Device. - If layers are frequently falling back to
Client, investigate why. Common reasons include having too many layers (exceeding the HWC's limit), using unsupported blending modes, or utilizing complex crop transformations that the specific hardware controller cannot handle natively.