The background,

Startup speed is the face of an APP and is critical to user experience. As the business continues to increase, more and more tasks need to be initialized. If left unchecked, the startup time will gradually increase, so snowball client has done a lot of optimization for the application startup time. Starting from the basic principle of application startup, this paper summarizes the ideas and problems of snowball client startup optimization. It mainly includes three aspects: introduction of startup principle, optimization scheme and online verification.

Two, the starting principle

According to Google’s official documentation, there are three types of app launches:

  • Cold start
  • Warm start
  • Wen started

Cold start

Cold start means that the APP process is killed (the system reclaims the APP or the user manually shuts down the APP). To start the APP, the system needs to create the APP process again, from the user clicks the icon on the APP desktop to the first page is loaded. Cold start is the most time-consuming startup type and the most critical optimization point of startup optimization. Let’s take a look at the startup process of cold start.

It can be seen from the figure above that the cold startup of APP can be divided into the following three processes:

  • The user clicks on the desktop APP icon, invokes launch.startActivity, and the Binder notifies the system_server process, ActivityManagerService is used internally by System_server to inform Zygote to create application subprocesses
  • After the application process is created, the ActivityThread is loaded and the ActivityThread.main method is called to instantiate ApplicationThread, Lopper, and Handler
  • The Attach method is called internally by ActivityThread to bind back to the system_server process. The Application execution ActivityManagerService. AttachApplication created, at the same time start the first Activity

We can put it in a simpler way:

Zygote is a process, system_server is like a service manager, and ActivityThread is like each APP process’s own manager.

Start the APP by notifying the service manager (System_server), which then contacts its first contact, zygote, asking zygote to create a home for the child, that is, the APP’s own process. After the process is created, the child’s own work is next. It starts to use its own butler ActivityThread to decorate its home. Application can be likened to the door, Activity can be likened to the bedroom, AMS is the decoration team. The ActivityThread will continue to interact with AMS until the Application and Activity are created, at which point an APP is started.

Warm start

A hot start is when an application is invoked from the background, and the application process is still alive. No child processes need to be created for the application to start, but the Activity lifecycle may be restarted. In a hot start, all the system does is bring your Activity to the foreground. As long as all of the application’s activities remain in memory, the application does not have to perform object initialization, layout, and drawing repeatedly, such as when the user presses the back or home key to return to the background.

Wen started

A warm start involves some of the actions that occur during a cold start and is more expensive than a hot start, such as restarting an application after the user exits the application. The application process still exists, but the application must recreate the Activity from scratch by calling onCreate()

Cold startup is the most time-consuming of the three startup states, and startup optimization is also optimized on the basis of cold startup. Hot startup and warm startup are relatively time-consuming, so optimization is not considered for the time being.

Third, attribution of problems

In order to optimize the startup time, you must first know what happens during the startup process and how it takes time. Here are some commonly used performance testing tools for apps:

adb shell

Adb command: adb shell am start -w [packageName]/[packageName. XActivity]

Detailed use reference documents: developer. The android. Google. Cn/studio/comm…

Parameter Description:

Activity: The first Activity that the application starts

TotalTime: Total Application startup time, including Application process creation, Application creation, first Activity creation, drawing, and display. For cold startup we only need to focus on TotalTime

Displayed

Displayed is relatively easy to use. We only need to filter the keyword displayed in Logcat to see the total startup time of the application. As shown in the figure below, displayed printing time is almost the same as adb shell, that is, the total time of a cold startup.

Adb shell and Displayed can be used to show how long an application has been started, but not to show how long a stack has been used. Systrace and Traceview can be used to show how long an application has been started.

Systrace

Systrace is an Android command-line tool that records device activity over a short period of time and stores it in a compressed text file. The tool generates a report that summarizes data from the Android kernel, such as CPU schedulers, disk activity, and application threads.

The Systrace tool is stored in the Android SDK by default. The path is Android/ SDK /platform-tools/ Systrace

Use Systrace to generate application cold start information

  • If there is no configuration environment variables, first cut to systrace directory CD ~ / Library/Android/SDK/platform – the tools/systrace
  • Perform systrace. Py 10 – o – t/Users/liuyakui/trace. The HTML – a com. Xueqiu. Fund

Or simply execute systrace using absolute paths

Detailed use reference documents: developer. The android. Google. Cn/topic/perfo…

python ~/Library/Android/sdk/platform-tools/systrace/systrace.py -t 10 -o /Users/liuyakui/trace.html -a com.xueqiu.fund
Copy the code

The Systrace report is shown below, which only captures the main information needed to start optimization:

  • Area 1 represents CPU usage. The higher the column, the more dense the column, the higher the CPU usage
  • Area 2 represents the CPU number. The device is an 8-core processor numbered from 0 to 7. Click the AREA of CPU number to view the currently running tasks
  • Area 3 represents the specific time consumption of all threads and methods, which can help us locate specific time consuming methods

As can be seen from the figure above, the average CPU utilization is low within 0-3 seconds, especially during the period of 1-3 seconds, the CPU is almost idle. Improving CPU utilization and giving full play to CPU performance is our main optimization direction.

The information provided in the three sections above basically helps us locate the startup time problem. It provides information about CPU usage and how each thread is working, but it does not tell us where the specific problem code is. To determine the specific problem code, we can use the Traceview tool.

Traceview

