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"><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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/736896.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mybatisplus的条件构造器

条件构造器wrapper&#xff0c;主要用于构造sql语句的where条件&#xff0c;他更擅长这个&#xff0c;但也可以用于构造其他类型的条件&#xff0c;比如order by、group by等。 条件构造器的使用经验&#xff1a; 基于QueryWrapper的查询 练习1. void testQueryWrapper(){Q…

吴恩达机器学习笔记 十八 制定一个性能评估标准 学习曲线 高偏差 高方差

一个模型的好坏的评估基准可以从下面几个方面考虑&#xff1a; 1.考虑人类在这个问题上的表现 2.对比竞争算法的表现 3.根据经验猜测 判断是高偏差还是高方差 训练样本数量越多&#xff0c;越难完美地拟合每个样本&#xff0c;因此 J_train 会逐渐增大一点点&#xff0c;但泛…

线性代数笔记17--行列式及其性质

1. 行列式 符号标识 d e t A ∣ A ∣ det A |A| detA∣A∣ 1.1 基本性质 性质 1 1 1 单位矩阵的行列式为1&#xff1a; d e t I 1 det\ I1 det I1性质 2 2 2 行列式两行交换&#xff0c;行列式取反。 A ⟶ s w a p r o w i , r o w j A ′ d e t A ′ − d e t A A\st…

Rust常用特型之Drop特型

Rust常用特型之Drop特型.md在Rust标准库中&#xff0c;存在很多常用的工具类特型&#xff0c;它们能帮助我们写出更具有Rust风格的代码。 今天&#xff0c;我们主要学习Drop特型。 &#xff08;注&#xff1a;本文更多的是对《Programing Rust 2nd Edition》的自己翻译和理解&…

应届生求职面试注意事项

应届生求职面试注意事项 引言 对于即将毕业的应届生来说&#xff0c;进入职场是一个全新的挑战。在面对众多竞争者的情况下&#xff0c;成功通过面试是获得理想工作的关键一步。本文将介绍一些应届生求职面试的注意事项&#xff0c;帮助应届生更好地应对面试&#xff0c;提高…

算法——滑动窗口之找到字符串中所有的字母异位词,串联所有单词的子串

6.找到字符串中所有的字母异位词 题目:. - 力扣&#xff08;LeetCode&#xff09; 6.1如何快速判断两个字符串是否是异位词 假设现在有s1 aabca,s2 abaca,那么这两个就是异位词,容易想到的判断方法就是将两个字符串按照字典序排序,再依次比较,但是时间复杂度很高;我们看看…

乌干达公司注册优势 乌干达公司注册的条件 乌干达公司注册的流程

乌干达公司注册优势 1、乌干达拥有稳定的政 治环境和开 放的市场经济&#xff0c;为企业提供了良好的发展机遇。 2、乌干达有着优越的地理位置&#xff0c;位于东非内陆&#xff0c;毗邻肯尼亚、坦桑尼亚和刚果&#xff08;金&#xff09;&#xff0c;是通往东非和中非的理想…

精通MySQL:从下载到部署,一切尽在掌握

MySQL数据库下载及安装教程 MySQL是一款广泛应用于各类项目的开源关系型数据库管理系统。它基于Structured Query Language&#xff08;SQL&#xff09;进行数据操作&#xff0c;具有高性能、易使用、成本低等优点。在这篇文章中&#xff0c;我们将向你介绍如何在不同操作系统…

代码随想录算法训练营第五十天| 583. 两个字符串的删除操作 、72. 编辑距离

文章目录 1.两个字符串的删除操作2.编辑距离 1.两个字符串的删除操作 给定两个单词 word1 和 word2&#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步可以删除任意一个字符串中的一个字符。 示例 1&#xff1a; 输入: word1 “sea”, word2 “eat” 输出: 2 …

分享软件项目实施方案模板

本项目在实施过程中将遵守做到以下几个方面&#xff1a; 与建设单位共同完成整个系统软件、网络等设计,负责系统的开发、测试、调试、人员培训、系统的试运行和交付&#xff0c;并保证系统质量。负责系统的维护、应用软件的升级和更新。提出对系统硬件设备的相关技术要求。在项…

