Android 8.0 SystemUI (2): Startup process and initialization

The article has been updated to the WeChat public account: Yuan Shi Xoong

What am I good at?
When I think about this question, my mind is blank: Oh, I know everything, but I'm good at it, but I really can't do it, how can I do it!
So there are articles in the SystemUI series.
- Ape Wet Xoong

In the last article "Introduction with pictures and texts: D", I gave a brief introduction to SystemUI in Android 8.0. I feel very good, and it is a mind map and a screenshot. I think it will be helpful to those who don't understand. But it may be too brief, and was scolded as parallel imports. qaq, bah bah bah!

This article will describe the startup and general initialization of SystemUI. The length should be more than the previous one. Ha ha.

The old way, go to the catalog first, concise and clear.

Overview

Due to the need for real-time feedback of system status, such as bluetooth switch, wifi switch, time and corresponding user navigation bar operations, SystemUI is brought up as soon as the system is started (SystemUI: I don't want to! I'm tired!). During normal use of the SystemUI, most of the functional modules are in the running state, and only a few functions, such as the screenshot function, you can press the power + volume down button for a long time to take a screenshot.

Here is a brief description of the system startup process: by init process -> Zygote process -> SystemServer process.

How did the init process get up? When you press the power button, the system is powered on, and the Bootloader code solidified in the ROM is loaded from the fixed address into the RAM and executed. The Bootloader boot program is responsible for pulling up the system OS. When the system OS is pulled up and a series of initialization and system settings are completed, it will first look for the "init" file in the system file and start the first process in our user space.

Emmm, digress, back to the topic. According to the system startup process at the beginning, our SystemUI process is brought up during the startup process of SystemServer.

From the first introduction, we know that SystemUI has many modules and corresponds to the corresponding interface. These modules have something in common, for example they all need:

  • Handle the initialization of the respective modules
  • Handling system state changes
  • execute dump
  • When the system startup is completed, the corresponding logic needs to be processed

Therefore, it is reflected in the code as follows: these common points are extracted and abstracted to form the SystemUI abstract class with the following structure.

Briefly explain this code:

  1. A start method is defined for the subclass for the subclass to complete the initialization. This method is an abstract method, so the concrete subclass must implement it now.
  2. onConfigurationChanged is a callback for processing system state changes, where the state changes include: time zone changes, font size changes, input mode changes, screen size changes, screen orientation changes, etc.
  3. Many modules in the system contain the dump method. The dump method is used to dump the internal state of the module to the output stream. This method is mainly used to assist debugging. During the development process, developers can execute dump through adb shell to understand the internal state of the system.
  4. onBootCompleted is the callback method for system startup completion.

Except for the screenshot service, the mentioned modules all inherit the abstract class SystemUI and are initialized separately when the application starts. From this perspective, SystemUI applications are more like containers for these functional modules.

It is worth mentioning that, compared with Nougat, in Oreo, two subclasses of abstract class SystemUI: BaseStatusBar and PhoneStatusBar are merged and replaced by StatusBar.java. I believe that the old drivers who have contacted the SystemUI module must be familiar with the core class of PhoneStatusBar, and now it is dust and dirt.

2. SystemUI startup process

