赞
踩
SystemUI
全称System User Interface
,直译过来就是系统级用户交互界面,在 Android 系统中由SystemUI
负责统一管理整个系统层的 UI,它是一个系统级应用程序(APK),源码在/frameworks/base/packages/
目录下。
- 作者:话唠扇贝
- 链接:https://juejin.cn/post/7326464207365177380
Android - Phone中SystemUI
从源码量看就是一个相当复杂的程序,常见的如:状态栏、消息中心、近期任务、截屏以及一系列功能都是在SystemUI
中实现的。
源码位置:/frameworks/base/packages/SystemUI
常见 UI
组件有(包含但不限于,完整列表可以查看 SystemUI
服务组件列表)
状态栏 StatusBar
导航栏 NavigationBar
通知栏 NotificationPanel
快捷按键栏 QSPanel
最近任务 Recent
键盘锁 Keyguard
原生 Android
系统中 SystemUI
大概是这样
Android-AutoMotive
中的SystemUI
相对手机中要简单不少,目前商用车载系统中几乎必备的顶部状态栏、消息中心、底部导航栏在原生的Android
系统中都已经实现了。
源码位置:frameworks/base/packages/CarSystemUI
虽然CarSystemUI
与SystemUI
的源码位置不同,但是二者实际上是复用关系。通过阅读CarSystemUI
的 Android.bp 文件可以发现CarSystemUI
在编译时把SystemUI
以静态库的方式引入进来了。
android.bp 源码位置:/frameworks/base/packages/CarSystemUI/Android.bp
- android_library {
- name: "CarSystemUI-core",
- ...
- static_libs: [
- "SystemUI-core",
- "SystemUIPluginLib",
- "SystemUISharedLib",
- "SystemUI-tags",
- "SystemUI-proto",
- ...
- ],
- ...
- }
System UI
的启动大致可分为以下两个流程:
在Framework
中启动SystemUIService
在SystemUIService
中启动SystemUI
所需的各种组件
说明:本文源码分析基于版本:android-12.0.0_r3
SystemUI
是系统应用,所以它也是一个 APK,有入口 Application
,只不过它是由 system_server
进程直接启动的。
关于SystemServer
,它是 Android framework 中关键系统的服务,由 Android 系统最核心的进程Zygote
fork 生成,进程名为system_server
。常见的ActivityManagerService
、PackageManagerService
、WindowManageService
都是由SystemServer
启动的。
SystemServer 源码路径:/frameworks/base/services/java/com/android/server/SystemServer.java
第一步:SystemServer
的 main()
方法中调用 SystemServer.run()
,run()
中调用startOtherServices()
- public static void main(String[] args) {
- new SystemServer().run();
- }
- private void run() {
- ... ...
- // Start services.
- try {
- startBootstrapServices(t);
- startCoreServices(t);
- startOtherServices(t); //SystemServer在startOtherServices()被启动
- }
- ... ...
- }
第二步:startOtherServices()
中通过AMS
的回调方法ready()
,然后调用startSystemUi()
- 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
的启动。
- 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
整个应用的启动,其流程也就是应用常见的冷启动流程,这里展开讲一下:
context
中的startServiceAsUser()
是一个抽象方法,具体实现在ContextImpl.java
里。实现方法startServiceCommon()
中,通过ActivityManager.getService()
就会走到AMS
中,最终在AMS
来启动SystemUIService
。
- @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()
方法。
- @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()
方法,
- 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()
中:
- 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
类中,找到对应的调用方法:
- 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
- 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()
方法:
- 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 系统已经完成开机。
- @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 {
- // 我们不需要为正在执行某些任务的子进程启动服务。
- ...
- }
- }
第六步:SystemUIService
初始化完成后会调用onCreate()
方法,onCreate()
中调用了SystemUIApplication
中的startServiceIfNeeded()
方法完成SystemUI
子模块的初始化。
SystemUIService 源码位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.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
- // 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
- <!-- 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()
方法来继续执行子模块的初始化。
- 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
的源码如下,方法基本都能见名知意,就不再介绍了。
- 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() {
- }
前文提到CarSystemUI
复用了手机SystemUI
的代码,所以CarSystemUI
的启动流程和SystemUI
的是完全一致的。
但CarSystemUI
中需要的功能与SystemUI
中也有部分差异,那么是这些差异化的功能是如何引入并完成初始化?以及一些手机的SystemUI
才需要的功能是如何去除的呢?
其实很简单,在SystemUI
的启动流程中我们得知,各个子模块的 className 是通过SystemUIFactory
的getSystemUIServiceComponents()
获取到的,那么只要继承SystemUIFactory
并重写getSystemUIServiceComponents()
就可以了。
- 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;
- }
- }
- <!-- 需要移除的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
子模块的替换。
总结一下,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
开发的同学。
关注我获取更多知识或者投稿
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。