Measuring Android App Startup Times: Cold and Warm Launch Performance

Application resposne time is typically measured as the duration from when a user initiates an action to when the UI becomes fully interactive. For Android apps, this often focuses on cold start (app launched from scratch) and warm start (app relaunched after being backgrounded). Two broad approaches exist: hardware-based measurement using high-speed cameras and software-based measurement using logs and command-line tools.

Hardware Approach

With a high-speed camera, define the start frame (e.g., tap event) and the end frame (e.g., first visible content). The system automatically calculates the elapsed time between these frames.

Software Approach

The software approach can be manual or automated. One manual method involves monitoring logcat output. Clear the buffer with adb logcat -c, then filter events with adb logcat -v threadtime -b events and look for activity_launch_time entries which include both response and initialization time.

A more systematic method uses Python scripts to invoke adb shell am start -W -n. The output contains three key metrics:

  • ThisTime: Time taken by the target activity to start.
  • TotalTime: Total app startup time (ThisTime + app resource initialization).
  • WaitTime: System-wide startup time (TotalTime + system resource initialization).

For automated measurement, many testers parse ThisTime from the command output. The variation across runs can be visualized as a trend curve, and the average is compared against competitors (competitive analysis) or against previous versions (horizontal comparison).

Cold Start Measurement with Python

Cold start requires the app to be fully stopped before each launch. The following script forces the app to stop, launches it via am start, extracts ThisTime, and stores timestamped data into a CSV file.

import csv
import os
import time

class AppTester:
    def __init__(self):
        self.cmd_output = ""
        self.start_time = 0

    def launch_app(self):
        cmd = 'adb shell am start -W -n com.android.contacts/.activities.PeopleActivity'
        self.cmd_output = os.popen(cmd)

    def stop_app_cold(self):
        cmd = 'adb shell am force-stop com.android.contacts'
        os.popen(cmd)

    def get_launch_time(self):
        for line in self.cmd_output.readlines():
            if "ThisTime" in line:
                self.start_time = line.split(":")[1].strip()
                break
        return self.start_time

class TestController:
    def __init__(self, iteration_count):
        self.tester = AppTester()
        self.remaining = iteration_count
        self.records = [("timestamp", "launch_time_ms")]

    def single_run(self):
        self.tester.launch_app()
        time.sleep(5)
        elapsed = self.tester.get_launch_time()
        self.tester.stop_app_cold()
        time.sleep(3)
        current = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        self.records.append((current, elapsed))

    def run_all(self):
        while self.remaining > 0:
            self.single_run()
            self.remaining -= 1

    def save_to_csv(self):
        with open('cold_launch.csv', 'w', newline='') as f:
            writer = csv.writer(f)
            writer.writerows(self.records)

if __name__ == "__main__":
    controller = TestController(10)
    controller.run_all()
    controller.save_to_csv()

Warm Start Measurement with Python

Warm start simulates the user pressing the Home button and then relaunching the app. The app is sent to the background using the KEYCODE_HOME event (keycode 3), preserving its process in memory.

import csv
import os
import time

class AppTester:
    def __init__(self):
        self.cmd_output = ""
        self.start_time = 0

    def launch_app(self):
        cmd = 'adb shell am start -W -n com.android.contacts/.activities.PeopleActivity'
        self.cmd_output = os.popen(cmd)

    def stop_app_warm(self):
        cmd = 'adb shell input keyevent 3'
        os.popen(cmd)

    def get_launch_time(self):
        for line in self.cmd_output.readlines():
            if "ThisTime" in line:
                self.start_time = line.split(":")[1].strip()
                break
        return self.start_time

class TestController:
    def __init__(self, iteration_count):
        self.tester = AppTester()
        self.remaining = iteration_count
        self.records = [("timestamp", "launch_time_ms")]

    def single_run(self):
        self.tester.launch_app()
        time.sleep(5)
        elapsed = self.tester.get_launch_time()
        self.tester.stop_app_warm()
        time.sleep(3)
        current = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        self.records.append((current, elapsed))

    def run_all(self):
        while self.remaining > 0:
            self.single_run()
            self.remaining -= 1

    def save_to_csv(self):
        with open('warm_launch.csv', 'w', newline='') as f:
            writer = csv.writer(f)
            writer.writerows(self.records)

if __name__ == "__main__":
    controller = TestController(10)
    controller.run_all()
    controller.save_to_csv()

Data Analysis

After collecting several measurements (e.g., 10 runs), you can plot the data to observe variance and compute the average. Excluding the first sample (which may be an outlier due to system caching) is common. Use the resulting metrics for comparative benchmarks between app versions or competing products.

Tags: Android ADB python app-startup-time performance-testing

Posted on Wed, 26 Aug 2026 16:46:08 +0000 by romic