当前位置:   article > 正文

Android 车载应用开发指南 - SystemUI

automotive systemui启动流程

一  SystemUI 概述

SystemUI全称System User Interface,直译过来就是系统级用户交互界面,在 Android 系统中由SystemUI负责统一管理整个系统层的 UI,它是一个系统级应用程序(APK),源码在/frameworks/base/packages/目录下。

  1. 作者:话唠扇贝
  2. 链接:https://juejin.cn/post/7326464207365177380

1.1 SystemUI

Android - Phone中SystemUI从源码量看就是一个相当复杂的程序,常见的如:状态栏、消息中心、近期任务、截屏以及一系列功能都是在SystemUI中实现的。

源码位置:/frameworks/base/packages/SystemUI

常见 UI 组件有(包含但不限于,完整列表可以查看 SystemUI 服务组件列表)

  • 状态栏 StatusBar

  • 导航栏 NavigationBar

  • 通知栏 NotificationPanel

  • 快捷按键栏 QSPanel

  • 最近任务 Recent

  • 键盘锁 Keyguard

原生 Android 系统中 SystemUI 大概是这样

ae4568ceec04499171c3b80a07bd1659.jpeg

1.2 CarSystemUI

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

源码位置:frameworks/base/packages/CarSystemUI

a763f154d0f6502e0301d7e489a0b1f2.jpeg

虽然CarSystemUISystemUI的源码位置不同,但是二者实际上是复用关系。通过阅读CarSystemUI的 Android.bp 文件可以发现CarSystemUI在编译时把SystemUI以静态库的方式引入进来了。

android.bp 源码位置:/frameworks/base/packages/CarSystemUI/Android.bp

  1. android_library {
  2. name: "CarSystemUI-core",
  3. ...
  4. static_libs: [
  5. "SystemUI-core",
  6. "SystemUIPluginLib",
  7. "SystemUISharedLib",
  8. "SystemUI-tags",
  9. "SystemUI-proto",
  10. ...
  11. ],
  12. ...
  13. }

二 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。常见的ActivityManagerServicePackageManagerServiceWindowManageService都是由SystemServer启动的。

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

第一步:SystemServermain() 方法中调用 SystemServer.run()run()中调用startOtherServices()

  1. public static void main(String[] args) {
  2. new SystemServer().run();
  3. }
  1. private void run() {
  2. ... ...
  3. // Start services.
  4. try {
  5. startBootstrapServices(t);
  6. startCoreServices(t);
  7. startOtherServices(t); //SystemServer在startOtherServices()被启动
  8. }
  9. ... ...
  10. }