Traceview can graphically display the working status of threads, as well as the call stack and call chain of methods. We take Application onCreate() as an example to count detailed method calls inside onCreate() and generate trace reports.

Detailed use reference documents: developer. The android. Google. Cn/studio/initial…

@Override
public void onCreate(a) {
    super.onCreate();
    Debug.startMethodTracing("app_trace");

    // Initialize code...

    / /...

    Debug.stopMethodTracing();
}
Copy the code

Application startup is completed, will be in the/sdcard/Android/data/com xueqiu. The fund/files path generated a app_trace trace file, use AndroidStudio open can directly, as shown in the figure below:

The Trace file details how each thread works and how specific method calls are made within each thread. Here are the three most important areas of the Trace report:

  • Area 1 represents CPU usage. You can drag and drop to select a time period
  • Area 2 represents the working information of the current thread. The screenshot shows all method calls of the current main thread within 0-5s
  • Field 3 represents the method call stack within the current thread, as well as information such as method time. Top Down and Bottom Up can be used to sort methods backwards and forwards

The Trace report clearly shows the call chain and time consumption of all methods corresponding to each thread, which helps us locate specific problems in the startup process and provides an important reference for the optimization scheme.

Fourth, optimization plan

After the above analysis, APP startup problems are mainly concentrated in the following two stages:

  • Application to create
  • Splash page drawing

Therefore, the following is mainly optimized for these two aspects

Application creation optimization

As can be seen from the above Traceview report, the code that affects Application creation is mainly concentrated in initThirdLibs. Let’s take a look at the initialization code execution process in initThirdLibs.

InitThirdLibs contains all the initialization items of snowball client. These initialization tasks are executed in the main thread sequence regardless of priority or priority. Any task blocked in the middle will affect the creation of Application. The Application creation time also continues to accumulate.

Therefore, sorting out the priority of internal tasks of initThirdLibs, unified scheduling in a reasonable way, and delayed initialization of each task are important contents of optimization Application creation. The main objectives of delayed initialization are as follows:

  • Improve CPU utilization and give full play to CPU performance
  • Initializing Task processing reduces maintenance costs and improves Task scheduling flexibility
  • Multi-thread processing, sorting out the priority of each Task, forming a directed acyclic graph

Task The Task flow is as follows:

The core logic of the initiator is to define the thread pool, dynamically calculate the number of threads according to the CPU condition of the device, and ensure that all Task tasks are executed concurrently and independently from each other. After all tasks are executed, Final tasks will be executed to do some finishing work or tasks with strong dependence. It can also be implemented in Final Task. The following two implementations are recommended:

  • CountDownLatch
  • Custom thread pools

The initiator pseudocode is as follows:

// This is just a piece of pseudo-code to help you understand the basic implementation principle of the launcher

TaskManager manager = new TaskManager();
ExecutorService service = createThreadPool();
final Task1 task1 = new Task1(1);
final Task2 task2 = new Task2(2);
final Task3 task3 = new Task3(3);
final Task4 task4 = new Task4(4);
for (int i = 0; i < n; i++) {
    Runnable runnable = new Runnable() {
        @Override
        public void run(a) { manager.get(i).start(); }}; service.execute(runnable); }Copy the code

After Task scheduling is complete, initialization tasks that do not depend on the main thread are moved to concurrent tasks for delayed initialization. In this way, centralized management is implemented to avoid blocking the main thread and improve CPU utilization.

Optimization of flash page rendering

At present, the flash page mainly carries business advertisements. The layout structure of the page can be adjusted indirectly by optimizing the logic of advertising loading.

Layout structure

Splash screen pages will be preloaded advertisement data to a local, each application start the data read from the local advertising, here we have no advertising page display logic can be optimized, at present have no advertising at the splash screen page will still be loaded layout file, and set the default page for the length, in theory if the page without advertising, the splash screen can directly enter the page after page has been created, There is no need to load the layout file of the page to reduce the page drawing time. After the adjustment, the core code of the page advertising loading logic is as follows:

private void prepareSplashAd(a) {
    // Read AD data
    String jsonString = PublicSetting.getInstance().getSplashAd();
    if (TextUtils.isEmpty(jsonString)) {
        // No ads, close the page, enter the home page
        exitDelay();
        return;
    }

    // Load the layout file
    View parentView = inflateView();
    setContentView(parentView);
    // Display ads
    AD todayAd = ads.get(0);
    showSplashAd(todayAd.imgUrl, todayAd.linkUrl);
}
Copy the code

The optimization results

After online data sampling of multiple versions, the startup time decreases significantly. Taking Huawei Mate 30E Pro as an example, the effect comparison is as follows:

Before optimization

The optimized

As can be seen from the above comparison, on flagship models within 5 years, the startup time is reduced from the original 1.9s-2.5s to 0.75s-1.2s, an overall decrease of about 60%, which can achieve the effect of turning on in seconds! CPU activities become intensive, giving full play to CPU performance and improving CPU utilization.

Five, the summary

This paper first introduces the basic principle of Application startup, and how to locate the reasons affecting startup speed through various detection tools. Finally, it focuses on the optimization scheme of Application creation and flash page drawing. It also represents a set of best practices that can be used for subsequent performance optimizations.

In fact, there are many start-up optimization schemes, but in addition to focusing on the start-up optimization itself, we need to make long-term planning and design a suitable scheme for ourselves, paving the way for subsequent business iterations and avoiding the problem of gradual increase in start-up time again.