What am I good at? When I think of this problem, the mind is a blank: oh, I know everything, but say good at, really did not take the hand, this how line! Hence the SystemUI series of articles. Wet Xoong – ape

In the last “illustrated introduction :D” I made a brief introduction to the SystemUI in Android8.0, I feel very good, and is the mind map is screenshots, think it will be helpful to people who do not understand. But maybe it was too brief and was called cheap. Qaq, pooh!

This article will describe the startup and general initialization of SystemUI. I think it’s a little longer than the last one. Ha ha.

Same old, table of contents first, simple and clear.

An overview of the

Because of the need for real-time feedback on system status, such as Bluetooth switch, wifi switch, time, and corresponding user navigation bar actions, SystemUI is brought up from the start of the system. Tired! . Normal use of SystemUI, most of the functional modules are running, only a few functions, such as: screen capture function, you long press the power + volume button will click screen capture.

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

How does the init process work? When you press the power button, the system is powered on, and the Bootloader code solidified in ROM is loaded into RAM from its fixed address and executed. The Bootloader is responsible for pulling up the system OS. After the system OS is pulled up and some initialization and system setup is complete, the first thing to do is look for the “init” file in the system file and start the first process in our user space.

Emmm, anyway, back to the point. Following the initial system boot process, our SystemUI process is brought up during the SystemServer boot process.

As we know from the first introduction, SystemUI has many modules and corresponding interfaces. These modules have something in common. For example, they all need to:

  • Handles the initialization of the respective modules
  • Handle system state changes
  • To perform the dump
  • When the system is started, the corresponding logic needs to be processed

So reflected in the code: extract and abstract these common points, forming the SystemUI abstract class, the structure is as follows.

A brief explanation of this code:

  1. A start method is defined for subclasses to initialize. This method is abstract, so concrete subclasses must be implemented.
  2. OnConfigurationChanged is a callback that handles system state changes, such as time zone changes, font size changes, input mode changes, screen size changes, screen orientation changes, etc.
  3. Many modules in the system include the dump method. The dump method is used to dump the internal state of a module into the output stream. This method is mainly used as a debugging aid. Developers can use ADB shell to perform dump during development to understand the internal state of the system.
  4. OnBootCompleted is the callback method for system startup completion.

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

It is worth noting that in Oreo, two subclasses of the abstract SystemUI class, BaseStatusBar and PhoneStatusBar, were merged and replaced with Statusbar.java compared to Nougat. PhoneStatusBar this core class must be very familiar with, and now also dust to dust, dust to dust.

Second,SystemUI Startup process

SystemServer is responsible for starting important services in the system. Unfortunately, due to the importance of SystemUI, it is also started, albeit in the “Other” position. Bootstrap->Core->Other, SystemUI starts in Other).

In startOtherServices(), AMS is notified of its readiness by calling its systemReady() method. SystemReady () has a Runnable instance named goingCallback as an argument, So AMS will call back to the Runnable run() method when it has finished processing systemReady().

private void startOtherServices(a) {...// omit about 1000 lines
    mActivityManagerService.systemReady(() -> {
        Slog.i(TAG, "Making services ready"); . traceBeginAndSlog("StartSystemUI");
        try {
            startSystemUi(context, windowManagerF);
        } catch (Throwable e) {
            reportWtf("starting System UI", e); }... }}Copy the code

In the startSystemUi method, use the component name in the red box to start the SystemUIService service in SystemUI

For Android, when an Application is launched, the system ensures that its Application class is the first to be instantiated, and that its onCreate method precedes all activities in the Application. Creation of Service and BroadcastReceiver.

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, such as the Status Bar
  • One type of service is unique to each user

The following two arrays record these two sets of services

As mentioned earlier, SystemUI abstracts the commonality of functional modules into the abstract class Systemui.class. All of the types listed above are subclass implementations of SystemUI.

Next, in SystemUIApplication, the onCreate method is called: basically registering a broadcast receiver to receive the BOOT_COMPLETED broadcast, upon which the function onBootCompleted for each module is called.

Do you remember the code that starts SystemUI in SystemServer? That target is an Intent for SystemUIService.

When the SystemApplication home onCreate is finished, the SystemUIService is started. As a rule, the service onCreate method is called at startup.

This guy is just a transfer agent (giving someone a chance to boot you up). Look, the actual code is just one line below.

The whole service, the real work is only one sentence in the red box. If you look closely, the startServicesIfNeeded method in SystemUIApplication is called and comes back.

This is where the modules start.

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 property value, which AMS will set after the system boot is complete
            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 {
            The SystemUIFactory class was not available in 6.0, but was introduced in 7.0 to provide a customizable 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);
        }

        // Initialize each Service in the array
        mServices[i].mContext = this;
        mServices[i].mComponents = mComponents;
        if (DEBUG) Log.d(TAG, "running: " + mServices[i]); 
        mServices[i].start();

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

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

Here’s a separate further explanation of SystemBars initialization.

Three,e.g. SystemBars

SystemBars mainly contains NavigationBar and StatusBar. If you don’t know the corresponding position of these two bars, you can read the first chapter “Illustrated introduction :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(a) {    
        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(a) {        
        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 newRuntimeException(msg, t); }}Copy the code

This code is described as follows:

  1. The start method is called by SystemUIApplication
  2. Call createStatusBarFromConfig method, according to the information in the configuration file for the Status Bar of the initialization
  3. Read the class name of the implementation class in the configuration file. The value in the frameworks/base/packages/SystemUI/res/values/config. Defined in XML. In the mobile phone, its value is: com. Android. The systemui. The statusbar. Phone. The statusbar
  4. The corresponding class is loaded through the class loader
  5. Create object instances through the reflection API
  6. Finally, the instance’s start method is called to initialize it. For mobile devices, this is the statusbar.start method

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

The benefits are:

Here, the class name is configured in the resource file, so for different platforms like Tv and Car, the implementation of the status bar in the system can be replaced by modifying the configuration file without modifying any code, thus reducing the coupling between modules and reducing the maintenance cost of the system.

It is worth learning from.


SystemUI startup ends here. We will follow up on SystemBars and StatusBar.

Please follow the wechat official account: Ape Wet Xoong for the latest notice