Android boot speed optimization

Problem description

The startup time is too slow compared with the reference machine, about 15s slow. Android system 7.0.

problem analysis

Bootloader -- > kernel -- > zygote -- > PMS -- > AMS -- > launcher involves many levels
It can be analyzed with bootchart or directly through log analysis. Unfortunately, the bootchart cannot be captured by the project machine due to unknown reasons.
Fortunately, I found an artifact perfboot tool while browsing the source code. See system / core / init / perfboot py.
The command needs to be run in the source code compilation environment. Please refer to the source code file for details, which will not be introduced here.
Use command:
./perfboot.py --iterations=5 --interval=30 -v --output=/data/My_Doc/Performance/Bugs/bootup_op_4200151/J5D_UE.tsv
Obtain the startup data of the problem machine and the reference machine. Generate the following figure

 

The X-axis in the figure above is some important nodes during startup. Y axis is the start-up time.
Specify the meaning of each node representation on the X-axis.

|boot_progress_start | the system enters the user space, marking the completion of kernel startup. In this example, it can be seen that the kernel startup takes about 30s
|:---
|boot_progress_preload_start|Zygote start
|boot_progress_preload_end|Zygote end
|boot_progress_system_run|SystemServer ready to start Android system services, such as PMS, APMS, etc
|boot_progress_pms_start|PMS starts scanning installed applications
|boot_progress_pms_system_scan_start|PMS scans the installation package in the / system directory first
|boot_progress_pms_data_scan_start|PMS scan the installation package in the / data directory
|boot_ progress_ pms_ scan_ End | end of PMS scanning
|boot_progress_pms_ready|PMS ready
|boot_progress_ams_ready|AMS ready
|boot_progress_enable_screen|AMS starts to activate the screen after it is started. From then on, the screen can respond to the user's touch. Before WindowManagerService sends the time node to exit the startup animation, it will take a little time to actually exit the startup animation, which depends on desc.txt in the animation zip package. wm_boot_animation_done is the end time node perceived by the user
|sf_stop_bootanim|SF set service bootanim. The value of exit attribute is 1, which indicates that the system is about to end the startup animation. It can be used to track the time consumed at the end of the startup animation
|wm_boot_animation_done | the startup animation ends. In this step, the user can intuitively feel the end of startup
From the above figure, you can visually see that the problem machine is entering the boot_ progress_ Before the start node, it takes more time than the reference machine. Before that, it mainly involved bootloader and kernel.

bootloader optimization

I haven't touched this one. I'll give it to my colleagues at the bottom for optimization. About how to grab log s

adb shell cat /proc/bootmsg > bootmsg.txt.

From the log, the bottom colleagues found that there was a problem with the bootimg signature. After more detailed analysis, they really didn't understand this and couldn't summarize helpful opinions.

kernel layer optimization

For kernel optimization, check the config configuration first. There are many kinds of config configurations in the kernel. Even kernel engineers who have worked for several years may not be able to understand the role of each config value. Android provides a basic configuration table.
You can use scripts: kernel/scripts/kconfig/merge_config.sh to generate a config file. Specific usage Poke this
Compare the generated config file with the config file in the current project, and also compare the config file of the reference machine. A ready-made tool kernel/scripts/diffconfig can be used for comparison.
After comprehensive comparison, debug a little bit locally and find data. Finally, the following config is removed:

