When an app feels sluggish, the UI stutters, or the battery drains faster than expected, the underlying cause is often hidden deep inside the system scheduler, graphics pipeline, or input stack. Android’s built‑in tracing framework, Perfetto, records low‑level events in a highly efficient binary format, allowing you to see exactly what the kernel and system services were doing at any moment.
Why use Perfetto? Unlike the generic “Show layout bounds” overlay, Perfetto captures timestamps from the kernel, SurfaceFlinger, binder calls, and more. This gives you a single source of truth that can be replayed on a desktop, filtered, and correlated with app‑level logs.
adb installed (part of the Android SDK Platform‑Tools).Privacy note: A Perfetto trace can contain sensitive data such as app package names, input events, and even clipboard contents. Treat trace files like any other personal data – keep them private and delete them when you’re done.
Perfetto ships as part of the system image, but some heavily trimmed custom ROMs may disable it. Run the following command from a terminal on your PC:
adb shell "which perfetto"
If the output is /system/bin/perfetto (or any path), you’re good to go. If the command returns nothing, your device does not expose the binary – you’ll need to use a device with standard Android firmware.
Perfetto records data in buffers identified by a comma‑separated list of categories. The most useful default set for UI performance looks like this:
--buffers=perfetto.trace --categories=sched,gpu,view,hal,am,wm,androidx,process,network
Brief explanation of the most common categories:
sched – kernel scheduler events (CPU run time, context switches).gpu – GPU command submission and rendering timing.view – Android View hierarchy layout and draw calls.wm – Window manager actions (surface creation, composition).am – Activity Manager lifecycle events (app launch, pause, resume).process – Process start/stop and thread activity.If you are troubleshooting a specific subsystem, you can trim the list to only the relevant categories – this reduces trace size and speeds up analysis.
Open a command prompt on your PC and run the following one‑liner. Adjust --duration (in seconds) and --buffer-size (in MB) to match the length of the problem you want to capture.
adb shell "perfetto -c - --out /data/local/tmp/trace.pb \
-t 30 \
-b 64M \
-c "sched,gpu,view,wm,am,process""
Explanation of the flags:
-c – tells Perfetto to use the command‑line config (no JSON file needed).-t 30 – record for 30 seconds.-b 64M – allocate a 64 MB ring buffer; increase if you expect a very busy trace.-c "..." – the category list we discussed./data/local/tmp/trace.pb – the temporary location on the device where the binary trace will be written.When you press Enter, the command returns immediately and the trace starts in the background. You will see a short log line like:
Trace started, writing to /data/local/tmp/trace.pb
Reproduce the issue on the device (open the problematic app, scroll, start a game, etc.) while the trace is running. After the duration expires, Perfetto automatically stops and writes the file.
adb pull /data/local/tmp/trace.pb ~/Desktop/trace.pb
Verify the file size – it should be roughly the buffer size you allocated (e.g., 10‑30 MB). If the file is unexpectedly small (< 100 KB), the trace likely captured no data; revisit the category list and ensure the device was not in a low‑power “Doze” state.
You have two main options:
trace.pb. The UI loads instantly and provides a timeline with layers for each category.Both tools let you zoom, filter, and hover over events to see timestamps and thread IDs.
In the Perfetto UI, enable the View hierarchy track (under the view category). Look for long gaps between measure and draw events. A gap larger than 16 ms (the frame budget for 60 Hz displays) shows up as a red “jank” marker.
Example: A scroll operation where the draw event takes 45 ms will produce a visible stall – this often points to heavy layout work or bitmap decoding on the UI thread.
Switch to the sched track. Look for a thread that stays in the Running state for an extended period while the UI thread is idle. That thread is likely hogging the CPU, causing the UI to miss its frame deadline.
The gpu track shows when the compositor submits commands to the GPU. If you see a burst of glFlush calls followed by a long gpu:frame interval, the GPU is the bottleneck. This is common on older devices when rendering complex animations.
Binder calls appear under the process track. A sudden spike of Binder transaction events from a background service can indicate excessive IPC, which may delay the UI thread.
Use the androidx category to see lifecycle callbacks from Jetpack components – helpful when diagnosing misbehaving ViewModels.
If you prefer not to type long ADB commands, Android 12+ ships with a quick‑access shortcut:
adb bugreport – the generated zip contains a perfetto_trace.pb file you can extract and open.This method is slower (the bugreport includes many extra logs) but requires no manual command construction.
adb shell getprop ro.build.version.sdk (must be ≥ 26). If the binary exists but returns permission denied, you may need to run adb root on a userdebug build, which is not possible on production devices.-b 32M) or shorten the duration. You can also direct the output to /sdcard/ if /data/local/tmp is too small.For power users who need fine‑grained control, Perfetto accepts a JSON configuration file. Create myconfig.json on your PC:
{
"buffers": [{"size_kb": 65536, "name": "main"}],
"data_sources": [{
"config": {
"name": "android.trace",
"target_buffer": 0,
"android_trace_config": {
"categories": ["sched", "gpu", "view", "wm", "am"]
}
}
}]
}
Push it to the device and start Perfetto with:
adb push myconfig.json /data/local/tmp/
adb shell "perfetto -c /data/local/tmp/myconfig.json -o /data/local/tmp/trace.pb"
This approach lets you pre‑define buffer sizes, enable multiple data sources (e.g., system stats), and reuse the same config for repeated captures.
/data/local/tmp/trace.pb from the device: adb shell rm /data/local/tmp/trace.pb.Perfetto gives you a window into the low‑level workings of Android without ever needing root access. By following the steps above you can capture a concise, high‑resolution trace, pull it to your workstation, and dissect the exact moments where the system missed a frame or a background thread stole cycles. The workflow scales from quick “why is my app janky?” investigations to deep‑dive performance audits for release engineering.
Keep the following checklist handy for future debugging sessions:
perfetto is present on the device..pb file.view, sched, and gpu tracks.With practice, interpreting Perfetto traces becomes second nature, turning vague “slow app” complaints into concrete, actionable data.