SystemServer is responsible for the startup of various important services in the system. Unfortunately, due to the importance of SystemUI, she is also started, although it is in the position of "Other"~ (SystemServer's code is roughly divided into three categories of system services. : Bootstrap->Core->Other, the startup of SystemUI is in Other).

In startOtherServices(), notify AMS that it is ready by calling the systemReady() method of AMS. systemReady() has a Runnable instance named goingCallback as a parameter. So, when AMS finishes processing systemReady(), it will call back the run() method of this Runnable.

private void startOtherServices() {
    ... //省略大概1000行
    mActivityManagerService.systemReady(() -> {
        Slog.i(TAG, "Making services ready");
        ...
        traceBeginAndSlog("StartSystemUI");
        try {
            startSystemUi(context, windowManagerF);
        } catch (Throwable e) {
            reportWtf("starting System UI", e);
        }
        ...
    }       
}

And in the startSystemUi method, the SystemUIService service in SystemUI is started through the component name in the red box

For the Android system, when an application starts, the system will ensure that its Application class is the first class to be instantiated, and the Application's onCreate method must precede the creation of all Activity, Service and BroadcastReceiver in the application.

In SystemUI, SystemUIApplication is the first class to be instantiated.

In it, two sets of services are defined:

  • One is the SystemUI service shared by all users, for example: Status Bar
  • One class is a service unique to each user

The following two arrays record these two sets of services

As mentioned earlier, SystemUI extracts the commonality of functional modules to form the abstract class SystemUI.class. All the types listed in the above figure are subclasses of SystemUI.

Next, in SystemUIApplication, the onCreate method is called: mainly register a broadcast receiver to receive the BOOT_COMPLETED broadcast, and after receiving the broadcast, call the function onBootCompleted of each module.

Do you remember the code to start SystemUI in SystemServer? That target is the Intent of SystemUIService.

When the onCreate of the SystemApplication home is executed, it will start the SystemUIService. As a rule, the onCreate method of this service is called at startup.

I don’t know if I don’t study it. Whoa, this guy is just a transit agent (give others a chance to start you)~ If you don’t believe me, look at it, the actual code is only the following line, see the picture below.

In the whole service, the real work is only a sentence in the red box. Looking carefully, the startServicesIfNeeded method in SystemUIApplication is called, and it comes back after a circle.

This is where the various modules are launched.

private void startServicesIfNeeded(Class<?>[] services) {
    if (mServicesStarted) {
        return;
    }

    if (!mBootCompleted) {
        // check to see if maybe it was already completed long before we began
        // see ActivityManagerService.finishBooting()
        if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
            // sys.boot_completed属性值,在系统boot完成后,AMS会对其进行设置
            mBootCompleted = true;
            if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
        }
    }

    Log.v(TAG, "Starting SystemUI services for user " + 
            Process.myUserHandle().getIdentifier() + ".");
    final int N = services.length;
    for (int i = 0; i < N; i++) {
        Class<?> cl = services[i];
        if (DEBUG) Log.d(TAG, "loading: " + cl);
        try {
            // SystemUIFactory类在6.0上还没有,是7.0上出现的,目的是为了提供可定制化的SystemUI
            Object newService = SystemUIFactory.getInstance().createInstance(cl);
            mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InstantiationException ex) {
            throw new RuntimeException(ex);
        }

        // 对数组中的每一个Service都进行初始化
        mServices[i].mContext = this;
        mServices[i].mComponents = mComponents;
        if (DEBUG) Log.d(TAG, "running: " + mServices[i]); 
        mServices[i].start();

        if (mBootCompleted) {
            mServices[i].onBootCompleted();
        }
    }
    ...
}

For the startup of SystemUI App, here is a summary of the startup sequence diagram for your reference, as shown below:

Further, it comes to the initialization logic of each module.

Here we further explain the initial SystemBars separately.

Three, eg SystemBars

SystemBars mainly includes NavigationBar and StatusBar. Students who do not know the corresponding positions of these two Bars can read the first "Introduction with pictures and texts: D".

Show the code:

public class SystemBars extends SystemUI {
    private static final String TAG = "SystemBars";    
    private static final boolean DEBUG = false;    
    private static final int WAIT_FOR_BARS_TO_DIE = 500; 

    // in-process fallback implementation, per the product config
    private SystemUI mStatusBar;    

    @Override
    public void start() {    
        if (DEBUG) Log.d(TAG, "start");        
        createStatusBarFromConfig();
    }    

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {        
        if (mStatusBar != null) {            
            mStatusBar.dump(fd, pw, args);
        }
    }    

    private void createStatusBarFromConfig() {        
        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
        final String clsName = mContext.getString(R.string.config_statusBarComponent);        
        if (clsName == null || clsName.length() == 0) {
            throw andLog("No status bar component configured", null);
        }        
        Class<?> cls = null;        
        try {         
            cls = mContext.getClassLoader().loadClass(clsName);
        } catch (Throwable t) {    
            throw andLog("Error loading status bar component: " + clsName, t);
        }   
        try {       
            mStatusBar = (SystemUI) cls.newInstance();
        } catch (Throwable t) { 
            throw andLog("Error creating status bar component: " + clsName, t);
        }        
        mStatusBar.mContext = mContext; 
        mStatusBar.mComponents = mComponents; 
        mStatusBar.start(); 
        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
    } 

    private RuntimeException andLog(String msg, Throwable t) {
        Log.w(TAG, msg, t);
        throw new RuntimeException(msg, t);
    }
}

This code is explained as follows:

  1. The start method is called by SystemUIApplication
  2. Call the createStatusBarFromConfig method to initialize the Status Bar according to the information in the configuration file
  3. Read the class name of the implementation class in the configuration file. This value is defined in frameworks/base/packages/SystemUI/res/values/config.xml . In phone, its value is: com.android.systemui.statusbar.phone.StatusBar
  4. Load the corresponding class through the class loader
  5. Create object instances via reflection API
  6. Finally, call the start method of the instance to initialize it. If it is a mobile device, here is the StatusBar.start method

Why read the resource file to get the class name and create an instance through reflection?

Benefits are:

Here, the class name is configured in the resource file, so for different platforms such as Tv and Car, you don't need to modify any code, just modify the configuration file to replace the implementation of the status bar in the system, thereby reducing the number of modules. Coupling also reduces the maintenance cost of the system.

It is worth learning from.


Well, the startup of SystemUI is over here. What the SystemBars and StatusBar have done will be followed up later.

Welcome to the WeChat public account: Yuan Shi Xoong to get the latest notice

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325856317&siteId=291194637