CONFIG_MTD_TESTS=m ----> m Change to n
CONFIG_SERIAL_MSM_HSL=y ----> y Change to n
CONFIG_SERIAL_MSM_HSL_CONSOLE=y ----> y Change to n
CONFIG_MMC_BLOCK_TEST=m ---->Comment out
CONFIG_MMC_TEST=m ---->Comment out
CONFIG_SERIAL_MSM_HSL=y ----> y Change to n
CONFIG_SERIAL_MSM_HSL_CONSOLE=y ----> y Change to n
CONFIG_MSM_SMD_DEBUG=y ---->Comment out
CONFIG_CGROUP_DEBUG=y ---->Comment out
CONFIG_RELAY=y ---->Comment out
CONFIG_RMNET_DATA_DEBUG_PKT=y ---->Comment out
CONFIG_DEBUG_GPIO=y ---->Comment out
CONFIG_CORESIGHT=y ---->Comment out
CONFIG_CORESIGHT_EVENT=y ---->Comment out
CONFIG_CORESIGHT_FUSE=y ---->Comment out
CONFIG_CORESIGHT_CTI=y ---->Comment out
CONFIG_CORESIGHT_TMC=y ---->Comment out
CONFIG_CORESIGHT_TPIU=y ---->Comment out
CONFIG_CORESIGHT_FUNNEL=y ---->Comment out
CONFIG_CORESIGHT_REPLICATOR=y ---->Comment out
CONFIG_CORESIGHT_STM=y ---->Comment out
CONFIG_CORESIGHT_HWEVENT=y ---->Comment out
CONFIG_DEBUG_MEMORY_INIT=y ---->Comment out
CONFIG_DYNAMIC_DEBUG=y ---->Comment out
//All the following are also noted out
CONFIG_SCHED_DEBUG
CONFIG_DEBUG_KMEMLEAK
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF
CONFIG_DEBUG_SPINLOCK
CONFIG_DEBUG_MUTEXES
CONFIG_DEBUG_ATOMIC_SLEEP
CONFIG_DEBUG_STACK_USAGE
CONFIG_DEBUG_LIST
CONFIG_FAULT_INJECTION_DEBUG_FS
CONFIG_LOCKUP_DETECTOR
CONFIG_DEBUG_PAGEALLOC
CONFIG_PAGE_POISONING
CONFIG_RMNET_DATA_DEBUG_PKT
CONFIG_MMC_PERF_PROFILING
CONFIG_DEBUG_BUS_VOTER
CONFIG_SLUB_DEBUG
CONFIG_DEBUG_BUGVERBOSE
CONFIG_ALLOC_BUFFERS_IN_4K_CHUNK
CONFIG_SERIAL_CORE
CONFIG_SERIAL_CORE_CONSOLE
CONFIG_SERIAL_MSM_HSL
CONFIG_SERIAL_MSM_HSL_CONSOLE
CONFIG_MSM_TZ_LOG
CONFIG_DYNAMIC_DEBUG 

Here, the configuration of config includes y,n,m, m, which means that it is compiled into a module and not into the kernel. If not configured, it is equivalent to n.
CONFIG_DEBUG_INFO cannot be removed, which will cause CTS. Since the values of config may be scattered in different kernel files, we can compile the kernel separately, and then check obj / kernel in the out directory_ OBJ/. Config file. The configuration items in this file are complete.

After the kernel turns off some debug switches. The retest results on the new version are as follows:


 

 

Here is how to view the kernel log,
After startup, use the command: ADB shell dmesg > dmesg Txt grab Log
Search the keyword "bootloader start count" -- > LK start in the log
"Bootloader end count" -- > LK end
"Kernel MPM timestamp" -- > bootloader running completed


Through the optimization of bootloader and kernel, the boot time of about 14s is directly reduced. It can be seen that the optimization effect is still obvious.

Framework layer optimization

Use the command: adb logcat -b events|grep boot to filter out the main events in the startup phase.

01-01 13:38:52.139   391   391 I boot_progress_start: 15452
01-01 13:38:53.329   391   391 I boot_progress_preload_start: 16641
01-01 13:38:56.675   391   391 I boot_progress_preload_end: 19989
01-01 13:38:57.020  1729  1729 I boot_progress_system_run: 20333
01-01 13:38:57.824  1729  1729 I boot_progress_pms_start: 21137
01-01 13:38:58.865  1729  1729 I boot_progress_pms_system_scan_start: 22179
01-01 13:39:08.852  1729  1729 I boot_progress_pms_data_scan_start: 32166
01-01 13:39:08.907  1729  1729 I boot_progress_pms_scan_end: 32221
01-01 13:39:10.109  1729  1729 I boot_progress_pms_ready: 33422
01-01 13:39:12.557  1729  1729 I boot_progress_ams_ready: 35871
01-01 13:39:15.189  1729  1782 I boot_progress_enable_screen: 38503
01-01 13:39:17.973   290   321 I sf_stop_bootanim: 41287
01-01 13:39:18.887  1729  1961 I wm_boot_animation_done: 42201

