Cold Start and ANR on a Mid-Tier Android Device
An Android app has a p90 cold start of 4.8 seconds on a four-year-old mid-tier device, against a product target of 2.0 seconds. In Application.onCreate the app sequentially initialises analytics (380 ms), crash reporting (210 ms), an image loader (250 ms), an ad SDK (600 ms), and opens a Room database (300 ms). SplashActivity then calls GET /config and GET /me synchronously on the main thread before calling setContentView. On a 3G profile with 900 ms round-trip time, each call takes about 1.4 seconds. Play Console shows an ANR cluster for input dispatching timed out, with some reports at the 12-second mark. The team proposes moving the two network calls to a background thread and showing a spinner until both complete. The ad SDK is required for revenue but is not needed to render the first screen. Crash reporting must initialise before any crash could occur, but not necessarily before first frame.
1. Diagnose the startup sequence. Which changes address the ANR, and which address time to first meaningful content?
Read the worked answer
The ANR is caused by network I/O on the main thread in SplashActivity. Input dispatching cannot proceed while the main thread is blocked on socket reads, so moving those calls off the main thread is mandatory and fixes the ANR class of failure.
It does not fix perceived startup. The team's proposal still waits for both calls before rendering anything, so the user sees a spinner for roughly 2.8 seconds after the app has already spent about 1.7 seconds in Application.onCreate. The total remains near 4.5 seconds. A spinner is not content.
Separate the work into must-render and can-defer. Must-render: inflate and display a cached shell of the first screen immediately, using last-known config and profile from local storage. Can-defer: refresh /config and /me in parallel, then update the UI. The ad SDK and image loader should be initialised lazily or after first frame. Crash reporting can be initialised early but should be measured; 210 ms may be acceptable, whereas 600 ms of ad SDK work before first frame is not.
The diagnosis should be stated as a budget: Application.onCreate consumes about 1.74 seconds sequentially, and main-thread network adds about 2.8 seconds. Fixing only the second number leaves the app well above the 2-second target.
2. Propose a startup architecture and initialisation order that meets the target without breaking revenue or crash reporting.
Read the worked answer
Adopt a phased startup with explicit ownership.
Phase 1, before first frame: create the application, install the crash handler, open only the database handles needed for the first screen, and read cached config and profile. Render a skeleton or cached content immediately. No network call blocks rendering and no ad SDK initialisation occurs here.
Phase 2, after first frame: run /config and /me in parallel on a background dispatcher. Update the screen when either returns; do not wait for both. If config is stale beyond a defined age, show a non-blocking banner rather than blocking the UI.
Phase 3, idle or first user interaction: initialise the ad SDK and image loader. The ad SDK can be warmed on a background thread if it is thread-safe, but its readiness must not gate content. Revenue risk is managed by placing ads in a later slot and measuring fill rate rather than by blocking startup.
Dependency management: use an explicit initialiser graph rather than ad hoc calls in Application.onCreate. Mark crash reporting as a dependency of any component that could crash, and mark ad SDK as dependent on nothing in the first screen. Add per-phase tracing so regressions are attributable to a phase rather than to a single 4.8-second number.
3. Define how you would measure success and what guardrails you would put in place to prevent regression.
Read the worked answer
Measure both technical and user-visible outcomes. Use macrobenchmark cold-start measurements on a fixed mid-tier device profile, reporting p50 and p90 rather than an average. Add per-phase traces for Application.onCreate, first frame, config load, and profile load. Track ANR rate and crash-free sessions in the release dashboard, and segment by device tier and network profile.
Set guardrails before shipping: p90 cold start at or below 2.0 seconds on the reference device; no main-thread network or disk I/O during startup; ANR rate no worse than the previous release; first-frame time independent of network latency. Add a startup budget in CI so a new SDK initialisation that adds more than 100 ms fails the check or requires an explicit waiver.
Measure the ad SDK separately because revenue metrics can hide a latency regression: track ad fill rate, impression latency, and revenue per session alongside startup time. Also verify that cached config does not serve dangerously stale values; define a maximum age and a refresh path. Finally, run the measurement on a cold install and after an update, because update flows can trigger different initialisation paths.