LinkedIn Android
The Cold Start Glacier
LinkedIn's Android app took 8+ seconds to cold-start on mid-range devices. The fix began with understanding what was happening before the first frame was drawn.
The Incident
By 2021, LinkedIn's Android app cold-start latency had become a significant user experience issue, particularly for users on mid-range devices common in growth markets. Time-to-interactive on a fresh launch exceeded 8 seconds in some measurements. Engineers used Android Vitals, Perfetto traces, and App Startup library tooling to diagnose a startup sequence that had accumulated years of SDK integrations and initialization logic — none of which had ever been audited as a system.
Evidence from the Scene
- App cold-start consistently exceeded 8 seconds on devices with 4GB RAM
- Perfetto trace showed 14 ContentProviders registering before Application.onCreate() completed
- StrictMode logs (enabled internally) flagged disk I/O on the main thread during Application.onCreate()
- The full Hilt dependency graph was initialized synchronously before any Activity was visible
- Removing a single analytics SDK in a test build reduced startup time by over 1 second
The Suspects
3 of these are the real root causes. The others are plausible-sounding distractors.
ContentProviders from third-party SDKs auto-initializing synchronously before Application.onCreate()
Hilt dependency graph fully initialized at app startup instead of lazily on first use
SharedPreferences reads blocking the main thread during Application.onCreate()
Complex layout hierarchies with deep nesting causing slow initial inflation
Room database schema migration running on the main thread at startup
Firebase Remote Config performing a synchronous network fetch at startup
The Verdict
Real Root Causes
ContentProviders from third-party SDKs auto-initializing synchronously before Application.onCreate()
Every ContentProvider registered in AndroidManifest.xml is instantiated synchronously before Application.onCreate() runs. Third-party SDKs that register ContentProviders for automatic initialization run their startup logic without the app's knowledge or control, adding hundreds of milliseconds each. The App Startup library consolidates these into a single ContentProvider with explicit dependency ordering.
Hilt dependency graph fully initialized at app startup instead of lazily on first use
Eager DI initialization builds the entire object graph — network clients, database connections, analytics pipelines — before any UI is visible. Migrating to lazy initialization and scoping components to their actual consumer's lifecycle defers this work to the moment each component is first needed, removing it from the startup critical path entirely.
SharedPreferences reads blocking the main thread during Application.onCreate()
SharedPreferences.getString() blocks the main thread waiting for disk I/O on the first read if the file has not been loaded. Multiple SDK initializations each reading their own preference files compounded this into seconds of blocking time. Moving reads to DataStore with async coroutine APIs removes this bottleneck.
Plausible But Wrong
Complex layout hierarchies with deep nesting causing slow initial inflation
Layout inflation affects the first frame render, not the pre-Activity startup time captured in ContentProvider and Application initialization traces. Perfetto would show layout inflation as a distinct phase after the main thread is unblocked — not during the 8-second ContentProvider/DI initialization window.
Room database schema migration running on the main thread at startup
Room migrations with main-thread execution cause ANRs, not a gradual 8-second startup. The clues point to initialization-time overhead from SDK and DI setup, not a database migration operation.
Firebase Remote Config performing a synchronous network fetch at startup
Firebase Remote Config fetches are asynchronous by default and would not block startup. The blocking startup operations described here are disk I/O and in-process initialization, not network calls.
Summary
LinkedIn's startup had accumulated years of SDK integrations, each adding ContentProviders, Application.onCreate() callbacks, and DI component initializations — none of which were gated on actual user need. The engineering team used the App Startup library to consolidate ContentProvider initialization into a single provider with explicit ordering, migrated DI initialization to lazy patterns, and replaced synchronous SharedPreferences reads with DataStore coroutine reads deferred to background threads. These changes reduced cold-start time by over 60% on mid-range devices.
The Real Decision That Caused This
“Integrating third-party SDKs and expanding the dependency graph over years without auditing the cumulative startup cost — allowing synchronous initialization work to compound into multi-second startup times that were invisible until measured with proper tooling.”
Lesson Hint
Chapter 7 (Platform & Performance) covers App Startup optimization, ContentProvider consolidation with the App Startup library, and Perfetto tracing. Chapter 2 (App Architecture) covers lazy initialization patterns and Hilt component scoping.
Want to test yourself before reading the verdict?
Open Interactive Case in Autopsy Lab