Combined with the comparison diagram, boot_ progress_ enable_ Before screen, the time consumption of each node of the problem machine is similar to that of the comparison machine. Here, the boot phase on Android m goes to boot_progress_enable_screen is over, and there is SF on Android N_ stop_ Bootanim and wm_boot_animation_done two events. This is the figure - the brownish red line to boot after optimizing the kernel_ progress_ enable_ Screen is not delayed because it represents a reference machine, which happens to be the Android M system.
As can be seen from the timestamp of the log:
boot_ progress_ enable_ Screen --- > it takes about 2s to reach SF_ stop_ Bootanim --- > take more than 1s to reach wm_boot_animation_done. The extra two processes take nearly 4s in total.
We should focus on what happened in this process and why it took nearly 4s more time.

1. Look at the boot first_ progress_ enable_ Where screen appears.
It is in frameworks / base / services / core / Java / COM / Android / server / AM / activitymanagerservice java

void enableScreenAfterBoot() {
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
            SystemClock.uptimeMillis());
    mWindowManager.enableScreenAfterBoot();

    synchronized (this) {
        updateEventDispatchingLocked();
    }
}

 

2.sf_ stop_ Where bootanim appears.
It's in frameworks / native / services / surfacelinker / surfaceflinger_ hwc1. cpp.
In particular, surface flinger_ hwc1. CPP is surfaceflinger CPP is an upgraded version. It supports HWC 2.0 and uses surfaceflinger CPP or SurfaceFlinger_hwc1.cpp is related to platform selection.

void SurfaceFlinger::bootFinished()
{
    ...
    // stop boot animation
    // formerly we would just kill the process, but we now ask it to exit so it
    // can choose where to stop the animation.
    property_set("service.bootanim.exit", "1");
    const int LOGTAG_SF_STOP_BOOTANIM = 60110;
    LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                   ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}

 

3.wm_ boot_ animation_ Where done appears.
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public void performEnableScreen() {
    ...
    // Don't enable the screen until all existing windows have been drawn.
    if (!mForceDisplayEnabled && checkWaitingForWindowsLocked()) {
        return;
    }
    if (!mBootAnimationStopped) {
        // Do this one time.
        Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
        try {
            IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
            if (surfaceFlinger != null) {
                //Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
                Parcel data = Parcel.obtain();
                data.writeInterfaceToken("android.ui.ISurfaceComposer");
                surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
                        data, null, 0);
                data.recycle();
            }
        } catch (RemoteException ex) {
            Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
        }
        mBootAnimationStopped = true;
    }
    if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
        if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete");
            return;
    }
    ...
    EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
    ...
}

 

After finding the location where the three nodes appear, let's analyze how to connect the three nodes in series.
1 -- > 2 process: the enablescreen afterboot of AMS calls the enablescreen afterboot method of WMS. The enablescreen afterboot in WMS will continue to call the internal method performEnableScreen, which internally judges that if the startup animation does not stop, it will call SurfaceFlinger to stop the startup animation

surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
                                data, null, 0);

First here_ CALL_ Transaction is actually a BOOT_FINISHED.
frameworks/native/include/gui/ISurfaceComposer.h

class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
public:
    enum {
        // Note: BOOT_FINISHED must remain this value, it is called from
        // Java by ActivityManagerService.
        BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,

surfaceFlinger. The call request from transact will be processed by ISurfaceComposer.
frameworks/native/libs/gui/ISurfaceComposer.cpp

status_t BnSurfaceComposer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    ...
    switch(code) {
        case BOOT_FINISHED: {
                CHECK_INTERFACE(ISurfaceComposer, data, reply);
                bootFinished();
                return NO_ERROR;
            }
    }
    ...
}

 

