小工具知识网

当前位置: 首页 > 行业知识 > Android SystemUI梳理

行业知识

Android SystemUI梳理

2026-11-02 14:55:48 来源:互联网转载

文章目录

  • 一、简介
  • 二、功能介绍
  • 三、SystemUI 启动流程
  • 四、SystemUI 初始化流程
    • 4.1、Application初始化
    • 4.2、启动 SystemUIService

        团队博客: 汽车电子社区


      一、简介

        在Android系统中SystemUI是一个系统级的APP,它提供了系统的用户界面,由system_server进程启动。SystemUI本身不属于system_server进程,它是一个独立的进程。它的HMI包括了状态栏、导航栏、通知栏、锁屏、近期任务等等。

        SystemServer是一个由Zogyte进程启动的程序,它负责启动和管理Android系统中的各种核心服务。 例如:ActivityManagerService和PackageManagerService,这些服务也都运行在system_server进程中,为Android系统提供各种功能和接口,供应用程序和其他服务调用。我们常说的Android Framework其实就是由这些Service组成的。

      二、功能介绍

        这部分将主要介绍那些对我们定制自己的SystemUI时有参考价值的模块。

        1. 状态栏

           StatusBar,负责显示时间,电量,信号,通知等状态信息。

        2. 导航栏

          NavigationBar,显示返回,主页,最近任务等按钮。在车载Android中,我们多数时候会称为Dock栏(DockBar)。一般负责显示车控、主页、蓝牙电话等常用功能的快捷控制和入口。

        3. 通知栏

          NotificationPanel,显示、控制通知的界面。实际的车载项目中通知栏往往会和【消息中心】合并成一个独立的APP。

        4. 快捷控制

          QuickSettings,这个面板可以让用户快速地调整一些常用的设置,例如亮度、飞行模式、蓝牙等。QS面板有多种状态,包括初级展开面板(Quick Quick Settings,QQS)和完整QS面板(Quick Settings,QS)。用户可以通过下拉通知栏来打开或关闭QS面板。

        5. 其他功能

          一些系统级的对话框、弹窗、动画、屏保等,这些内容相对比较简单,不再介绍了。而锁屏、媒体控制等一些功能,车载SystemUI开发时涉及的不多,也同样不再介绍。

      三、SystemUI 启动流程

        当Android系统启动完成后,system_server进程会通过ActivityManagerService启动一个名为com.android.systemui.SystemUIService的服务,这个服务是SystemUI的入口类,它继承了Service类。

      SystemServer的源码位置:/frameworks/base/services/java/com/android/server/SystemServer.java

      mActivityManagerService.systemReady(() -> {        Slog.i(TAG, "Making services ready");        //...        t.traceBegin("StartSystemUI");        try {            startSystemUi(context, windowManagerF);        } catch (Throwable e) {            reportWtf("starting System UI", e);        }        t.traceEnd();    }, t);

        从这里我们可以看出,SystemUI本质就是一个Service,通过Pm获取到的Component是com.android.systemui/.SystemUIService。startSystemUi代码细节如下:

      private static 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();}

        以上就是SystemUI的启动流程,接下来我们继续看SystemUI是如何初始化的。

      四、SystemUI 初始化流程

        SystemUI的初始化流程分为以下几步:

      4.1、Application初始化

      SystemUIApplication源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

        在SystemUI启动后,首先会调用Application的onCreate方法,并在onCreate方法中对SystemUI进行初始化。这里我把它分为四个部分的内容。

        1、第一部分内容不多,主要是通过Dagger拿到SystemUI中的一些创建好的组件,同时设定一些调试工具。

      public void onCreate() {    super.onCreate();    Log.v(TAG, "SystemUIApplication created.");    // This line is used to setup Dagger's dependency injection and should be kept at the    // top of this method.    // TimingsTraceLog 是一个用于跟踪代码执行时间的工具类,它可以在traceview中看到。    TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",            Trace.TRACE_TAG_APP);    log.traceBegin("DependencyInjection");    // 此行用于设置Dagger的依赖注入,并应保持在onrecate方法的顶部。    mContextAvailableCallback.onContextAvailable(this);    log.traceEnd();    mLocalHandler = new LocalHandler();    // 设置所有服务继承的应用程序主题。请注意,    // 仅在清单中设置应用程序主题仅适用于活动。请将其与在那里设置的主题同步。    setTheme(R.style.Theme_SystemUI);}

        2、首先判断当前进程是否属于系统用户。然后根据SF GPU上下文优先级设置设定SystemUI的渲染器的上下文优先级,最后开启SystemServer的binder调用trace跟踪。

      public void onCreate() {    // 判断当前进程是否是系统进程。如果是系统进程,那么就注册 BOOT_COMPLETED 广播接收器。    if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {        // 创建 BOOT_COMPLETED 广播接收器的意图过滤器。        IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);        bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);       }}

        ThreadedRenderer可以简单理解为一个渲染器,它可以在后台线程中渲染视图层次结构。优先级越高,渲染速度越快。

        Process.myUserHandle()可以获取当前进程的用户类型。如果是从事移动端APP开发,很少会涉及Android系统的多用户机制。但是由于汽车是一种具有共享属性的工具,会存在多个家庭成员使用一辆车的情况,所以Android多用户在车载Android开发中较为常见。

        当我们在系统设置中的「系统」「多用户」添加一个新用户并切换到这个新用户时,实际上会再启动一个SystemUI进程,新的SystemUI进程的用户ID会从U1X开始,原始的SystemUI的用户ID则始终是U0。

        3、第三部分注册监听开机广播,并在SystemUIService启动后,再通知SystemUI中的其它组件「系统启动完成」。

      public void onCreate() {registerReceiver(new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            if (mBootCompleted) return;            if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");            unregisterReceiver(this);            mBootCompleted = true;            if (mServicesStarted) {                final int N = mServices.length;                for (int i = 0; i  

        4、第四部分如果当前用户非系统用户那么调用startSecondaryUserServicesIfNeeded方法。

      // 我们不需要为正在执行某些任务的子进程初始化组件。例如:截图进程等String processName = ActivityThread.currentProcessName();ApplicationInfo info = getApplicationInfo();if (processName != null && processName.startsWith(info.processName + ":")) {    return;}// 对于第二个用户,boot-completed永远不会被调用,因为它已经在启动时为主SystemUI进程广播了// 对于需要每个用户初始化SystemUI组件的组件,我们现在为当前非系统用户启动这些组件。startSecondaryUserServicesIfNeeded();

        在这里插入代码片`startSecondaryUserServicesIfNeeded方法也是通过startServicesIfNeeded方法来初始化SystemUI中的功能组件。具体是如何初始化,我们之后再来分析。

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

        到这里,我们简单总结一下SystemUIApplication中其实最主要的工作,其实只有两个:

          1.、在系统用户空间中监听开机广播,并通知SystemUI的功能组件。

          2、在非系统用户空间中,直接初始化SystemUI的功能组件。

      4.2、启动 SystemUIService

        当Application完成初始化之后,紧接着,SystemUIService就会被启动。

      SystemUIService源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java

        SystemUIService在onCreate()方法中会调用((SystemUIApplication) getApplication()).startServicesIfNeeded()方法。

      @Overridepublic void onCreate() {    super.onCreate();    // Start all of SystemUI    ((SystemUIApplication) getApplication()).startServicesIfNeeded();    ...}

        这里可能有个疑问:为什么不把startServicesIfNeeded的相关逻辑写在Service中,非要写到Application中?

        是因为,当前用户不是系统用户时,startSecondaryUserServicesIfNeeded也需要去调用startServicesIfNeeded方法进行组件初始化,所以干脆把所有的初始化逻辑都写到Application中了。

      private void startServicesIfNeeded(String[] services) {    if (mServicesStarted) {        return;    }    mServices = new SystemUI[services.length];    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"))) {            mBootCompleted = true;            if (DEBUG) {                Log.v(TAG, "BOOT_COMPLETED was already sent");            }        }    }    Log.v(TAG, "Starting SystemUI services for user " +            Process.myUserHandle().getIdentifier() + ".");    Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);    Message msg = mLocalHandler.obtainMessage();    msg.obj = services;    msg.arg1 = services.length;    msg.arg2 = 0;    msg.what = EVENT_START_SERVICE;    msg.sendToTarget();}

上一篇:天猫服务器坏了怎么修理?

下一篇:【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 前端