The Secret of SystemUI

Path: frameworks/base/packages/SystemUI

In fact, SystemUI is an APP with the following main functions:

  • Status bar information display, such as battery, wifi/signal
  • Notification panel, such as system messages and third-party application messages
  • The recent taskbar display panel, such as long pressing the recent task shortcut key, displays recently used applications
  • Screenshot service
  • Wallpaper service….

The secret of immortality

<application  
android:name=".SystemUIApplication"  
android:persistent="true"  
android:allowClearUserData="false"  
android:backupAgent=".backup.BackupHelper"  
android:killAfterRestore="false"  
android:hardwareAccelerated="true"  
android:label="@string/app_label"  
android:icon="@drawable/icon"  
android:process="com.android.systemui"  
android:supportsRtl="true"  
android:theme="@style/Theme.SystemUI"  
android:defaultToDeviceProtectedStorage="true"  
android:directBootAware="true"  
tools:replace="android:appComponentFactory"  
android:appComponentFactory=".SystemUIAppComponentFactory">

android:persistent="true"It is guaranteed that after hanging up, it will be forcibly pulled up by the system.

Pay attention here, android:appComponentFactory=".SystemUIAppComponentFactory"which will be mentioned later.

SystemUI startup

  • SystemServer.java ->startOtherServices->startSystemUi(context, windowManagerF);

In fact, here we see that SystemUI is actually a service, because it is startService when it is started.

private static void startSystemUi(Context context, WindowManagerService windowManager) {
    PackageManagerInternal pm = LocalServices.*getService*(PackageManagerInternal.class);
    Intent intent = new Intent();
       //pm.getSystemUiServiceComponent() 
    intent.setComponent(pm.getSystemUiServiceComponent());
    intent.addFlags(Intent.*FLAG_DEBUG_TRIAGED_MISSING*);
    //Slog.d(TAG, "Starting service: " + intent);
    context.startServiceAsUser(intent, UserHandle.*SYSTEM*);
    windowManager.onSystemUiStarted();
}
@Override
public ComponentName getSystemUiServiceComponent() {
    return ComponentName.*unflattenFromString*(mContext.getResources().getString(
            com.android.internal.R.string.config_systemUIServiceComponent));
}

Path: frameworks/base/core/res/res/values/config.xml

  

<!-- SystemUi service component -->
    <string name="config_systemUIServiceComponent" translatable="false"
            >com.android.systemui/com.android.systemui.SystemUIService</string>

SystemUIService.java

onCreate(){
   //
   ((SystemUIApplication) getApplication()).startServicesIfNeeded();
...
  
   
  startServiceAsUser(
                new Intent(getApplicationContext(), SystemUIAuxiliaryDumpService.class),
                UserHandle.SYSTEM);
}

SystemUIApplication.java

  • implements SystemUIAppComponentFactory.ContextInitializer (note this interface)
 

public class SystemUIApplication extends Application implements
        SystemUIAppComponentFactory.ContextInitializer {
public void startServicesIfNeeded() {
  //
  //
        String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
        startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
    }


private void startServicesIfNeeded(String metricsPrefix, String[] services) {
   //
        if (mServicesStarted) {
            return;
        }
        mServices = new SystemUI[services.length];

        if (!mBootCompleteCache.isBootComplete()) {
            // check to see if maybe it was already completed long before we began
            // see ActivityManagerService.finishBooting()
            if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
                mBootCompleteCache.setBootComplete();
                if (DEBUG) {
                    Log.v(TAG, "BOOT_COMPLETED was already sent");
                }
            }
        }

        final DumpManager dumpManager = mSysUIComponent.createDumpManager();

   
     
        final int N = services.length;
        for (int i = 0; i < N; i++) {
            String clsName = services[i];
          
            log.traceBegin(metricsPrefix + clsName);
            long ti = System.currentTimeMillis();
            try {
              //
                SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
                if (obj == null) {
                  //
                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                    obj = (SystemUI) constructor.newInstance(this);
                }
                mServices[i] = obj;
            } catch (ClassNotFoundException
                    | NoSuchMethodException
                    | IllegalAccessException
                    | InstantiationException
                    | InvocationTargetException ex) {
                throw new RuntimeException(ex);
            }

            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
            mServices[i].start();//
           

            // Warn if initialization of component takes too long
            ti = System.currentTimeMillis() - ti;
            if (ti > 1000) {
                Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
            }
            if (mBootCompleteCache.isBootComplete()) {
                mServices[i].onBootCompleted();
            }

            dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
        }
        mSysUIComponent.getInitController().executePostInitTasks();
        log.traceEnd();
         //
        mServicesStarted = true;
    }}

Path: frameworks/base/packages/SystemUI/res/values/config.xml

 <!-- SystemUI Services: The classes of the stuff to start. -->
    <string-array name="config_systemUIServiceComponents" translatable="false">
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.statusbar.phone.StatusBar</item>
        <item>com.android.systemui.usb.StorageNotification</item>
        <item>com.android.systemui.power.PowerUI</item>
        <item>com.android.systemui.media.RingtonePlayer</item>
        <item>com.android.systemui.keyboard.KeyboardUI</item>
        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
        <item>@string/config_systemUIVendorServiceComponent</item>
        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
        <item>com.android.systemui.LatencyTester</item>
        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
        <item>com.android.systemui.ScreenDecorations</item>
        <item>com.android.systemui.biometrics.AuthController</item>
        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
        <item>com.android.systemui.theme.ThemeOverlayController</item>
        <item>com.android.systemui.accessibility.WindowMagnification</item>
        <item>com.android.systemui.accessibility.SystemActions</item>
        <item>com.android.systemui.toast.ToastUI</item>
        <item>com.android.systemui.wmshell.WMShell</item>
    </string-array>