The bootFinished here is the surface flinger_ hwc1. The bootFinished() method defined by CPP finally comes to the second node sf_stop_bootanim.
In order to verify the above call process, we add the log of the print call stack to see the output.

void SurfaceFlinger::bootFinished()
{
    const nsecs_t now = systemTime();
    const nsecs_t duration = now - mBootTime;
    ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
    mBootFinished = true;
    android::CallStack stack;
    stack.update();
    stack.log("azhengye", ANDROID_LOG_DEBUG, " ");
    String8 strtemp = stack.toString("");
    ALOGD("Sunny\t%s", strtemp.string());
}
---------------------------------------------------------------------------------
04-28 12:41:15.978   308  2956 D azhengye:  #00 pc 0002b761  /system/lib/libsurfaceflinger.so
04-28 12:41:15.978   308  2956 D azhengye:  #01 pc 00045c9f  /system/lib/libgui.so
04-28 12:41:15.978   308  2956 D azhengye:  #02 pc 000310cf  /system/lib/libsurfaceflinger.so
04-28 12:41:15.978   308  2956 D azhengye:  #03 pc 000359b3  /system/lib/libbinder.so
04-28 12:41:15.979   308  2956 D azhengye:  #04 pc 0003d159  /system/lib/libbinder.so
04-28 12:41:15.979   308  2956 D azhengye:  #05 pc 0003cdb7  /system/lib/libbinder.so
04-28 12:41:15.979   308  2956 D azhengye:  #06 pc 0003d2bb  /system/lib/libbinder.so
04-28 12:41:15.979   308  2956 D azhengye:  #07 pc 0004f5f5  /system/lib/libbinder.so
04-28 12:41:15.979   308  2956 D azhengye:  #08 pc 0000e349  /system/lib/libutils.so
04-28 12:41:15.979   308  2956 D azhengye:  #09 pc 000473d3  /system/lib/libc.so
04-28 12:41:15.979   308  2956 D azhengye:  #10 pc 0001a0c9  /system/lib/libc.so
---------------------------------------------------------------------------------
SurfaceFlinger_hwc1.cpp:312   android::SurfaceFlinger::bootFinished()
ISurfaceComposer.cpp:371      android::BnSurfaceComposer::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
SurfaceFlinger_hwc1.cpp:3103  android::SurfaceFlinger::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
Binder.cpp:126                android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
IPCThreadState.cpp:1111       android::IPCThreadState::executeCommand(int)
IPCThreadState.cpp:445        android::IPCThreadState::getAndExecuteCommand()
IPCThreadState.cpp:513        android::IPCThreadState::joinThreadPool(bool)
ProcessState.cpp:63 (discriminator 1)android::PoolThread::threadLoop()
Threads.cpp:751               android::Thread::_threadLoop(void*)
pthread_create.cpp:198 (discriminator 1)__pthread_start(void*)
clone.cpp:41 (discriminator 1)__start_thread

 

The above log also confirms the previous analysis. So far, the process of 1 -- > 2 is passed. Looking at the 2 -- > 3 process, there is another judgment before the 3 nodes appear:

if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
                if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete");
                return;
}

Here, the system needs to check whether the boot animation is still playing,

private boolean checkBootAnimationCompleteLocked() {
    if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {
        mH.removeMessages(H.CHECK_IF_BOOT_ANIMATION_FINISHED);
        mH.sendEmptyMessageDelayed(H.CHECK_IF_BOOT_ANIMATION_FINISHED,
                BOOT_ANIMATION_POLL_INTERVAL);
        return false;
    }
    return true;
}

BOOT_ANIMATION_SERVICE is started when initializing SurfaceFlinger.
frameworks/native/services/surfaceflinger/SurfaceFlinger_hwc1.cpp

void SurfaceFlinger::init() {
    ...
    // start boot animation
    startBootAnim();
}

 

I came to BootAnimation. As analyzed earlier, set "service.bootanim.exit" to 1 in the bootFinished method of SurfaceFlinger. This setting is read in BootAnimation.
frameworks/base/cmds/bootanimation/BootAnimation.cpp

