How to measure android app start-up time?
Tags: android, performance, gradle, benchmark
Published: 2023-03-18 21:28:03

Did you try to test how much time takes the loading of your app? If not this article can be a guide for the first step. Probably you have already checked the Android Vitals metric "Loading" in Google Play or Firebase performance metrics. However, I think you want to know the results before the release.

The goal is to check the difference in start-up time between releases. The most useful can be a percentage of the changes in start-up time and not a value because users have different devices and on each device, the value will be different, but the percent changes can be right for most cases.

Imagine the next case, if you add a new library to your project, how can you check that this new library will not make your app slower? I hope after reading this article you will have an instrument for that.

From my point of view, it is a vital metric for each release, but it is not so easy to measure it in the right way.

Let's try to create rules that we will follow during measuring this metric.
- network shouldn't have an impact
- content shouldn't have an impact
- we need to measure from "start" until the first frame became visible to the user - TTID.

> [TTID](https://developer.android.com/topic/performance/vitals/launch-time#time-initial) - metric measures the time it takes for an application to produce its first frame, including process initialization (if a cold start), activity creation (if cold/warm), and displaying first frame.

Not a lot of rules. We can just avoid calling any network request or long operation in the Application.onCreate and in the first activity onCreate method. (Probably you know this, it is not only about measuring, but it is also a mandatory rule for android app development)

However, there are at least a few things that can have an impact on measurement:
- device CPU current frequency
- device Memory speed
- CPU loading

Let's start with variants that we can use for measurement and then find out how we can improve our results.

#### ActivityManager and LogCat

First, we have log cat, there we can find logs from ActivityManager about how much time has been taken to start an activity:

```
03-19 13:05:20.146   523   550 I ActivityTaskManager: Displayed com.example/.MainActivity: +343ms
03-19 13:05:23.920   523   550 I ActivityTaskManager: Displayed com.example/.SplashActivity: +1s845ms
03-19 13:05:25.728   523   550 I ActivityTaskManager: Displayed com.example/.ui.SignupActivity: +381ms
```

There are logs for each activity, we need to filter logs that are related only to the first app activity. Then we can launch the app a few times and calculate the average time.

For using this method we don't need anything special, only execute ADB command and check LogCat logs:

Clear LogCat logs:

`adb logcat -c`

Launch the app:

`adb shell am start-activity -n com.example/.SplashActivity`

Then you will see logs in the LogCat as was shown above. More details about this variant you can find in the [documentation](https://developer.android.com/topic/performance/vitals/launch-time#retrieve-TTID)

You can check my full bash script and example on [Github](https://github.com/devapro/app_start_up_time) 


#### Android benchmark plugin

Benchmark plugin gives us the ability to measure app start time in a more convenient way, after launch, we can see a few types of results in the command line:

```
Starting: Intent { cmp=com.example.MainActivity }
Status: ok
LaunchState: COLD
Activity: com.example.MainActivity
TotalTime: 2303
WaitTime: 2305
Complete
```

But in this case, you need to add a plugin to your project.
app/build.gradle.kts

```
plugins {
   ....
    id 'androidx.benchmark'
}
```

/build.gradle.kts

```
buildscript {
    ....

    dependencies {
        classpath("androidx.benchmark:benchmark-gradle-plugin:1.1.1")
    }
}
```

Then you can run the command:

`adb shell am start-activity -W -n com.example/.MainActivity`

Ok, now we found two ways how to get the time that our app spent to start. Now we can discuss how to make our results more precession. All suggestion bellow is applicable to both types of measurement.

1. Cold start and clear app data

`adb shell pm clear com.example` Run this command every time before measurement.

2. Run the measurement a few times and calculate the average value.

3. Run the measurement on the same device/emulator and within a short time. I mean that results are relevant only for measurements that were done in the short time period because you can't provide a guarantee that after some time the condition on the device/emulator will be the same.

4. Lock clocks (on rooted devices/emulator), more details in the [documentation](https://developer.android.com/topic/performance/benchmarking/benchmarking-in-ci#clock-locking) 

5. Run the measurement on the device. In most cases, you will see the right results even on the emulator if you use the same emulator on the same laptop for measuring the difference between two APK files. However, some optimization works only on a real device, for example [adding a baseline file](https://developer.android.com/topic/performance/baselineprofiles/overview) shows results only when running measurements on the real device.

We completed the first step of measuring. Now we have the ability to compare different apk (for example different releases). As the next step we can run measuring N times and then calculate the average result in this way results will be more stable for each version of APK.

I created a few examples of bash scripts on my [Github](https://github.com/devapro/app_start_up_time)

If you have questions, please ask in the comments.