StatusBar, VolumeBar, NavigationBar, DropList, StatusBar, DropList, etc. So you need to understand the SystemUI startup process, to understand how StatusBar, DropList view is loaded in the system interface, the following is from the SystemUI startup entry, SystemUI loading mechanism and to StatusBar as an example to analyze the whole process. The following is a sequence diagram of SystemUI startup:
The SystemUI startup portal
SystemUI is loaded when the Android system boots, so we can know that the SystemUI entry is probably in the system boot process. Through the investigation, found in the SyetemServer process start system services, such as AMS, PMS, Bluetooth, window management services, including SystemUI, then look at the code is how to achieve.
/frameworks/base/services/java/com/android/server/SystemServer.java
public final class SystemServer { ... /** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); }... private voidrun() {... // Initialize native services. System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
SystemServerInitThreadPool.get();
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System"."* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
Slog.e("System"."************ Failure starting system services", ex); throw ex; } finally { traceEnd(); }... }Copy the code
Zygote: Zygote: zygote: zygote: Zygote: Zygote: Zygote In the SystemServer Main function, run() is called, so the run method is followed (the above code is omitted, only the Main thread is kept), and the native services and system context are initialized first. A SystemServiceManager object is then created to start and manage subsequent system services. StartBootstrapServices (), startCoreServices(), startOtherServices() Start the boot service, start the central service, and start other services. These three methods are portals to open different system services, so enter the three methods 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)); . }Copy the code
In startBootstrapServices () method, which can be found mSystemServiceManager. StartServic () as the core, methods to different service as a parameter, in order to realize the opening of different services, including the AMS, PMS, LightsService and other systems required some small key services;
- startCoreServices()
/**
* Starts some essential services that are not tangled up in the bootstrap process.
*/
private void startCoreServices() {
traceBeginAndSlog("StartBatteryService");
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
traceEnd();
// Tracks application usage stats.
traceBeginAndSlog("StartUsageService");
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
traceEnd();
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
traceBeginAndSlog("StartWebViewUpdateService"); mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class); traceEnd(); }... }Copy the code
. Similarly, in the code to mSystemServiceManager startService () to open services, but the inside of the parameters is different, don’t do a detailed discussion, continue to look at the third method;
- startOtherServices()
private void startOtherServices() {... traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e); }}Copy the code
In the third startOtherServices() method, the main core is the startSystemUi() method, which passes the systemContext and WindowManagerService parameters. That is, we have found the systemUI startup portal, so proceed to the startSystemUi() method.
- startSystemUi()
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();
}
Copy the code
In the above code, you can see that an Intent is created, and then the component name is set to start SystemUIService. At this point, SystemUI only finds the start entry.
SystemUI starts loading
The first part finds the SystemUIService boot, so enter the SystemUIService class first. As shown below: / frameworks/base/packages/SystemUI/SRC/com/android/SystemUI/SystemUIService. Java
public class SystemUIService extends Service {
@Override
public void onCreate() { super.onCreate(); ((SystemUIApplication) getApplication()).startServicesIfNeeded(); . }}Copy the code
After getting the SystemUIApplication in onCreate() and calling its startServicesIfNeeded() method, we then go to the SystemUIApplication class, Find the startServicesIfNeeded method in the SystemUIApplication class as follows.
- startServicesIfNeeded()
public class SystemUIApplication extends Application implements SysUiServiceProvider {
...
public void startServicesIfNeeded() { String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents); startServicesIfNeeded(names); }... }Copy the code
The startServicesIfNeeded() method creates an array containing the names of services and calls the startServicesIfNeeded(String[] services) method with the array as an argument. Here don’t see the internal structure, this method first let’s look at the array gain what are the services, according to the code for the id of state Richard armitage rray. Config_systemUIServiceComponents we found in the XML config., XML this file, Found some data, which are as follows: / frameworks/base/packages/SystemUI/res/values/config. The XML
<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>
Copy the code
In the above items, you can find some of our familiar classes, such as VolumeUI, SystemBars, PowerUI, KeyboardUI, etc., that is, our mobile phone interface often see the system volume, lock screen, status bar, etc., and these UI is the construction part of SystemUI.
These widgets are gathered together in the startServicesIfNeeded() method, then startServicesIfNeeded(String[] services) is called, Then we can guess if the next step is to start loading these widgets separately and placing them in their respective locations.
- StartServicesIfNeeded (String [] services);
private void startServicesIfNeeded(String[] services) { private SystemUI[] mServices; . mServices = new SystemUI[services.length]; . final int N = services.length;for (int i = 0; i < N; i++) {
String clsName = services[i];
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(); . }}Copy the code
First we create an array of SystemUI widgets to load. Then we iterate through the “Services” array in startServicesIfNeeded() to reflect the various SystemUI objects. Finally, call their start() methods, respectively. For example, the start() method of VolumeUI is called at the end of the loop after the sixth fetch of the object.
At this point, as we guessed above, SystemUI starts loading uIs in different locations, and how each UI is loaded internally, and how views are placed in different locations, let’s move on.
Loading and customization of StatusBar
Since SystemUI contains many parts, here is an example of loading the StatusBar StatusBar. The above traversal got the SystemBar object and started calling its start(), so we went into the SystemBar class and looked at its start().
/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemBars.java
public class SystemBars extends SystemUI {
...
@Override
public void start() {
if (DEBUG) Log.d(TAG, "start"); createStatusBarFromConfig(); }... private voidcreateStatusBarFromConfig() { final String clsName = mContext.getString(R.string.config_statusBarComponent); 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()); }}Copy the code
The start method is called createStatusBarFromConfig (), and then into the createStatusBarFromConfig, here, the first feeling a little familiar with the code, StartServicesIfNeeded (String[] services) ¶ The same by id lookup to config. The first name in the XML file, as follows: / frameworks/base/packages/SystemUI/res/values/config. XML
<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
Copy the code
You can see from the string name that StatusBar is started last, which is the start() method that calls StatusBar.
public class StatusBar extends SystemUI{
@Override
public void start() {... CreateAndAddWindows (); . } public voidcreateAndAddWindows() {addStatusBarWindow(); }... private voidaddStatusBarWindow() {makeStatusBarView(); mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); . / / step 5 mStatusBarWindowManager. Add (mStatusBarWindow, getStatusBarHeight ()); }... protected voidmakeStatusBarView() { final Context context = mContext; . // Step 4 inflateStatusBarWindow(context); }... // Load Layout, Initialize StatusBarWindow protected void inflateStatusBarWindow(Context Context) {mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar, null); }}Copy the code
A lot of code is omitted from the StatusBar class, leaving the main process of loading StatusBar intact, calling createAndAddWindows() from the Start() method followed by addStatusBarWindow(), The StatusBarWindow is then initialized as a inflate loading layout in the makeStatusBarView() method, loading the style designed in super_status_bar.xml into the StatusBar interface.
In other words, when we need to customize SystemUI, we can customize a layout.xml and replace the source file here. Step 5 is after initializing StatusBarWindow, loading the statusBarView into the system interface through the add() method of StatusBarWindowManager, and setting the height of the statusBar. So let’s go to the add() method of the StatusBarWindowManager class, as follows:
public class StatusBarWindowManager{
...
/**
* Adds the status bar view to the window manager.
*
* @param statusBarView The view to add.
* @param barHeight The height of the status bar in collapsed state.
*/
public void add(View statusBarView, int barHeight) {
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
barHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; mStatusBarView = statusBarView; mBarHeight = barHeight; mWindowManager.addView(mStatusBarView, mLp); mLpChanged = new WindowManager.LayoutParams(); mLpChanged.copyFrom(mLp); }}Copy the code
Can find StatusBar loading is really WindowManager processing, first set up WindowManager. LayoutParams wide, high level TYPE, parameters such as Flag, Then take the LayoutParams and the mStatusBarView passed in as arguments and call addView() to load the View into the appropriate location. So let’s think about it the other way around. What would happen if we changed mStatusBarView to our custom View?
/ / StatusBar/VolumeBar/NavigationBar/VolumeBar/VolumeBar/VolumeBar/VolumeBar/VolumeBar/VolumeBar/VolumeBar/VolumeBar After sorting out the above code, go back to the beginning of the article to see the sequence diagram, you can clearly know the SystemUI startup process, on this basis, the task of SystemUI customization also becomes clear.
References:
Android startup process (3) Analyze the startup process of the SyetemServer process