...
#define EXIT_PROP_NAME "service.bootanim.exit"
...
void BootAnimation::checkExit() {
    // Allow surface flinger to gracefully request shutdown
    char value[PROPERTY_VALUE_MAX];
    property_get(EXIT_PROP_NAME, value, "0");
    int exitnow = atoi(value);
    if (exitnow) {
        requestExit();
        if (mAudioPlayer != NULL) {
            mAudioPlayer->requestExit();
        }
    }
}

 

After tracking this 2 -- > 3, the process will be smooth. After sorting out the calling logic of the process, the problem also surfaced. It turned out that when a former colleague solved a black screen problem when he turned on the desktop, he artificially delay ed for a few seconds in checkExit

The following errors were also found when checking the log:

01-01 15:55:23.506  1865  1865 E BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /data/system/users/0/wallpaper_orig (No such file or directory)

 

The adb shell enters the mobile phone and finds that / data / system / users / 0 / wallpaper does not exist_ Orig file.
Is it because of the wallpper exception that it consumes too much time?
To clear debug, filter the log

adb logcat -b all|grep -E "Wallpaper may change|haveWall|sf_stop_bootanim|boot_progress_enable_screen"

The output is as follows:

01-02 12:13:03.814  1851  2082 V WindowManager: Wallpaper may change!  Adjusting
01-02 12:13:04.865  1851  2082 V WindowManager: Wallpaper may change!  Adjusting
01-02 12:13:06.986  1851  2006 I boot_progress_enable_screen: 40388
01-02 12:13:06.988  1851  2082 V WindowManager: Wallpaper may change!  Adjusting
01-02 12:13:07.052  1851  2006 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:07.056  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:07.184  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:08.049  1851  2082 V WindowManager: Wallpaper may change!  Adjusting
01-02 12:13:08.066  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:08.067  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:08.071  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:08.072  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:08.076  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=false wallEnabled=true haveKeyguard=true
01-02 12:13:09.894  1851  2082 V WindowManager: Wallpaper may change!  Adjusting
01-02 12:13:09.908  1851  3413 V WindowManager: Wallpaper may change!  Adjusting
01-02 12:13:10.178  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=true wallEnabled=true haveKeyguard=true
01-02 12:13:10.186   292  3736 I sf_stop_bootanim: 43587
01-02 12:13:10.191  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=true wallEnabled=true haveKeyguard=true
01-02 12:13:10.196  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=true wallEnabled=true haveKeyguard=true
01-02 12:13:10.397  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=true wallEnabled=true haveKeyguard=true

Then I'm doing an experiment to push a wallpaper_orig to the specified directory, although the error of BitmapFactory is missing. However, it is of little use to shorten the time.
It seems that this is not the exception and does not slow down the boot speed. But I noticed

01-02 12:13:10.178  1851  2082 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=true wallEnabled=true haveKeyguard=true
01-02 12:13:10.186   292  3736 I sf_stop_bootanim: 43587

 

Havewall = false before haveWall=true in this log. Havewall indicates that the system Window has successfully loaded the Wallpaper. Continuous output in log
WindowManager: Wallpaper may change! Adjusting
Why on earth does Wallpaper constantly adjust here? It seems that once the Wallpaper is adjusted, it will set haveWall to true.
The position of the following sentence log in the code is tracked:
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

private boolean checkWaitingForWindowsLocked() {
        //Omit irrelevant code

        if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
            Slog.i(TAG_WM, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
                    + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
                    + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
                    + " haveKeyguard=" + haveKeyguard);
        }

        // If we are turning on the screen to show the boot message,
        // don't do it until the boot message is actually displayed.
        if (!mSystemBooted && !haveBootMsg) {
            return true;
        }

        // If we are turning on the screen after the boot is completed
        // normally, don't do so until we have the application and
        // wallpaper.
        if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
                (wallpaperEnabled && !haveWallpaper))) {
            return true;
        }

        return false;
    }

This checkWaitingForWindowsLocked indicates whether the system needs to wait for Windows to be ready. Called by the performEnableScreen method in the WindowManagerService class