Summary of the first step

How to start SystemUI.

When SystemServer starts, execute run, call startOtherServices(t); call startSystemUi (context, windowManagerF);

The SystemUIService service is started. In onCreate() of the service, it is checked whether it has been started to avoid multiple starts, and then the required system UI service is loaded.

Factory’s little secret (Construction of SystemUIFactory)

  • Basic process of APP startup.

The startup of an Android application begins with the Zygote process forking out a new child process. For every Android application, the starting point of its life cycle can be considered to be the method ActivityThreadof the class main(). The following is the simplified ActivityThread startup process:

  1. The system starts the application process :
    • When a user clicks on an icon or triggers the startup of an application component (such as Activity) through other methods, the system first finds the corresponding Package and process information.
    • If necessary, the system will fork a new process through the Zygote mechanism.
  2. Initialize ApplicationThread :
    • In the new process, ActivityThreadthe main()method is called, which is the actual entry point into the process.
    • main()An internal class ApplicationThreadinstance will be created in the method. This class inherits from IApplicationThreadthe interface and implements the AIDL interface required for Binder communication. It is a bridge for cross-process communication between ActivityThread and system services (mainly ActivityManagerService, referred to as AMS).
  3. Bind to AMS :
    • ActivityThread registers the created ApplicationThread object to AMS, so that AMS can send instructions to the process through the Binder mechanism, including starting, stopping or restarting the Activity.
  4. Create Application instance :
    • ActivityThread then loads and creates Applicationan instance of the application-defined class and calls its lifecycle methods.
  5. Start the first Activity :
    • When AMS decides to start an Activity, it will call the corresponding methods of ApplicationThread through the Binder mechanism, and these methods will eventually be called back in the main thread of ActivityThread.
    • After ActivityThread receives the message to start the Activity, it will go through a series of steps, such as preparing Context, Instrumentation, Intent, etc., and then call performLaunchActivity()methods to create and start the target Activity.

In summary, ActivityThread is not started directly by developers, but is automatically started by the Android system when a new application process is created, and runs as the main thread of the process, responsible for managing the life cycle and system services of the entire application component. interaction between.

 Process.java -->start()
                -->startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                    packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
                    pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
                    bindMountAppStorageDirs, zygoteArgs);
                    ActivityThread的main()。
   
  • Application creation and AppComponentFactory
 
 performLaunchActivity()-->
 Application app = r.packageInfo.makeApplication(false, mInstrumentation);
   -->  app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);



// 
 public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }

 private AppComponentFactory getFactory(String pkg) {
        if (pkg == null) {
            Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
            return AppComponentFactory.DEFAULT;
        }
   //factory
        if (mThread == null) {
            Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
                    + " disabling AppComponentFactory", new Throwable());
            return AppComponentFactory.DEFAULT;
        }
        LoadedApk apk = mThread.peekPackageInfo(pkg, true);
        // This is in the case of starting up "android".
        if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
        return apk.getAppFactory();
    }

SystemUIAppComponentFactory.java

  • There is a point here app instanceof ContextInitializer. If you are this interface, then the following method is called back.createFromConfig() Depending on the current startup, it may be one of the following
    • com.android.systemui.SystemUIFactory
    • com.android.systemui.tv.TvSystemUIFactory
    • com.android.systemui.CarSystemUIFactory
   @NonNull
    @Override
    public Application instantiateApplicationCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Application app = super.instantiateApplicationCompat(cl, className);
        if (app instanceof ContextInitializer) {
            ((ContextInitializer) app).setContextAvailableCallback(
                    context -> {
                      //
                        SystemUIFactory.createFromConfig(context);
                         //
 com.android.systemui.SystemUIFactory / com.android.systemui.tv.TvSystemUIFactory/ com.android.systemui.CarSystemUIFactory
                        
                        SystemUIFactory.getInstance().getSysUIComponent().inject(
                                SystemUIAppComponentFactory.this);
                    }
            );
        }

        return app;
    }

Return to SystemUIApplication again

public void onCreate() {
        super.onCreate();
        
        //
        mRootComponent = SystemUIFactory.getInstance().getRootComponent();
        mSysUIComponent = SystemUIFactory.getInstance().getSysUIComponent();
        mComponentHelper = mSysUIComponent.getContextComponentHelper();
        mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
        
        }

final summary

When SystemServer starts, execute the run method, call startOtherServices(t); call startSystemUi (context, windowManagerF);

When SystemUIApplication was created, SystemUIAppComponentFactory was used to build SystemUIFactory using dagger2.

After starting the SystemUIService service, in onCreate() of the service, check whether it has been started to avoid multiple starts, and then load the required system UI style.

Leave a Reply

Your email address will not be published. Required fields are marked *