1. Overview of SystemUI
SystemUI is a system application, the apk path is located at /system/priv-app
source code path is located at: /framework/base/packages/SystemUI
is mainly responsible for functions:
- StatusBar: status bar
- NavigationBar: Navigation bar (back, home, recent tasks)
- Notification Panel: notification bar and quick setting panel
- wallpaper management
- screenshot function
- Recents: recent tasks (android9 uses recent tasks in launcher3, but SystemUI9 also retains related codes, which can be set in systemUi)
- Record screen function
- screenshot service
- VolumeBar: volume control
- Keyguard lock screen
- RingtonePlayer Ringtone player interface
- PipUI picture-in-picture interface
- RingtonePlayer Ringtone player interface
. . . . .
2. SystemUI startup
The general process of system startup:
uboot boot os startup > load kernel > init process, fork out zygote process > zygote starts SystemServer;
SystemServer is responsible for starting various core services of the system, initializing and loading some applications.
com.android.server.SystemServer.java:
main method:
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
run() method:
private void run() {
...
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices(); //引导服务
startCoreServices(); //核心服务
startOtherServices(); //其他
SystemServerInitThreadPool.shutdown();
}
...
}
The three start methods can be seen from the naming available to start the boot service, core service and other services respectively. startBootstrapServices():
private void startBootstrapServices() {
...
Installer installer = mSystemServiceManager.startService(Installer.class);
mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
mSystemServiceManager.startService(LightsService.class);
mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
...
}
You can see that AMS, PMS, LightsService and other services are enabled here.
The startup of SystemUI is located in startOtherServices():
private void startOtherServices() {
...
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
...
}
This method has a lot of code, only the key points are listed, and then look at the startSystemUi method:
static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
Create an Intent and start the SystemUIService service with the component name com.android.systemui.SystemUIService. At this point, I finally came to the SystemUI project.
3. Loading of SystemUI
com.android.systemui.SystemUIService.java
public class SystemUIService extends Service {
@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();
...
}
}
SystemUIService inherits Service, and onCreate calls the startServicesIfNeeded method of SystemUIApplication:
public class SystemUIApplication extends Application...{
public void startServicesIfNeeded() {
String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
startServicesIfNeeded(names);
}
}
The config_systemUIServiceComponents array contains the full class names of each functional module, as follows
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.Dependency</item>
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</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.stackdivider.Divider</item>
<item>com.android.systemui.SystemBars</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.pip.PipUI</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.fingerprint.FingerprintDialogImpl</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
</string-array>
You can see the corresponding functional modules mentioned in 1 above. Next is the real loading method,
startServicesIfNeeded(String[] services)
private void startServicesIfNeeded(String[] services) {
if (mServicesStarted) {
return;
}
mServices = new SystemUI[services.length];
......
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];
if (DEBUG) Log.d(TAG, "loading: " + clsName);
log.traceBegin("StartServices" + clsName);
long ti = System.currentTimeMillis();
Class cls;
try {
cls = Class.forName(clsName);
mServices[i] = (SystemUI) cls.newInstance();
} catch(ClassNotFoundException ex){
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
}
mServices[i].mContext = this;
mServices[i].mComponents = mComponents;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();
log.traceEnd();
// Warn if initialization of component takes too long
ti = System.currentTimeMillis() - ti;
if (ti > 1000) {
Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");
}
if (mBootCompleted) {
mServices[i].onBootCompleted();
}
}
......
}
First create a new SystemUI array (mServices), then traverse the incoming services array and assign the SystemUI object to the mServices array through reflection, and finally load each module through mServices[i].start(). Note that mServices[i].start here is not the usual startup service. Take NotificationChannels as an example:
NotificationChannels inherits SystemUI:
public abstract class SystemUI implements SysUiServiceProvider {
public Context mContext;
public Map<Class<?>, Object> mComponents;
public abstract void start();
....
}
public class NotificationChannels extends SystemUI{
@Override
public void start() {
createAll(mContext);
}
}
That is to say, each module inherits SystemUI, rewrites the start method, and mServices[i].start() calls the start method of each module to complete the loading.