What is cold start

A cold start is an Activity start in which the application process responds from scratch to the intention to start the Activity. According to the App startup time document:

This type of startup presents the biggest challenge in minimizing startup time because systems and applications have more work to do than other startup states.

We recommend always optimizing on the assumption of a cold start. Doing so can also improve the performance of warm and hot starts.

To optimize cold start, we need to measure it, which means we need to monitor cold start times in production.

The traditional method

If the first Activity is created within a minute of the application starting, most applications and libraries will report a cold start. It looks something like this:

class MyApp : Application() {

  override fun onCreate() {
    super.onCreate()

    val appCreateMs = SystemClock.uptimeMillis()

    var firstActivityCreated = false

    registerActivityLifecycleCallbacks(object :
        ActivityLifecycleCallbacks {
      override fun onActivityCreated(
          activity: Activity,
          savedInstanceState: Bundle?
      ) {
        if (firstActivityCreated) {
          return
        }
        firstActivityCreated = true
        val activityCreateMs = SystemClock.uptimeMillis()
        if (activityCreateMs - appCreateMs < 60_000) {
          // TODO Report cold start
        }
      }
    })
  }
}
Copy the code

Unfortunately, this approach also includes situations where the application process starts responding to broadcast receivers, content provider queries, or starts services, and then sometimes starts the Activity within the first minute. We should exclude these conditions from cold-start monitoring to avoid distorting our results.

  • When the application process is started, it will call ActivityThread. The main (), it will be in the process of system_server ActivityManagerService. AttachApplication () to block the IPC calls.

  • Process of system_server ActivityThread. In the process of the application of bindApplication () IPC calls, the call will BIND_APPLICATION message in the thread the message queue.

  • Then, for each Activity, need to start the process of system_server ActivityThread. In the process of the application of scheduleTransaction IPC call (), Queue the EXECUTE_TRANSACTION message to the main thread message queue.

  • When the ActivityManagerService. AttachApplication (), after the completion of the IPC call ActivityThread. The main () and then call stars. The loop (), it will always be cycle, Processes messages published to its MessageQueue.

  • Processing BIND_APPLICATION is the first message, it calls the ActivityThread. HandleBindApplication (), the latter calls Application. The onCreate ().

  • Under a deal with news is EXECUTE_TRANSACTION, it calls the TransactionExecutor. The execute () to start the activity.

This means that in application.oncreate (), the main thread message queue already has an EXECUTE_TRANSACTION message enqueued. If we post a new message from application.onCreate (), it will be executed after EXECUTE_TRANSACTION, and therefore after the Activity is created. If we post a message and do not create the Activity at execution time, then we know that this is not a cold start, even if the Activity eventually starts 20 seconds later.

Here’s how we detect cold start:

class MyApp : Application() {

  override fun onCreate() {
    super.onCreate()

    var firstActivityCreated = false

    registerActivityLifecycleCallbacks(object :
        ActivityLifecycleCallbacks {

      override fun onActivityCreated(
          activity: Activity,
          savedInstanceState: Bundle?
      ) {
        if (firstActivityCreated) {
          return
        }
        firstActivityCreated = true
      }
    })
    Handler().post {
      if (firstActivityCreated) {
        // TODO Report cold start
      }
    }
  }
}
Copy the code

Wen started

According to the App startup time document:

There are many potential states that can be considered warm priming. Such as:

The user exits the application and then restarts it. The process may continue, but the application must recreate the Activity from scratch by calling onCreate().

The system kills the application from memory, and the user restarts it. Processes and activities need to be restarted, but tasks can benefit from the saved instance state package passed to onCreate().

Therefore, if an Activity is created using a saved instance state package, it should not be considered a cold start. However, since the process needs to be restarted, there is more to do than create the Activity. Let’s call it a warm start.

We can update our code to take this into account:

class MyApp : Application() { override fun onCreate() { super.onCreate() var firstActivityCreated = false var hasSavedState = false registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated( activity: Activity, savedInstanceState: Bundle? ) { if (firstActivityCreated) { return } firstActivityCreated = true hasSavedState = savedInstanceState ! = null } }) Handler().post { if (firstActivityCreated) { if (hasSavedState) { // TODO Report lukewarm start } else { // TODO Report cold start } } } } }Copy the code