The cold start of Android apps refers to the process from the user clicking on the app icon (or launching it through other means) until the first frame of the screen (Activity content) is fully drawn and presented to the user when the application process does not exist at all. This is the most time-consuming and complete startup method. The process involves the collaborative work of multiple system components and applications, and can be divided into the following key stages:
1. User triggers launch (Launcher click/Content):
The user clicks on the application icon in the Launcher (desktop).
Or send an Intent through other applications (such as opening a link in a browser, notifying clicks, etc.) to launch a specific activity of the target application.
2. The Launcher process initiates a request to the SystemServer process:
The Launcher process sends a startActivity request to the core system service ActiveManagerial Service (AMS) running in the system_derver process through the Bind IPC mechanism.
3. AMS processing startup request:
Permission check: AMS checks the launch permissions of the caller (Launcher) and target activity.
Target Activity Analysis: Analyze the Intent to determine the target activity to be launched and its associated application.
Process check: AMS checks whether the process of the target application (package name) exists.
For cold start, the target process does not exist.
Create a new application process request: AMS has decided that a new process needs to be created for this application.
4. Request Zygote incubation process:
AMS sends a request to the Zygote process through a Socket connection (which may also use more efficient mechanisms in newer versions), informing it that a new application process needs to be incubated.
The request contains the package name, Application class name, Activity class name of the target application UID/GID、 Information such as resource paths.
5. Zygote fork new process:
After receiving the request, the Zygote process copies itself through the fork() system call and creates a new child process. This subprocess is the new process of the target application.
The new process inherits Zygote's preloaded framework classes (such as Activity, View, Resources, etc.), system resources (such as themes, commonly used Drawable), and core libraries (such as ART runtime environment). This greatly speeds up application startup and avoids each application having to load these common resources from scratch.
6. New application process startup - Runtime Init:
The newly forked process begins to execute, with the entry point located at the end of ZygoteIit's fork or at a dedicated Runtime Init.
Perform basic runtime environment initialization (such as setting up signal processors, thread pools, etc.).
7. Bind Application Thread to AMS:
The new process will create an Application Thread object (which is an internal class of Activity Thread and implements the IApplication Thread interface).
Register (bind) this Application Thread object as a binder server to AMS through the binder IPC. This establishes a bidirectional communication bridge between AMS and the target application process. AMS can now send instructions to application processes (such as launching activities, services, etc.) through this binder interface.
8. Create ActiveThread and Main Thread (UI Thread):
Create an ActiveThread instance, which serves as the management core for the main thread (UI thread) of the application process.
Create and enter a Looper message loop on the main thread, ready to receive and process messages from the system (AMS) and the application itself (such as Handler messages, UI events).
9. Create an Application object:
AMS sends a bindApplication message to the application process through the recently bound Application Thread Binding interface.
After receiving the message, the main thread (ActiveThread) of the application process:
Create LoadedApk object: Load application APK information.
Create an Instrumentation instance: used to monitor the interaction between the application and the system.
Create ContextImpl (Application Context): The global contextual environment of the application.
Instantiate Application subclass: Reflect to create developer defined Application subclass objects (such as MyApplication).
Call Application. attach (Context): Bind the Context to the Application object (developers typically do not need to override this method).
Installing Content Providers: Key Steps! Before calling Application. onCreate(), the system will install (initialize) ContentProviders under all<application>tags declared in the Manifest. The onCreate () method of these providers will be called at this moment. Note: The initialization of ContentProvider is very early and is an important focus of cold start optimization.
Call Application. onCreate(): Developer visible lifecycle starting point! After creating and binding the context to the Application object and installing ContentProvider, the system calls its onCreate () method on the main thread. This is the main location for developers to perform global initialization (such as initializing SDK, global configuration, database, preloading data, etc.). If this method takes too long to execute, it will significantly delay the start of subsequent activities!
10. Create and launch the target activity:
After confirming the completion of Application initialization, AMS sends a scheduleLaunchActivity message to the application process again through the Application Thread Binding interface.
The Handler of the main thread (ActiveThread) of the application process processes this message:
Create Activity Instance: Instantiate the target Activity class through reflection.
Create ContextImpl (Activity Context): The context environment for Activity.
Call Activity. attach(): Bind key objects such as Context, Application, Window, etc. to the Activity instance (internally creating PhoneWindow and WindowManager).
Call Instrumentation.callActiveonCreate (): and then call the onCreate (Bundle savedInstanceDate) method of the target activity. This is where developers write the main UI initialization logic:
SetContentView (int layoutResId): Key steps! Parse the specified layout XML file (time-consuming operation), create a View tree structure (DecorView and its child Views), but the View is not yet visible at this time.
Initialize the data and view controls (findViewById) required for the activity.
11. Activity visibility lifecycle callback (UI preparation):
After onCreate (), the system sequentially calls on the main thread:
OnStart(): Activity is about to become visible.
OnResume(): Activity has gained focus and is about to begin interacting with the user. At this point, the Activity is at the top of the stack, but the UI content is usually not yet drawn on the screen!
12. ViewRootImpl association and drawing scheduling:
The DecorView in the Activity's PhoneWindow needs to be associated with a ViewRootImpl object.
ViewRootImpl is responsible for:
Connect to Window Manager Service (WMS) to manage windows.
Manage the measurement, layout, and draw processes of the View tree.
Process input event distribution.
Coordinate the VSYNC signal for plotting.
After association, ViewRootImpl will request a complete drawing process once.
13. Perform measurement, layout, and drawing (Measure ->Layout ->Draw):
Measure: Starting from the DecorView root node, recursively traverse the entire View tree. Each View calculates its own size (onMeasure) based on the constraints of the parent container and its own MeasureSpec.
Layout: Based on the measurement results, recursively determine the specific position of each View in its parent container (onLayout).
Draw: recursively traverse the View tree. Each View draws its own content (onDraw) at the calculated location. This is a process of software drawing or hardware acceleration (through RenderThread).
14. First frame submission and display (VSYNC synchronization):
The drawing command (usually OpenGL ES or Vulkan command under hardware acceleration) is submitted to the system graphics buffer.
Choreographer listens for VSYNC (vertical synchronization) signals.
When the next VSYNC signal arrives, the system graphics synthesizer (such as SurfaceFlinger) synthesizes the content of the application buffer with other layers (status bar, navigation bar, other App windows).
The final synthesized image is sent to the display hardware for scanning and output.
The user sees the first frame! This marks the visual end of the cold start process.
Activity fully ready:
After the first frame is drawn and displayed, the activity may need to perform some additional asynchronous loading (such as loading data from the network or database to fill the list).
When all necessary initialization (including asynchronous tasks) is completed, the UI fully responds and can process user input without delay, the application reaches a fully interactive state.
1. Application. onCreate() optimization:
Avoid time-consuming operations (network requests, large amounts of IO, complex calculations).
Lazy loading/on-demand initialization: Only initialize components that are immediately needed.
Use backend threads to handle non UI critical initialization.
Check if the initialization of the third-party SDK is necessary and optimize its time consumption.
2. ContentProvider optimization:
Simplify the number of ContentProviders declared in the Manifest.
The onCreate () method of the provider must be lightweight. Avoid complex logic or IO.
Optimization of Activity. onCreate():
SetContentView(): Flatten the layout hierarchy, reduce nesting, and avoid complex or overly large layout files. Consider<include>,<merge>, and ViewStub.
Optimize findViewById (or use View Binding/Data Binding to reduce calls).
Avoid data loading on the main thread (using background threads and loading status UI).
Delay initialization of non essential views or data for the first screen.
4. Theme optimization (reducing white/black screens):
Use the windowBackground theme property to set the initial background (image or color) for launching the activity, making it consistent with the app design and eliminating the white/black screen flicker at startup.
Use Splash Screen API (Android 12+) to provide a smoother startup experience.
5. Asynchronous and Parallel:
Reasonably utilize thread pools, Asynchronous Tasks (used with caution, prone to leakage), IntentService/WorkManager, Kotlin coroutines, etc. for backend operations.
Pay attention to thread safety and synchronization.
6. Tool analysis:
Android Studio Profiler: CPU, Memory tracking, analysis of startup time at each stage.
Systrace/Perfetto: System level performance tracking, analyzing UI thread blocking, lock contention, rendering performance, and system resource usage. It is the gold standard for analyzing cold start performance.
Layout Inspector: Check the complexity of layout hierarchy.
Adb shell am start-W [package]/[activity]/Displayed Time: measures the time from the start command to the first frame being displayed.
ReportFullyDrawn(): Call this method when the application considers itself fully interactive to obtain a more accurate "fully ready" time.
Understanding the detailed process of cold start is the foundation for optimizing effective startup performance. Developers need to pay attention to every critical step on the core path from application initialization to the completion of the first frame drawing, identify bottlenecks, and perform targeted optimization.








