一、SystemUI 介绍

1、初步认识SystemUI
Android 的 SystemUI 其实就是 Android 的系统界面,它包括了界面上方的状态栏 status bar,下方的导航栏Navigation Bar,锁屏界面 Keyguard ,电源界面 PowerUI,近期任务界面 Recent Task 等等。对于用户而言,SystemUI 的改动是最能直观感受到的。因此,每个 Android 版本在 SystemUI 上都有比较大的改动。而对开发者而言,理解 Android SystemUI 对优化Android系统界面,改善用户体验十分重要。

2、SystemUI 在哪
在 Andorid 系统源码中,package/apps下放的是系统内置的一些 app,例如 settings,camera,Phone,Message 等等。而在 framework/base/package 下,它们也是系统的 app,SystemUI 就在此目录下。它控制着整个Android系统的界面,但其实他也是一个 app,不同于一般的 app,它不可卸载也不可以被第三方应用替换。因为SystemUI 是系统应用,所以它也是一个 APK,有入口 Application,只不过它是由 SystemServer 进程进行启动的。

3、SystemUI 整体结构

android so 源码环境编译 android systemui源码分析_Android


这是 SystemUI 相关类的继承关系图,可以看到 SystemUI 为基类,每个子类实现了不同的系统界面。Status Bar 系统上方的状态栏

Navigator Bar 系统下方的导航栏

Keyguard 锁屏界面

PowerUI 电源界面

Recents Screen 近期任务界面

VolumeUI 音量调节对话框

Stack Divider 分屏功能调节器

PipUI 画中画界面

Screenshot 截屏界面

RingtonePlayer 铃声播放器界面

Settings Activity 系统设置中用到的一些界面,例如:NetworkOverLimitActivity,UsbDebuggingActivity等。

android so 源码环境编译 android systemui源码分析_android so 源码环境编译_02

二、系统启动后在SystemServer进程中启动SystemUIService

1、SystemServer进程里面有个main()方法,main 方法如下:

framework/base/service/java/com/android/server/SystemServer.java

public static void main(String[] args) {
        new SystemServer().run();
    }

2、main 方法里启动了 run() 方法,而在 run 方法中调用了startOtherServices() 方法:

private void run() {
    	...
    	// 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();
        }
    	...
    }

3、在 startOtherServices() 里 mActivityManagerService.systemReady 创建线程去执行startSystemUi(context),这里将启动SystemUI。具体方法如下:

private void startOtherServices() {
            mActivityManagerService.systemReady(() -> {
          		...
	          	try {
	                startSystemUi(context, windowManagerF);
	            } catch (Throwable e) {
	                reportWtf("starting System UI", e);
	            }
          		...  
          }
    }
    //启动SystemUI
    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();
    }

三、在 SystemUIService 中启动 SystemUI 所需的各种组件

1、然后我们进入设置启动 systemui 程序的 SystemUIService 文件里,该类的onCreate() 方法如下:

framework/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java.

public class SystemUIService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
    }
  }

2、((SystemUIApplication) getApplication()).startServicesIfNeeded()这句很关键,该方法如下:

framework/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

public void startServicesIfNeeded() {
        String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
        startServicesIfNeeded(names);
    }

3、SystemUI要启动的所有组件都是在数组 config_systemUIServiceComponents中定义的,可以看下这个数组的定义:

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.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>

4、继续看SystemUIApplication的startServicesIfNeeded(String[] services)方法,其中有一个 for 循环,循环里第一句就是将 service[i] 赋值给 clsName, 而service[i]的赋值就是各个SystemUI组件的具体类对象路径,这里通过反射的方法,创建出来对应的SystemUI组件实例对象:

private void startServicesIfNeeded(String[] services) {
 		...
        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;
            ...
            mServices[i].start();
   			...
            ti = System.currentTimeMillis() - ti;
			...
            if (mBootCompleted) {
                mServices[i].onBootCompleted();
            }
        }
		...
        mServicesStarted = true;
    }

看到这里我们应该就明白了,这里是拿到每个和 SystemUI 组件相关的类的完整路径,存到了service[] 里,然后赋值给cls,紧接着通过反射将其转化为具体的类对象,存到了mService[i]数组里,最后对象调start() 方法启动相关类的服务,启动完成后,再调用该类的onBootCompleted( ) 方法。

至此我们已经分析完了SystemUI的启动流程,后续篇章我们将会继续通过源码来分析系统状态栏、导航栏等各种常见的SystemUI组件的启动流程。