Mobile Development 21 min read

Understanding and Optimizing Android Activity Startup Performance

Android activity startup latency stems from three phases—Pause, Launch, and Render—so optimizing only onCreate often leaves perceived delays; developers can measure each phase via system logs or AOP hooks (Instrumentation, Looper‑Printer, or ActivityThread handler) to pinpoint and reduce bottlenecks.

Didi Tech
Didi Tech
Didi Tech
Understanding and Optimizing Android Activity Startup Performance

Activity startup speed is a common concern for Android developers. When the transition between pages takes too long, the app feels sluggish. The first instinct is to blame a slow onCreate method, but even after optimizing onCreate the perceived delay may remain. The real cause lies in the whole Activity launch process, which can be divided into three stages: Pause , Launch and Render .

1. Activity launch flow

The launch consists of three steps (using ActivityA → ActivityB as an example):

From ActivityA.startActivity to the moment ActivityA is successfully paused.

From ActivityB's initialization to the end of its onResume method.

From ActivityB registering its window with the WindowManagerService (WMS) to the completion of the first frame rendering.

The communication between the app process, ActivityManagerService (AMS) and WindowManagerService (WMS) is complex; the article lists the key method call chains without reproducing the entire source.

2. Pause flow

When ActivityA calls startActivity , the system first pauses the currently visible Activity. The call chain is:

ActivityA.startActivity -> Instrumentation.execStartActivity -> ActivityManagerNative.getDefault.startActivity -> ActivityManagerService.startActivityAsUser -> ActivityStarter.startActivityMayWait -> ActivityStarter.startActivityLocked -> ActivityStarter.startActivityUnchecked -> ActivityStackSupervisor.resumeFocusedStackTopActivityLocked -> ActivityStack.resumeTopActivityUncheckedLocked -> ActivityStack.resumeTopActivityInnerLocked -> ActivityStack.startPausingLocked -> ActivityThread$ApplicationThread.schedulePauseActivity -> ActivityThread.handlePauseActivity -> ActivityA.onPauseActivityManagerNative.getDefault().activityPaused

If a time‑consuming operation is performed inside onPause , it directly delays the AMS notification that the previous Activity has paused, which in turn blocks the subsequent launch.

3. Launch flow

After the pause, AMS proceeds with the launch. The relevant call chain includes:

ActivityManagerService.activityPaused -> ActivityStack.activityPausedLocked -> ActivityStack.completePauseLocked -> ActivityStackSupervisor.resumeFocusedStackTopActivityLocked -> ActivityStackSupervisor.startSpecificActivityLocked -> (new process creation if needed) -> ActivityThread$ApplicationThread.scheduleLaunchActivity -> Activity.handleLaunchActivity -> Activity.onCreate -> Activity.onRestoreInstanceState -> Activity.handleResumeActivity -> Activity.onStart -> Activity.onResume -> WindowManager.addView

The total time measured by the system (displayed in Logcat as Displayed …: +XXms ) corresponds to the Launch and Render stages. The system does not count the Pause time unless it exceeds the 500 ms timeout, after which AMS forces the pause to complete.

4. Render flow

When onResume finishes, the UI rendering begins. The rendering chain is:

WindowManager.addView -> WindowManagerImpl.addView -> ViewRootImpl.setView -> ViewRootImpl.requestLayout -> ViewRootImpl.scheduleTraversals -> Choreographer.postCallback -> ViewRootImpl.doTraversal -> ViewRootImpl.performTraversals -> ViewRootImpl.performMeasure -> ViewRootImpl.performLayout -> ViewRootImpl.performDraw

The first frame is drawn after ViewRootImpl.performDraw . Any heavy work in measure , layout or draw of child views will increase the Render time.

5. Timing collection methods

Two main approaches are described:

System statistics : Use Logcat with the ActivityManager tag to see the total launch time reported by AMS.

In‑app statistics : Implement AOP‑style hooks to measure the three stages individually.

6. In‑app measurement solutions

Three hook techniques are recommended:

Hook Instrumentation : Replace the system Instrumentation instance via reflection and override lifecycle callbacks (e.g., callActivityOnPause , callActivityOnResume ) to record timestamps.

Hook Looper‑Printer : Set a custom Printer on the main looper to log message dispatches and calculate the duration of lifecycle messages. This method does not work on Android P+ because the message codes changed.

Hook ActivityThread$H : Replace the Handler.Callback of the internal ActivityThread$H handler to intercept lifecycle messages, handling the new EXECUTE_TRANSACTION code on Android P and later.

All three methods allow developers to obtain the Pause, Launch and Render times without modifying each Activity manually.

7. Summary

Activity startup consists of Pause, Launch and Render stages.

System Logcat shows Launch + Render time; Pause is ignored unless it exceeds the 500 ms timeout.

Hook‑based AOP solutions (Instrumentation, Looper‑Printer, Handler) enable fine‑grained timing for each stage, though Looper‑Printer is not compatible with Android P+.

For further reading, the article lists several open‑source projects and blog posts related to Activity launch analysis and performance monitoring.

performanceInstrumentationAndroidLooperHookActivitystartup
Didi Tech
Written by

Didi Tech

Official Didi technology account

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.