public void performEnableScreen() {
        // Don't enable the screen until all existing windows have been drawn.
        if (!mForceDisplayEnabled && checkWaitingForWindowsLocked()) {
            return;
        }
}

 

From the comments, performEnableScreen performs the action of activating the screen. However, before that, you need to wait for the system. The necessary windows have been drawn, that is, once my screen is activated, the drawn windows can be displayed immediately. Otherwise performEnableScreen will exit directly.
performEnableScreen is called by the enablesecreen afterboot method in the WindowManagerService class. The general calling process is as follows:
AMS prints boot_ progress_ enable_ Screen --- > call WMS's enablescreen afterboot --- > call WMS's performEnableScreen --- > call WMS's checkWaitingForWindowsLocked to check whether you can Enable Screen. Because the Wallpaper is not ready, checkWaitingForWindowsLocked returns true, resulting in performEnableScreen returning directly without performing the original Enable Screen action.

WindowManager: Wallpaper may change! Adjusting
It is printed in the code below.
frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java

// "Something has changed!  Let's make it correct now."
private void performSurfacePlacementInner(boolean recoveringMemory) {
        //Omit irrelevant code
        if (mWallpaperMayChange) {
            if (DEBUG_WALLPAPER_LIGHT)
                Slog.v(TAG, "Wallpaper may change!  Adjusting");
            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
                    defaultDisplay.pendingLayoutChanges);
        }
       //Omit irrelevant code
}

The debug call stack is as follows:

1-01 21:18:30.572  2912  2962 W System.err: java.lang.Exception: print stack
01-01 21:18:30.573  2912  2962 W System.err:    at com.android.server.wm.WindowManagerService.checkWaitingForWindowsLocked(WindowManagerService.java:5841)
01-01 21:18:30.574  2912  2962 W System.err:    at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:5905)
01-01 21:18:30.575  2912  2962 W System.err:    at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:8390)
01-01 21:18:30.576  2912  2962 W System.err:    at android.os.Handler.dispatchMessage(Handler.java:102)
01-01 21:18:30.577  2912  2962 W System.err:    at android.os.Looper.loop(Looper.java:154)
01-01 21:18:30.578  2912  2962 W System.err:    at android.os.HandlerThread.run(HandlerThread.java:61)
01-01 21:18:30.578  2912  2962 W System.err:    at com.android.server.ServiceThread.run(ServiceThread.java:46)

There are no redundant operations in this area, and the check is not continued.
After the above analysis, the code is modified, and finally the startup speed of the problem machine reaches the standard of the reference machine. The performance problem is a process of continuous mining and improvement. There must be some areas that can be optimized during startup.

debug technical description

Summarize some debug ging techniques collected when analyzing this problem.

  • Print stack slog. In java code d("azhengye", "Stack=="+new RuntimeException("azhengye debug"). fillInStackTrace());
    Or new exception ("print stack") printStackTrace(); Then search the log for "System.err:"

  • c++ debug: in order to view the function call stack in native, you can add the following code where necessary.
    #include <utils/CallStack.h>
    android::CallStack stack;
    stack.update();
    String8 strtemp = stack.toString("");
    ALOGD("\t%s", strtemp.string());
    The filtered log s need to be transferred to another line with arm linux Android addr2line. Fortunately, there are ready-made scripts to help us do this, which are posted here.

#!/usr/bin/python  
# stack symbol parser  
  
import os  
import string  
import sys  
  
ANDROID_TARGET_OUT = os.getcwd()+"/"  
  
# addr2line tool path and symbol path  
addr2line_tool = 'arm-linux-androideabi-addr2line'  
symbol_dir = ANDROID_TARGET_OUT + '/symbols'  
symbol_bin = symbol_dir + '/system/bin/'  
symbol_lib = symbol_dir + '/system/lib/'  
  
class ReadLog:  
    def __init__(self,filename):  
        self.logname = filename  
    def parse(self):  
        f = file(self.logname,'r')  
        lines = f.readlines()  
        if lines != []:  
            print 'read file ok'  
        else:  
            print 'read file failed'  
        result =[]  
        for line in lines:  
            if line.find('stack') != -1:  
                print 'stop search'  
                break  
            elif line.find('system') != -1:  
                #print 'find one item' + line  
                result.append(line)  
        return result  
  
