一 SystemUI 概述
SystemUI全称System User Interface,直译过来就是系统级用户交互界面 ,在 Android 系统中由SystemUI负责统一管理整个系统层的 UI,它是一个系统级应用程序(APK),源码在/frameworks/base/packages/目录下。
1.1 SystemUI
Android - Phone中SystemUI从源码量看就是一个相当复杂的程序,常见的如:状态栏、消息中心、近期任务、截屏以及一系列功能都是在SystemUI中实现的。
源码位置:/frameworks/base/packages/SystemUI
常见 UI 组件有(包含但不限于,完整列表可以查看 SystemUI 服务组件列表)
- 状态栏
StatusBar - 导航栏
NavigationBar - 通知栏
NotificationPanel - 快捷按键栏
QSPanel - 最近任务
Recent - 键盘锁
Keyguard
原生 Android 系统中 SystemUI 大概是这样

1.2 CarSystemUI
Android-AutoMotive中的SystemUI相对手机中要简单不少,目前商用车载系统中几乎必备的顶部状态栏、消息中心、底部导航栏在原生的Android系统中都已经实现了。
源码位置:frameworks/base/packages/CarSystemUI

虽然CarSystemUI与SystemUI的源码位置不同,但是二者实际上是复用关系。通过阅读CarSystemUI的 Android.bp 文件可以发现CarSystemUI在编译时把SystemUI以静态库的方式引入进来了。
android.bp 源码位置:/frameworks/base/packages/CarSystemUI/Android.bp
java
android_library {
name: "CarSystemUI-core",
...
static_libs: [
"SystemUI-core",
"SystemUIPluginLib",
"SystemUISharedLib",
"SystemUI-tags",
"SystemUI-proto",
...
],
...
}
二 SystemUI 启动流程
System UI的启动大致可分为以下两个流程:
- 在
Framework中启动SystemUIService - 在
SystemUIService中启动SystemUI所需的各种组件
说明:本文源码分析基于版本:android-12.0.0_r3
2.1 Framework 中的流程
SystemUI 是系统应用,所以它也是一个 APK,有入口 Application,只不过它是由 system_server 进程直接启动的。
关于SystemServer,它是 Android framework 中关键系统的服务,由 Android 系统最核心的进程Zygotefork 生成,进程名为system_server。常见的ActivityManagerService、PackageManagerService、WindowManageService都是由SystemServer启动的。
SystemServer 源码路径:/frameworks/base/services/java/com/android/server/SystemServer.java
第一步: SystemServer 的 main() 方法中调用 SystemServer.run(),run()中调用startOtherServices()
java
public static void main(String[] args) {
new SystemServer().run();
}
java
private void run() {
... ...
// Start services.
try {
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t); //SystemServer在startOtherServices()被启动
}
... ...
}
第二步: startOtherServices()中通过AMS的回调方法ready(),然后调用startSystemUi()
java
mActivityManagerService.systemReady(() -> {
... ...
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
... ...
,t);
第三步: startSystemUi()中可以看出,SystemUI本质就是一个Service,通过PM获取到的Component 是com.android.systemui/.SystemUIService,然后通过调用context.startServiceAsUser()完成对SystemUIService的启动。
java
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();
}
第四步: SystemUIService 依附于SystemUI应用,所以SystemUIService启动前需要完成SystemUI整个应用的启动,其流程也就是应用常见的冷启动流程,这里展开讲一下:
SystemUI 应用启动流程
context中的startServiceAsUser()是一个抽象方法,具体实现在ContextImpl.java里。实现方法startServiceCommon()中,通过ActivityManager.getService()就会走到AMS中,最终在AMS来启动SystemUIService。
java
@Override
public ComponentName startServiceAsUser(Intent service, UserHandle user) {
return startServiceCommon(service, false, user);
}
@Override
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService( //在AMS中开启Service
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
... ...
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
接下来进入AMS,一探究竟:
AMS 源码路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
在AMS的startService()方法里,会经过一系列内部流程,调用到bringUpServiceLocked()方法。
java
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
... ...
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId); // 内部调用到 startServiceLocked()
}
... ...
}
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
... ...
if (caller != null) {
// 这里记录app的进程信息
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
... ...
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); //内部调用到startServiceInnerLocked()
... ...
return cmp;
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
... ...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); //调用到bringUpServiceLocked()
if (error != null) {
return new ComponentName("!!", error);
}
... ...
return r.name;
}
继续调用了bringUpServiceLocked()方法,
java
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
... ...
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
//如果service进程存在
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
//启动service
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
}
}
}
... ...
// 如果不存在此进程
if (app == null && !permissionsReviewRequired) {
// 启动运行的线程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
}
... ...
return null;
}
这个方法做了两件事:
- 如果
SystemUIService所属进程已经存在,则直接调用realStartServiceLocked()。 - 如果
SystemUIService所属进程不存在,则执行startProcessLocked()方法创建进程,经过层层调用,最终也会走到realStartServiceLocked()中:
java
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
... ...
try {
... ...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
}
}
这个方法内部调用了app.thread.scheduleCreateService(),而app.thread是一个IApplicationThread类型的,他的实现是ActivityThread的一个内部类ApplicationThread,而这个类正好实现了IApplicationThread.Stub,在ApplicationThread类中,找到对应的调用方法:
java
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
可以看出,是发送一个消息给Handler,这个Handler是ActivityThread的内部类H
java
public void handleMessage(Message msg) {
switch (msg.what) {
... ...
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
... ...
}
}
最终调用了handleCreateService()方法:
java
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//创建service的context
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//创建Application
Application app = packageInfo.makeApplication(false, mInstrumentation);
//获取类加载器
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//加载service实例
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
//初始化service
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//调用service的onCreate方法
service.onCreate();
mServices.put(data.token, service);
try {
//通过serviceDoneExecuting告知AMS,service已经启动完成
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
这个方法主要做了以下几件事:
- 首先,创建上下文
- 创建
SystemUIApplication,获取类加载器 - 加载
SystemUIService实例,初始化SystemUIService, 调用onCreate()方法 - 最后通知
AMS,SystemUIService启动完成。
到这里SystemUIService已经启动完成。
第五步: 前面在SystemUIApplication创建成功后会回调内部的OnCreate()方法,在OnCreate()中方法注册了一个开机广播,当接收到开机广播后会调用SystemUI的onBootCompleted()方法来告诉每个子模块 Android 系统已经完成开机。
java
@Override
public void onCreate() {
super.onCreate();
Log.v(TAG, "SystemUIApplication created.");
// 设置所有服务继承的应用程序主题。
// 请注意,在清单中设置应用程序主题仅适用于activity。这里是让Service保持与主题设置同步。
setTheme(R.style.Theme_SystemUI);
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mBootCompleteCache.isBootComplete()) return;
if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
unregisterReceiver(this);
mBootCompleteCache.setBootComplete();
if (mServicesStarted) {
final int N = mServices.length;
for (int i = 0; i < N; i++) {
mServices[i].onBootCompleted(); //通知SystemUI子模块
}
}
}
}, bootCompletedFilter);
...
} else {
// 我们不需要为正在执行某些任务的子进程启动服务。
...
}
}
2.2 SystemUI 中的流程
第六步: SystemUIService初始化完成后会调用onCreate()方法,onCreate()中调用了SystemUIApplication中的startServiceIfNeeded()方法完成SystemUI子模块的初始化。
SystemUIService 源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
java
public class SystemUIService extends Service {
... ...
@Override
public void onCreate() {
super.onCreate();
// Start all of SystemUI
((SystemUIApplication) getApplication()).startServicesIfNeeded(); //调用startServicesIfNeeded()
... ...
}
}
第七步: 在SystemUIApplication的startServicesIfNeeded()方法中,通过SystemUIFactory获取到配置在config.xml中每个子模块的className。
SystemUIApplication 源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
java
// SystemUIApplication
public void startServicesIfNeeded() {
String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
startServicesIfNeeded("StartServices", names);
}
// SystemUIFactory
/** Returns the list of system UI components that should be started. */
public String[] getSystemUIServiceComponents(Resources resources) {
return resources.getStringArray(R.array.config_systemUIServiceComponents);
}
config.xml 位置:/frameworks/base/packages/SystemUI/res/values/config.xml
xml
<!-- SystemUI Services: The classes of the stuff to start. -->
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</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.statusbar.phone.StatusBar</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.biometrics.AuthController</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
<item>com.android.systemui.SizeCompatModeActivityController</item>
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.theme.ThemeOverlayController</item>
<item>com.android.systemui.accessibility.WindowMagnification</item>
<item>com.android.systemui.accessibility.SystemActions</item>
<item>com.android.systemui.toast.ToastUI</item>
</string-array>
第八步: 在startServicesIfNeeded()中通过反射完成了每个SystemUI组件的创建,然后再调用各个SystemUI的onStart()方法来继续执行子模块的初始化。
java
private SystemUI[] mServices;
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
if (mServicesStarted) {
return;
}
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);
try {
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
if (obj == null) {
Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
obj = (SystemUI) constructor.newInstance(this);
}
mServices[i] = obj;
} catch (ClassNotFoundException
| NoSuchMethodException
| IllegalAccessException
| InstantiationException
| InvocationTargetException ex) {
throw new RuntimeException(ex);
}
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
// 调用各个子模块的start()
mServices[i].start();
// 首次启动时,这里始终为false,不会被调用
if (mBootCompleteCache.isBootComplete()) {
mServices[i].onBootCompleted();
}
}
mServicesStarted = true;
}
这里的SystemUI是一个抽象类,状态栏、近期任务等等模块都是继承自SystemUI,通过这种方式可以很大程度上简化复杂的SystemUI程序中各个子模块创建方式,同时我们可以通过配置资源的方式动态加载需要的SystemUI模块。
SystemUI的源码如下,方法基本都能见名知意,就不再介绍了。
java
public abstract class SystemUI implements Dumpable {
protected final Context mContext;
public SystemUI(Context context) {
mContext = context;
}
public abstract void start();
protected void onConfigurationChanged(Configuration newConfig) {
}
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
}
protected void onBootCompleted() {
}
2.3 CarSystemUI 的启动流程
前文提到CarSystemUI复用了手机SystemUI的代码,所以CarSystemUI的启动流程和SystemUI的是完全一致的。
但CarSystemUI中需要的功能与SystemUI中也有部分差异,那么是这些差异化的功能是如何引入并完成初始化?以及一些手机的SystemUI才需要的功能是如何去除的呢?
其实很简单,在SystemUI的启动流程中我们得知,各个子模块的 className 是通过SystemUIFactory的getSystemUIServiceComponents()获取到的,那么只要继承SystemUIFactory并重写getSystemUIServiceComponents()就可以了。
java
public class CarSystemUIFactory extends SystemUIFactory {
@Override
protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
return DaggerCarSystemUIRootComponent.builder()
.contextHolder(new ContextHolder(context))
.build();
}
@Override
public String[] getSystemUIServiceComponents(Resources resources) {
Set<String> names = new HashSet<>();
// 先引入systemUI中的components
for (String s : super.getSystemUIServiceComponents(resources)) {
names.add(s);
}
// 再移除CarsystemUI不需要的components
for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsExclude)) {
names.remove(s);
}
// 最后再添加CarsystemUI特有的components
for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsInclude)) {
names.add(s);
}
String[] finalNames = new String[names.size()];
names.toArray(finalNames);
return finalNames;
}
}
xml
<!-- 需要移除的Components. -->
<string-array name="config_systemUIServiceComponentsExclude" translatable="false">
<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.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>com.android.systemui.LatencyTester</item>
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.accessibility.WindowMagnification</item>
<item>com.android.systemui.accessibility.SystemActions</item>
</string-array>
<!-- 新增的Components. -->
<string-array name="config_systemUIServiceComponentsInclude" translatable="false">
<item>com.android.systemui.car.navigationbar.CarNavigationBar</item>
<item>com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier</item>
<item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
<item>com.android.systemui.car.volume.VolumeUI</item>
</string-array>
通过以上方式,就完成了CarSystemUI子模块的替换。
2.4 小结
总结一下,SystemUI的大致启动流程可以归纳如下:

SystemUI 是一个 persistent 应用,它由操作系统启动,主要流程为
Android系统在开机后会创建system_server进程,它会启动各种系统所需要的服务,其中就包括SystemUIService。SystemUIService启动后进入到应用层SystemUI中,在SystemUIApplication它首先会初始化监听ACTION_BOOT_COMPLETED等通知,待系统完成启动后会通知各个组件onBootCompleted。- 在进入
SystemUIService中依然执行的SystemUIApplication中的startServicesIfNeeded()方法启动SystemUI中的子模块。 - 最终的服务启动逻辑都是在
SystemUIApplication里面,并且都保存在mServices数组中。
三 总结
SystemUI在原生的车载 Android 系统是一个较为复杂的模块,本文主要介绍了SystemUI 和CarSystemUI的功能、源码结构及启动时序,希望能帮到从事SystemUI开发的同学。