第二步:startOtherServices()中通过AMS的回调方法ready(),然后调用startSystemUi()

  1. mActivityManagerService.systemReady(() -> {
  2. ... ...
  3. try {
  4. startSystemUi(context, windowManagerF);
  5. } catch (Throwable e) {
  6. reportWtf("starting System UI", e);
  7. }
  8. ... ...
  9. ,t);

第三步:startSystemUi()中可以看出,SystemUI本质就是一个Service,通过PM获取到的Componentcom.android.systemui/.SystemUIService,然后通过调用context.startServiceAsUser()完成对SystemUIService的启动。

  1. private static void startSystemUi(Context context, WindowManagerService windowManager) {
  2. PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
  3. Intent intent = new Intent();
  4. intent.setComponent(pm.getSystemUiServiceComponent());
  5. intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
  6. //Slog.d(TAG, "Starting service: " + intent);
  7. context.startServiceAsUser(intent, UserHandle.SYSTEM);
  8. windowManager.onSystemUiStarted();
  9. }

第四步:SystemUIService 依附于SystemUI应用,所以SystemUIService启动前需要完成SystemUI整个应用的启动,其流程也就是应用常见的冷启动流程,这里展开讲一下:

  • SystemUI 应用启动流程

    context中的startServiceAsUser()是一个抽象方法,具体实现在ContextImpl.java里。实现方法startServiceCommon()中,通过ActivityManager.getService()就会走到AMS中,最终在AMS来启动SystemUIService

  1. @Override
  2. public ComponentName startServiceAsUser(Intent service, UserHandle user) {
  3. return startServiceCommon(service, false, user);
  4. }
  5. @Override
  6. private ComponentName startServiceCommon(Intent service, boolean requireForeground,
  7. UserHandle user) {
  8. try {
  9. validateServiceIntent(service);
  10. service.prepareToLeaveProcess(this);
  11. ComponentName cn = ActivityManager.getService().startService( //在AMS中开启Service
  12. mMainThread.getApplicationThread(), service,
  13. service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
  14. getOpPackageName(), getAttributionTag(), user.getIdentifier());
  15. ... ...
  16. } catch (RemoteException e) {
  17. throw e.rethrowFromSystemServer();
  18. }
  19. }

接下来进入AMS,一探究竟:

AMS 源码路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

AMSstartService()方法里,会经过一系列内部流程,调用到bringUpServiceLocked()方法。

  1. @Override
  2. public ComponentName startService(IApplicationThread caller, Intent service,
  3. String resolvedType, boolean requireForeground, String callingPackage,
  4. String callingFeatureId, int userId)
  5. throws TransactionTooLargeException {
  6. ... ...
  7. try {
  8. res = mServices.startServiceLocked(caller, service,
  9. resolvedType, callingPid, callingUid,
  10. requireForeground, callingPackage, callingFeatureId, userId); // 内部调用到 startServiceLocked()
  11. }
  12. ... ...
  13. }
  14. }
  15. ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage,
  16. @Nullable String callingFeatureId, final int userId,
  17. boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
  18. ... ...
  19. if (caller != null) {
  20. // 这里记录app的进程信息
  21. final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
  22. ... ...
  23. ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); //内部调用到startServiceInnerLocked()
  24. ... ...
  25. return cmp;
  26. }
  27. ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
  28. ... ...
  29. String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); //调用到bringUpServiceLocked()
  30. if (error != null) {
  31. return new ComponentName("!!", error);
  32. }
  33. ... ...
  34. return r.name;
  35. }

继续调用了bringUpServiceLocked()方法,

  1. private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired)
  2. throws TransactionTooLargeException {
  3. ... ...
  4. if (!isolated) {
  5. app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
  6. if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
  7. //如果service进程存在
  8. if (app != null && app.thread != null) {
  9. try {
  10. app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
  11. //启动service
  12. realStartServiceLocked(r, app, execInFg);
  13. return null;
  14. } catch (TransactionTooLargeException e) {
  15. throw e;
  16. } catch (RemoteException e) {
  17. Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
  18. }
  19. }
  20. }
  21. ... ...
  22. // 如果不存在此进程
  23. if (app == null && !permissionsReviewRequired) {
  24. // 启动运行的线程
  25. if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
  26. hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
  27. String msg = "Unable to launch app "
  28. + r.appInfo.packageName + "/"
  29. + r.appInfo.uid + " for service "
  30. + r.intent.getIntent() + ": process is bad";
  31. Slog.w(TAG, msg);
  32. bringDownServiceLocked(r);
  33. return msg;
  34. }
  35. }
  36. ... ...
  37. return null;
  38. }

这个方法做了两件事:

  1. 如果SystemUIService所属进程已经存在,则直接调用realStartServiceLocked()

  2. 如果SystemUIService所属进程不存在,则执行startProcessLocked()方法创建进程,经过层层调用,最终也会走到realStartServiceLocked()中:

  1. private final void realStartServiceLocked(ServiceRecord r,
  2. ProcessRecord app, boolean execInFg) throws RemoteException {
  3. ... ...
  4. try {
  5. ... ...
  6. app.thread.scheduleCreateService(r, r.serviceInfo,
  7. mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
  8. app.getReportedProcState());
  9. r.postNotification();
  10. created = true;
  11. }
  12. }

这个方法内部调用了app.thread.scheduleCreateService(),而app.thread是一个IApplicationThread类型的,他的实现是ActivityThread的一个内部类ApplicationThread,而这个类正好实现了IApplicationThread.Stub在ApplicationThread类中,找到对应的调用方法:

  1. public final void scheduleCreateService(IBinder token,
  2. ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
  3. updateProcessState(processState, false);
  4. CreateServiceData s = new CreateServiceData();
  5. s.token = token;
  6. s.info = info;
  7. s.compatInfo = compatInfo;
  8. sendMessage(H.CREATE_SERVICE, s);
  9. }

