首语
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"><applicationandroid: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/