vue3 动态路由及使用动态路由后刷新界面出现空白页或者404

最近编写vue3动态路由的功能遇到了一些问题&#xff0c;处理好了&#xff0c;总结出来&#xff0c;希望能帮助到你。正片开始 先写好本地缓存菜单的方法&#xff08;存储、删除、获取&#xff09; // utils/menu.jsconst getMenuList () > {return JSON.parse(localStorag…

MachineSink - 优化阅读笔记

注&#xff1a;该优化与全局子表达式消除刚好是相反的过程&#xff0c;具体该不该做这个优化得看代价模型算出来的结果(有采样文件指导算得会更准确) 该优化过程将指令移动到后继基本块中&#xff0c;以便它们不会在不需要其结果的路径上执行。 该优化过程并非旨在替代或完全…

【大厂AI课学习笔记NO.80】深度学习行业人才能力图谱

深度学习领域的就业岗位及所需关键技术、工具、能力分析 深度学习作为人工智能领域的一个重要分支&#xff0c;近年来得到了飞速的发展。随着技术的不断进步和应用场景的不断拓展&#xff0c;深度学习领域的就业岗位也日益增多。本文将从领军人才、产业研发人才、应用开发人才…

Linux——信号

目录 什么是信号 Linux下的信号 信号的记录 信号处理的常见方式 产生信号 使用组合键产生信号&#xff08;包含core dump&#xff09; 使用系统调用向进程发送信号 由软件条件产生信号 由硬件异常产生信号 阻塞信号 内核表示 sigset_t 信号集操作函数 sigpendin…

jvm八股

文章目录 运行时数据区域Java堆对象创建对象的内存布局对象的访问定位句柄直接指针 GC判断对象是否已死引用计数算法可达性分析算法 引用的类别垃圾收集算法分代收集理论标记清除算法标记复制算法标记整理算法 实现细节并发的可达性分析 垃圾收集器serial收集器ParNew收集器Par…

如何保证 redis 的高并发和高可用?redis 的主从复制原理能介绍一下么?redis 的哨兵原理能介绍一下么?

目录 一、面试官心理分析 二、面试题剖析 1.Redis 主从架构 2.Redis replication 的核心机制 3.Redis 主从复制的核心原理 4.主从复制的断点续传 5.无磁盘化复制 6.过期 key 处理 7.复制的完整流程 8.全量复制 9.增量复制 10.heartbeat 11.异步复制 12.Redis 如何…

【三十】springboot项目上高并发解决示例

互相交流入口地址 整体目录&#xff1a; 【一】springboot整合swagger 【二】springboot整合自定义swagger 【三】springboot整合token 【四】springboot整合mybatis-plus 【五】springboot整合mybatis-plus 【六】springboot整合redis 【七】springboot整合AOP实现日志操作 【…

工程经济学二

一、名词解释 可行性分析&#xff1a; 可行性研究是在投资项目拟建之前&#xff0c;通过对与项目有关的市场、资源、工程技术、经济和社会等方面的问题进行全面分析、论证和评价&#xff0c;从而确定项目是否可行或选择最佳实施方案的一项工作 厂址选择 厂址选择是指在一个大…

Java学习记录(十六):IO流(三)

缓冲流 缓冲流是一种高级流&#xff0c;可以理解为将基本流包装成了这种高级流&#xff0c;而这种高级流的特点就是将一个缓冲区放入到基本流当中&#xff0c;从而提高基本流的效率&#xff0c;但实际进行读写操作的还是基本流 下面为缓冲字节输出流和缓冲字节输入流的应用&am…

2024考研王道计算机408数据结构+操作系统+计算机组成原理+计算机网络

2024考研王道计算机408数据结构操作系统计算机组成原理计算机网络 链-接&#xff1a;https://pan.baidu.com/s/152XLyH64TlcLXwmU-zlAsQ?pwdr7zf 提取码&#xff1a;r7zf 信道利用率在408中经常考察到这里&#xff0c;我给大家总结一下这一类题目的做题方法以及技巧。首先&a…