SystemUI 解析

首语

SystemUI(System User Interface)是Android 系统为用户提供的系统级别的信息显示与交互的UI组件应用程序,包含状态栏、导航栏、锁屏、通知面板、快速设置、最近任务等,它们各部分独立,各尽其责。

SystemUI是一个常驻应用程序,只要系统运行,它就会一直运行,即使被杀死也会重新启动。

源码目录

SystemUI源码目录在frameworks/base/package下,和Settings不一样,它不在package/apps下。

从Android.bp文件中可以得出,模块名为SystemUI。

架构

SystemUI各组件经常会互相交互,例如点击通知面板通知在锁屏情况下会跳转锁屏页面先解锁,解锁情况下跳转锁屏内容页面,因此通知面板需要清楚锁屏状态来进行处理。为此需要设计好架构,还轻松获取到各个组件,避免产生很多的创建代码,SystemUI使用了依赖注入自动创建对象,SystemUI使用Dagger2来作为依赖注入库,管理组件。

Android系统中,为了适应多元化场景,诸如TV、Car,它们又是不同的UI组件,同时满足模块化设计,因此将SytemUI独立成一个单独的、常驻内存的应用程序。

SystemUI各种组件UI均存在UIController来进行UI逻辑的处理和交互,不同组件源码通过目录清晰划分。

关于Dagger2,可参考以下文档:
Android 官方:https://developer.android.google.cn/training/dependency-injection/dagger-basics?hl=zh_cn
Dagger: https://dagger.dev/dev-guide

AndroidManifest

由Manifest可以看出,SystemUI是一个比较特殊的应用程序,有许多特定设置项。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
        package="com.android.systemui"
        <!--指定共享的uid-->
        android:sharedUserId="android.uid.systemui"
        xmlns:tools="http://schemas.android.com/tools"
        coreApp="true">
     <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"
            <!--默认存储空间重定向到data/user_de-->
        	android:defaultToDeviceProtectedStorage="true"
            <!--DirectBoot 模式下可以启动-->
        	android:directBootAware="true"
        	tools:replace="android:appComponentFactory"
            <!--指定应用程序组件工厂,动态创建和初始化组件-->
        	android:appComponentFactory=".SystemUIAppComponentFactory">
     </application>       
</manifest>

启动流程

SystemServer 进程启动过程文章中,我们清楚SystemServer进程主要工作是启动系统服务,其中在startOtherServices方法中,当AMS系统服务进入就绪状态时,会调用startSystemUi方法来启动SystemUI,其中AMS是在startBootstrapServices方法中被启动的。在startSystemUi方法中启动了一个服务,服务intent的component通过PackageManagerInternal类的getSystemUiServiceComponent方法获取,PackageManagerInternal是一个抽象类,它的实现在PackageManagerInternalBase类中,可以看到getSystemUiServiceComponent实现中返回了config_systemUIServiceComponent字符串。

源码路径:frameworks\base\services\java\com\android\server\SystemServer.java

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
    mActivityManagerService.systemReady(() -> {
        ...
        t.traceBegin("StartSystemUI");
        try {
            startSystemUi(context, windowManagerF);
        } catch (Throwable e) {
            reportWtf("starting System UI", e);
        }
        t.traceEnd();
    },t);
}
private static void startSystemUi(Context context, WindowManagerService windowManager) {
        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
        Intent intent = new Intent();
        intent.setComponent(pm.getSystemUiServiceComponent());
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        //Slog.d(TAG, "Starting service: " + intent);
        context.startServiceAsUser(intent, UserHandle.SYSTEM);
        windowManager.onSystemUiStarted();
    }

源码路径:frameworks\base\services\core\java\com\android\server\pm\PackageManagerInternalBase.java

@Override
@Deprecated
public final ComponentName getSystemUiServiceComponent() {
    return ComponentName.unflattenFromString(getContext().getResources().getString(
                com.android.internal.R.string.config_systemUIServiceComponent));
}

可以看到指定的Component包名为com.android.systemui,类名为com.android.systemui.SystemUIService。

到这里我们就清楚,SystemUI是SystemServer进程启动SystemUIService来启动的。

源码路径: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类中调用SystemUIApplication类的startServicesIfNeeded方法。

源码路径:frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIService.java

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

首先获取定制的系统UI组件,其为VenderService。继续通过getStartableComponents和getStartableComponentsPerUser方法获取组件

源码路径:frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIApplication.java

public void startServicesIfNeeded() {
    	//定制系统UI组件
        final String vendorComponent = SystemUIFactory.getInstance()
                .getVendorComponent(getResources());
        Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
                Comparator.comparing(Class::getName));
        sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponents());
        sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser());
        startServicesIfNeeded(
                sortedStartables, "StartServices", vendorComponent);
}

源码路径:frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIFactory.java

//    <string name="config_systemUIVendorServiceComponent" translatable="false">com.android.systemui.VendorServices</string>
public String getVendorComponent(Resources resources) {
        return resources.getString(R.string.config_systemUIVendorServiceComponent);
}
public Map<Class<?>, Provider<CoreStartable>> getStartableComponents() {
        return mSysUIComponent.getStartables();
}
public Map<Class<?>, Provider<CoreStartable>> getStartableComponentsPerUser() {
        return mSysUIComponent.getPerUserStartables();
}

这里使用了Dagger2的@IntoMap注入相关类,只要是继承CoreStartable类的都将会被注入。

源码路径:frameworks\base\packages\SystemUI\src\com\android\systemui\dagger\SysUIComponent.java