可以看出,是发送一个消息给Handler,这个HandlerActivityThread的内部类H

  1. public void handleMessage(Message msg) {
  2. switch (msg.what) {
  3. ... ...
  4. case CREATE_SERVICE:
  5. if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
  6. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
  7. ("serviceCreate: " + String.valueOf(msg.obj)));
  8. }
  9. handleCreateService((CreateServiceData)msg.obj);
  10. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
  11. break;
  12. ... ...
  13. }
  14. }

最终调用了handleCreateService()方法:

  1. private void handleCreateService(CreateServiceData data) {
  2. LoadedApk packageInfo = getPackageInfoNoCheck(
  3. data.info.applicationInfo, data.compatInfo);
  4. Service service = null;
  5. try {
  6. //创建service的context
  7. ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
  8. //创建Application
  9. Application app = packageInfo.makeApplication(false, mInstrumentation);
  10. //获取类加载器
  11. java.lang.ClassLoader cl = packageInfo.getClassLoader();
  12. //加载service实例
  13. service = packageInfo.getAppFactory()
  14. .instantiateService(cl, data.info.name, data.intent);
  15. // Service resources must be initialized with the same loaders as the application
  16. // context.
  17. context.getResources().addLoaders(
  18. app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
  19. context.setOuterContext(service);
  20. //初始化service
  21. service.attach(context, this, data.info.name, data.token, app,
  22. ActivityManager.getService());
  23. //调用service的onCreate方法
  24. service.onCreate();
  25. mServices.put(data.token, service);
  26. try {
  27. //通过serviceDoneExecuting告知AMS,service已经启动完成
  28. ActivityManager.getService().serviceDoneExecuting(
  29. data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
  30. } catch (RemoteException e) {
  31. throw e.rethrowFromSystemServer();
  32. }
  33. } catch (Exception e) {
  34. if (!mInstrumentation.onException(service, e)) {
  35. throw new RuntimeException(
  36. "Unable to create service " + data.info.name
  37. + ": " + e.toString(), e);
  38. }
  39. }
  40. }

这个方法主要做了以下几件事:

  1. 首先,创建上下文

  2. 创建SystemUIApplication,获取类加载器

  3. 加载SystemUIService实例,初始化SystemUIService, 调用onCreate()方法

  4. 最后通知AMSSystemUIService启动完成。

到这里SystemUIService已经启动完成。

第五步: 前面在SystemUIApplication创建成功后会回调内部的OnCreate()方法,在OnCreate()中方法注册了一个开机广播,当接收到开机广播后会调用SystemUIonBootCompleted()方法来告诉每个子模块 Android 系统已经完成开机。

  1. @Override
  2. public void onCreate() {
  3. super.onCreate();
  4. Log.v(TAG, "SystemUIApplication created.");
  5. // 设置所有服务继承的应用程序主题。
  6. // 请注意,在清单中设置应用程序主题仅适用于activity。这里是让Service保持与主题设置同步。
  7. setTheme(R.style.Theme_SystemUI);
  8. if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
  9. IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
  10. bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
  11. registerReceiver(new BroadcastReceiver() {
  12. @Override
  13. public void onReceive(Context context, Intent intent) {
  14. if (mBootCompleteCache.isBootComplete()) return;
  15. if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
  16. unregisterReceiver(this);
  17. mBootCompleteCache.setBootComplete();
  18. if (mServicesStarted) {
  19. final int N = mServices.length;
  20. for (int i = 0; i < N; i++) {
  21. mServices[i].onBootCompleted(); //通知SystemUI子模块
  22. }
  23. }
  24. }
  25. }, bootCompletedFilter);
  26. ...
  27. } else {
  28. // 我们不需要为正在执行某些任务的子进程启动服务。
  29. ...
  30. }
  31. }

2.2 SystemUI 中的流程

第六步:SystemUIService初始化完成后会调用onCreate()方法,onCreate()中调用了SystemUIApplication中的startServiceIfNeeded()方法完成SystemUI子模块的初始化。

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

  1. public class SystemUIService extends Service {
  2. ... ...
  3. @Override
  4. public void onCreate() {
  5. super.onCreate();
  6. // Start all of SystemUI
  7. ((SystemUIApplication) getApplication()).startServicesIfNeeded(); //调用startServicesIfNeeded()
  8. ... ...
  9. }
  10. }

第七步:SystemUIApplicationstartServicesIfNeeded()方法中,通过SystemUIFactory获取到配置在config.xml中每个子模块的className

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

  1. // SystemUIApplication
  2. public void startServicesIfNeeded() {
  3. String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
  4. startServicesIfNeeded("StartServices", names);
  5. }
  6. // SystemUIFactory
  7. /** Returns the list of system UI components that should be started. */
  8. public String[] getSystemUIServiceComponents(Resources resources) {
  9. return resources.getStringArray(R.array.config_systemUIServiceComponents);
  10. }

config.xml 位置:/frameworks/base/packages/SystemUI/res/values/config.xml

  1. <!-- SystemUI Services: The classes of the stuff to start. -->
  2. <string-array name="config_systemUIServiceComponents" translatable="false">
  3. <item>com.android.systemui.util.NotificationChannels</item>
  4. <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
  5. <item>com.android.systemui.recents.Recents</item>
  6. <item>com.android.systemui.volume.VolumeUI</item>
  7. <item>com.android.systemui.stackdivider.Divider</item>
  8. <item>com.android.systemui.statusbar.phone.StatusBar</item>
  9. <item>com.android.systemui.usb.StorageNotification</item>
  10. <item>com.android.systemui.power.PowerUI</item>
  11. <item>com.android.systemui.media.RingtonePlayer</item>
  12. <item>com.android.systemui.keyboard.KeyboardUI</item>
  13. <item>com.android.systemui.pip.PipUI</item>
  14. <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
  15. <item>@string/config_systemUIVendorServiceComponent</item>
  16. <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
  17. <item>com.android.systemui.LatencyTester</item>
  18. <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
  19. <item>com.android.systemui.ScreenDecorations</item>
  20. <item>com.android.systemui.biometrics.AuthController</item>
  21. <item>com.android.systemui.SliceBroadcastRelayHandler</item>
  22. <item>com.android.systemui.SizeCompatModeActivityController</item>
  23. <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
  24. <item>com.android.systemui.theme.ThemeOverlayController</item>
  25. <item>com.android.systemui.accessibility.WindowMagnification</item>
  26. <item>com.android.systemui.accessibility.SystemActions</item>
  27. <item>com.android.systemui.toast.ToastUI</item>
  28. </string-array>

第八步:startServicesIfNeeded()中通过反射完成了每个SystemUI组件的创建,然后再调用各个SystemUIonStart()方法来继续执行子模块的初始化。

  1. private SystemUI[] mServices;
  2. private void startServicesIfNeeded(String metricsPrefix, String[] services) {
  3. if (mServicesStarted) {
  4. return;
  5. }
  6. mServices = new SystemUI[services.length];
  7. ...
  8. final int N = services.length;
  9. for (int i = 0; i < N; i++) {
  10. String clsName = services[i];
  11. if (DEBUG) Log.d(TAG, "loading: " + clsName);
  12. try {
  13. SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
  14. if (obj == null) {
  15. Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
  16. obj = (SystemUI) constructor.newInstance(this);
  17. }
  18. mServices[i] = obj;
  19. } catch (ClassNotFoundException
  20. | NoSuchMethodException
  21. | IllegalAccessException
  22. | InstantiationException
  23. | InvocationTargetException ex) {
  24. throw new RuntimeException(ex);
  25. }
  26. if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
  27. // 调用各个子模块的start()
  28. mServices[i].start();
  29. // 首次启动时,这里始终为false,不会被调用
  30. if (mBootCompleteCache.isBootComplete()) {
  31. mServices[i].onBootCompleted();
  32. }
  33. }
  34. mServicesStarted = true;
  35. }

这里的SystemUI是一个抽象类,状态栏、近期任务等等模块都是继承自SystemUI,通过这种方式可以很大程度上简化复杂的SystemUI程序中各个子模块创建方式,同时我们可以通过配置资源的方式动态加载需要的SystemUI模块。

SystemUI的源码如下,方法基本都能见名知意,就不再介绍了。

  1. public abstract class SystemUI implements Dumpable {
  2. protected final Context mContext;
  3. public SystemUI(Context context) {
  4. mContext = context;
  5. }
  6. public abstract void start();
  7. protected void onConfigurationChanged(Configuration newConfig) {
  8. }
  9. @Override
  10. public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
  11. }
  12. protected void onBootCompleted() {
  13. }

2.3 CarSystemUI 的启动流程

前文提到CarSystemUI复用了手机SystemUI的代码,所以CarSystemUI的启动流程和SystemUI的是完全一致的。

CarSystemUI中需要的功能与SystemUI中也有部分差异,那么是这些差异化的功能是如何引入并完成初始化?以及一些手机的SystemUI才需要的功能是如何去除的呢?

其实很简单,在SystemUI的启动流程中我们得知,各个子模块的 className 是通过SystemUIFactorygetSystemUIServiceComponents()获取到的,那么只要继承SystemUIFactory并重写getSystemUIServiceComponents()就可以了。

  1. public class CarSystemUIFactory extends SystemUIFactory {
  2. @Override
  3. protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
  4. return DaggerCarSystemUIRootComponent.builder()
  5. .contextHolder(new ContextHolder(context))
  6. .build();
  7. }
  8. @Override
  9. public String[] getSystemUIServiceComponents(Resources resources) {
  10. Set<String> names = new HashSet<>();
  11. // 先引入systemUI中的components
  12. for (String s : super.getSystemUIServiceComponents(resources)) {
  13. names.add(s);
  14. }
  15. // 再移除CarsystemUI不需要的components
  16. for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsExclude)) {
  17. names.remove(s);
  18. }
  19. // 最后再添加CarsystemUI特有的components
  20. for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsInclude)) {
  21. names.add(s);
  22. }
  23. String[] finalNames = new String[names.size()];
  24. names.toArray(finalNames);
  25. return finalNames;
  26. }
  27. }
  1. <!-- 需要移除的Components. -->
  2. <string-array name="config_systemUIServiceComponentsExclude" translatable="false">
  3. <item>com.android.systemui.recents.Recents</item>
  4. <item>com.android.systemui.volume.VolumeUI</item>
  5. <item>com.android.systemui.stackdivider.Divider</item>
  6. <item>com.android.systemui.statusbar.phone.StatusBar</item>
  7. <item>com.android.systemui.keyboard.KeyboardUI</item>
  8. <item>com.android.systemui.pip.PipUI</item>
  9. <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
  10. <item>com.android.systemui.LatencyTester</item>
  11. <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
  12. <item>com.android.systemui.SliceBroadcastRelayHandler</item>
  13. <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
  14. <item>com.android.systemui.accessibility.WindowMagnification</item>
  15. <item>com.android.systemui.accessibility.SystemActions</item>
  16. </string-array>
  17. <!-- 新增的Components. -->
  18. <string-array name="config_systemUIServiceComponentsInclude" translatable="false">
  19. <item>com.android.systemui.car.navigationbar.CarNavigationBar</item>
  20. <item>com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier</item>
  21. <item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
  22. <item>com.android.systemui.car.volume.VolumeUI</item>
  23. </string-array>