class ParseContent:  
    def __init__(self,addr,lib):  
            self.address = addr # pc address  
            self.exename = lib  # executable or shared library  
    def addr2line(self):  
        cmd = addr2line_tool + " -C -f -s -e " + symbol_dir + self.exename + " " + self.address  
        #print cmd  
        stream = os.popen(cmd)  
        lines = stream.readlines();  
        list = map(string.strip,lines)  
        return list  
      
inputarg = sys.argv  
if len(inputarg) < 2:  
    print 'Please input panic log'  
    exit()  
  
filename = inputarg[1]  
readlog = ReadLog(filename)  
inputlist = readlog.parse()  
  
for item in inputlist:  
    itemsplit = item.split()  
    test = ParseContent(itemsplit[-2],itemsplit[-1])  
    list = test.addr2line()  
    print "%-30s%s" % (list[1],list[0])  

imge compiled in the source code

Execute the above script under the folder, and use the script to debug the bootFinished of SF. The following is an output example.

 

01-02 01:38:13.305   477  3072 D azhengye   :   #00 pc 000059b9  /system/bin/bootanimation
01-02 01:38:13.305   477  3072 D azhengye   :   #01 pc 00006515  /system/bin/bootanimation
01-02 01:38:13.305   477  3072 D azhengye   :   #02 pc 0000591f  /system/bin/bootanimation
01-02 01:38:13.305   477  3072 D azhengye   :   #03 pc 000054f1  /system/bin/bootanimation
01-02 01:38:13.305   477  3072 D azhengye   :   #04 pc 0000e349  /system/lib/libutils.so
01-02 01:38:13.305   477  3072 D azhengye   :   #05 pc 000473d3  /system/lib/libc.so
01-02 01:38:13.305   477  3072 D azhengye   :   #06 pc 0001a0c9  /system/lib/libc.so
------------------------------------------------------------------------------------
python panic.py /data/My_Doc/Performance/boot_c_log 
read file ok
BootAnimation.cpp:534         android::BootAnimation::checkExit()
BootAnimation.cpp:972         android::BootAnimation::playAnimation(android::BootAnimation::Animation const&)
BootAnimation.cpp:870         android::BootAnimation::movie()
BootAnimation.cpp:452         android::BootAnimation::threadLoop()
Threads.cpp:751               android::Thread::_threadLoop(void*)
pthread_create.cpp:198 (discriminator 1)__pthread_start(void*)
clone.cpp:41 (discriminator 1)__start_thread
  • Stack dump

    adb shell kill -3 <pid>

The output trace will be saved in / data/anr / traces Txt file. Note that if there is no / data/anr / directory or / data/anr / traces Txt this file needs to be created manually and set the read and write permissions. For stack printing of native thread, you may need to modify Dalvik / VM / thread The dumpNativeThread method of CPP.

  • debuggerd coredump this is the debug method found by analyzing the problem and checking the data. However, I have no practice and it is only for record reference.
    Debuggerd is a daemon process of android. It is responsible for dumping the runtime information of the process for analysis in case of abnormal errors. The coredump data generated by debuggerd is presented in text form and saved in the / data/tombstone / directory. It can print the native stack of the current process without interrupting the process execution. The method of use is:

debuggerd -b <pid>

This can help us analyze the process execution behavior, and can also be used to locate the code location of deadlock or dead loop caused by wrong logic in the native process.

summary

Each manufacturer will customize different boot behaviors, so there is no fixed method to fix all boot problems. However, through this paper, we summarize and analyze the routine of this kind of problems, that is, pay attention to each event event in the boot stage, first quantify where the boot is slow, and then go to targeted optimization.
The source code is really a treasure house. Read more.

Article reprint:

Android boot speed optimization (Part 3)

Keywords: Java Android webview

Added by lesliesathish on Fri, 17 Dec 2021 00:20:58 +0200