@SysUISingleton
@Subcomponent(modules = {
        DefaultComponentBinder.class,
        DependencyProvider.class,
        SystemUIBinder.class,
        SystemUIModule.class,
        SystemUICoreStartableModule.class,
        ReferenceSystemUIModule.class})
public interface SysUIComponent {
    Map<Class<?>, Provider<CoreStartable>> getStartables();
    @PerUser Map<Class<?>, Provider<CoreStartable>> getPerUserStartables();
}

注入方法如下,相关注入结束后,继续回到SystemUIApplication类的startServicesIfNeeded方法。

源码路径:frameworks\base\packages\SystemUI\src\com\android\systemui\dagger\SystemUICoreStartableModule.kt

@Module
abstract class SystemUICoreStartableModule {
     /** Inject into AuthController.  */
    @Binds
    @IntoMap
    @ClassKey(AuthController::class)
    abstract fun bindAuthController(service: AuthController): CoreStartable

    /** Inject into ClipboardListener.  */
    @Binds
    @IntoMap
    @ClassKey(ClipboardListener::class)
    abstract fun bindClipboardListener(sysui: ClipboardListener): CoreStartable
    ......
}

获取所有组件后,启动所有组件,至此System UI和SystemUI所有组件启动完成。

private void startServicesIfNeeded(
            Map<Class<?>, Provider<CoreStartable>> startables,
            String metricsPrefix,
            String vendorComponent) {
        if (mServicesStarted) {
            return;
        }
        mServices = new CoreStartable[startables.size() + (vendorComponent == null ? 0 : 1)];

        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");
                }
            }
        }

        mDumpManager = mSysUIComponent.createDumpManager();

        Log.v(TAG, "Starting SystemUI services for user " +
                Process.myUserHandle().getIdentifier() + ".");
        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                Trace.TRACE_TAG_APP);
        log.traceBegin(metricsPrefix);

        int i = 0;
        for (Map.Entry<Class<?>, Provider<CoreStartable>> entry : startables.entrySet()) {
            String clsName = entry.getKey().getName();
            int j = i;  // Copied to make lambda happy.
            timeInitialization(
                    clsName,
                	//启动组件
                    () -> mServices[j] = startStartable(clsName, entry.getValue()),
                    log,
                    metricsPrefix);
            i++;
        }

        if (vendorComponent != null) {
            timeInitialization(
                    vendorComponent,
                    () -> mServices[mServices.length - 1] =
                            startAdditionalStartable(vendorComponent),
                    log,
                    metricsPrefix);
        }

        for (i = 0; i < mServices.length; i++) {
            if (mBootCompleteCache.isBootComplete()) {
                mServices[i].onBootCompleted();
            }

            mDumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
        }
        mSysUIComponent.getInitController().executePostInitTasks();
        log.traceEnd();

        mServicesStarted = true;
    }
private CoreStartable startStartable(String clsName, Provider<CoreStartable> provider) {
        if (DEBUG) Log.d(TAG, "loading: " + clsName);
        return startStartable(provider.get());
    }

    private CoreStartable startStartable(CoreStartable startable) {
        if (DEBUG) Log.d(TAG, "running: " + startable);
        startable.start();

        return startable;
    }

总结

SystemUI是Android系统中与用户交互频繁的UI组件应用程序,地位不言而喻。后续会对SystemUI中重要的组件进行单独分析,深入了解。同时对于这个一个UI组件应用程序,Android 14引入了Jetpack Compse进行部分UI代码的重构,在保持稳定性的前提下官方会持续进行重构,到时架构及实现将会发生重大变化。

官方文档:frameworks/base/package/SystemUI/docs/

相关推荐

  1. SystemUI

    2024-03-14 12:44:03       33 阅读
  2. SystemUI入门之CentralSurfaces

    2024-03-14 12:44:03       44 阅读
  3. SystemUI QSFactory插件

    2024-03-14 12:44:03       34 阅读
  4. InterLM代码

    2024-03-14 12:44:03       46 阅读
  5. UV、PV

    2024-03-14 12:44:03       66 阅读
  6. Yaml语法

    2024-03-14 12:44:03       77 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-14 12:44:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-14 12:44:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-14 12:44:03       87 阅读
  4. Python语言-面向对象

    2024-03-14 12:44:03       96 阅读

热门阅读

  1. 【MySQL】的相关面试题(三)

    2024-03-14 12:44:03       44 阅读
  2. 22.3 分布式

    2024-03-14 12:44:03       45 阅读
  3. [Ubuntu 20.04] QT屏幕与触摸旋转

    2024-03-14 12:44:03       39 阅读
  4. Linux 信号量的使用

    2024-03-14 12:44:03       41 阅读
  5. Mysql将datetime数据转为Data/Char

    2024-03-14 12:44:03       35 阅读
  6. linux内核网络揭秘《二》“每日读书”

    2024-03-14 12:44:03       46 阅读
  7. 高防服务器能够抵御哪些攻击?

    2024-03-14 12:44:03       44 阅读
  8. C语言自学笔记10----C语言数组

    2024-03-14 12:44:03       37 阅读
  9. SpringBoo和vue项目blob传参未生效

    2024-03-14 12:44:03       42 阅读
  10. 蚓链助新零售企业快速实现数字化转型

    2024-03-14 12:44:03       44 阅读
  11. 用python实现人生重开模拟器游戏

    2024-03-14 12:44:03       45 阅读
  12. (自用)Spring常用配置

    2024-03-14 12:44:03       39 阅读
  13. sheel和setuptools两个包的作用

    2024-03-14 12:44:03       35 阅读