通过以上方式,就完成了CarSystemUI子模块的替换。

2.4 小结

总结一下,SystemUI的大致启动流程可以归纳如下:

8622528ecec2330fd3e0500d7539ec4c.jpeg

SystemUI 是一个 persistent 应用,它由操作系统启动,主要流程为

  • Android 系统在开机后会创建 system_server 进程,它会启动各种系统所需要的服务,其中就包括 SystemUIService

  • SystemUIService 启动后进入到应用层 SystemUI 中,在 SystemUIApplication 它首先会初始化监听ACTION_BOOT_COMPLETED 等通知,待系统完成启动后会通知各个组件 onBootCompleted

  • 在进入 SystemUIService 中依然执行的 SystemUIApplication 中的startServicesIfNeeded() 方法启动 SystemUI 中的子模块。

  • 最终的服务启动逻辑都是在 SystemUIApplication 里面,并且都保存在 mServices 数组中。

三 总结

SystemUI在原生的车载 Android 系统是一个较为复杂的模块,本文主要介绍了SystemUICarSystemUI的功能、源码结构及启动时序,希望能帮到从事SystemUI开发的同学。

关注我获取更多知识或者投稿

dd70a4dede93ca65510dc3f1ce61111d.jpeg

1bc4c550baf20f3d8a92d83752ba277e.jpeg

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号