androidengineers.Book a session

Android Architecture Fundamentals

Exercise: Trace a Process Start with adb/systrace

exercise45 minMedium

Measuring is the first step to optimizing. This exercise walks through capturing and reading a startup trace to identify exactly what your app does — and what slows it down — during cold start.

Setup

You need:

  • A physical device or emulator with USB debugging enabled
  • adb in your PATH
  • Android Studio (for the built-in Profiler alternative)

Verify connection:

adb devices
# Should list your device as "device" (not "unauthorized")

Option A: Android Studio CPU Profiler (Easiest)

  1. Run your app in debug or profileable mode
  2. Open Profiler tab → CPU → click Record before cold start
  3. Force-stop the app: adb shell am force-stop com.example.myapp
  4. Launch from home screen while recording
  5. Stop recording after first frame renders

The flame chart shows:

  • Thread activity over time
  • Method durations (click any slice to see duration)
  • Long slices on the main thread = potential jank

Option B: Perfetto (Production-grade)

# 1. Force-stop the app
adb shell am force-stop com.example.myapp

# 2. Start Perfetto trace
adb shell perfetto \
  -c - --txt \
  -o /data/misc/perfetto-traces/startup.pftrace \
<<EOF
buffers: { size_kb: 65536 drain_period_ms: 250 }
data_sources: { config { name: "linux.process_stats" } }
data_sources: { config { name: "track_event" } }
data_sources: { config {
    name: "android.startupapp"
    android_startup_config { startup_type: "cold" }
} }
duration_ms: 10000
EOF &

# 3. Immediately cold-start your app
adb shell am start-activity -W com.example.myapp/.MainActivity

# 4. Pull the trace
adb pull /data/misc/perfetto-traces/startup.pftrace ~/Desktop/

Open startup.pftrace at ui.perfetto.dev.

Reading the Trace

Key slices to find in the trace:

SliceWhat it meansTarget
Zygote:ForkAndSpecializeCommonProcess fork from Zygote< 5ms
bindApplicationART init + app class load< 100ms
ActivityThread:handleBindApplicationApplication.onCreate runs hereYour code
ContentProvider onCreate callsOften hidden bottleneckEach < 20ms
ActivityThread:performLaunchActivityActivity.onCreateYour code
Choreographer#doFrame (first)First frame renderedTarget: < 500ms total

Step-by-Step Analysis

1. Find your Application.onCreate: Search for bindApplication. Everything between this and the first Choreographer#doFrame is your startup cost.

2. Identify ContentProvider init: Look for ContentProvider.onCreate calls inside bindApplication. These run synchronously before your Application.onCreate — a common surprise.

3. Find the slowest methods: Sort flame chart by duration. Look for synchronous disk reads, network calls, or heavy object init on the main thread.

4. Measure with am start -W:

adb shell am force-stop com.example.myapp
adb shell am start-activity -W -n com.example.myapp/.MainActivity
# Output:
# WaitTime: 892ms    ← total wall time
# ThisTime: 756ms    ← your activity only
# TotalTime: 789ms   ← from process create to first frame

Run this 5 times and average; first run is always slower due to disk cache effects.

Exercise Tasks

  1. Record a cold start trace for your app
  2. Find your Application.onCreate in the trace — how long does it take?
  3. List all ContentProviders that initialize at startup
  4. Identify the single slowest operation on the main thread
  5. Move any synchronous DB/file reads to a background thread and re-measure
  6. Check: does removing a non-critical SDK init from Application.onCreate reduce TotalTime?

Expected Findings in a Typical App

  • Firebase init in Application.onCreate: ~50–150ms
  • Room database creation: ~30–80ms if done synchronously
  • ContentProvider from analytics SDK: ~20–50ms per provider
  • Glide/Coil init: usually fast (<5ms)

Eliminating 3 synchronous SDK inits from Application.onCreate and moving them to lazy/background initialization typically cuts cold start by 100–300ms.

Key Takeaways

ToolBest for
Android Studio ProfilerInteractive debugging, easy setup
PerfettoProduction-accurate, shareable traces
am start -WQuick timing without trace overhead
bindApplication sliceWhere your app's startup cost lives
ContentProviderCheck each one — they run before Application.onCreate

YOUR LEARNING JOURNEY

0 of 177 available lessons completed

Progress saved in this browser. No account needed.
Exercise: Trace a Process Start with adb/systrace | Android System Design | Android Engineers