Android 8.0学习(27)--- SystemUI(二)启动流程和初始化
Android 8.0 SystemUI(二):启动流程和初始化
这篇的话,将对SystemUI的启动和大体的初始化作描述。篇幅应该比上篇多了些。哈哈。
老样子,先上目录,简洁明了。
概述
由于需要实时反馈系统状态,如蓝牙开关、wifi开关、时间及相应用户导航栏操作,SystemUI从系统一启动就被带起来了(SystemUI:我也不想啊!老累了!)。正常使用过程中的SystemUI,大多数功能模块都是出于运行状态,只有少数功能,比如:截屏功能,你长按电源+音量下键才会咔嚓截屏。
这里简要说下系统启动过程:由init进程->Zygote进程->SystemServer进程。
那init进程又是怎么起来的?当你按下电源键,系统上电,从固定地址开始加载固化在ROM的Bootloader代码到RAM中并执行,Bootloader引导程序负责将系统OS拉起。当系统OS被拉起,并完成一些列初始化和系统设置后,就会首先在系统文件中寻找“init”文件并启动这个咱们用户空间的第一个进程。
Emmm,扯远了,回到主题。按照一开始的系统启动过程,我们的SystemUI进程是在SystemServer的启动过程中被带起来。
从第一篇介绍我们知道,SystemUI有着很多的模块且对应着相应的界面。这些模块有些共同的地方,例如都需要:
- 处理各自模块的初始化
- 处理系统的状态变化
- 执行dump
- 系统启动完成时,要处理相应逻辑
所以在代码中体现为:将这些共同点提取并抽象,形成SystemUI抽象类,结构如下。
简单对这段代码说明下:
- 为子类定义了一个start方法供子类完成初始化,这个方法是一个抽象方法,因此具体的子类必现实现。
- onConfigurationChanged是处理系统状态变化的回调,这里的状态变化包括:时区变更,字体大小变更,输入模式变更,屏幕大小变更,屏幕方向变更等。
- 系统中很多的模块都包含了dump方法。dump方法用来将模块的内部状态dump到输出流中,这个方法主要是辅助调试所用。开发者可以在开发过程中,通过adb shell执行dump来了解系统的内部状态。
- onBootCompleted是系统启动完成的回调方法。
除了截屏服务,提及模块均继承抽象类SystemUI并在应用启动时被分别初始化。从这种角度来看,SystemUI应用更像是这些功能模块的容器。
值得一提的是,和Nougat相比,在Oreo中,抽象类SystemUI的两个子类:BaseStatusBar和PhoneStatusBar被合并替换成了StatusBar.java。相信了解接触过SystemUI模块的老司机对PhoneStatusBar这个核心类一定很熟悉和,现在也尘归尘、土归土咯。
二、SystemUI启动流程
SystemServer负责系统中各种重要服务的启动,不巧,由于SystemUI的重要性,她也在被启动之列,虽然是处于“Other”的地位~(SystemServer的代码对系统服务类别大体分为三类:Bootstrap->Core->Other,SystemUI的启动就在Other中)。
在startOtherServices()中,通过调用AMS的systemReady()方法通知AMS准备就绪。systemReady()拥有一个名为goingCallback的Runnable实例作为参数,So,当AMS完成对systemReady()的处理后将会回调这一Runnable的run()方法。
private void startOtherServices() {... //省略大概1000行mActivityManagerService.systemReady(() -> {Slog.i(TAG, "Making services ready");...traceBeginAndSlog("StartSystemUI");try {startSystemUi(context, windowManagerF);} catch (Throwable e) {reportWtf("starting System UI", e);}...}
}
并在startSystemUi方法中,通过红框中的组件名启动了SystemUI中的SystemUIService服务
对于Android系统来说,当一个应用启动,系统会保证其Application类是第一个被实例化的类,并且Application的onCreate方法,一定先于应用中所有的Activity,Service和BroadcastReceiver的创建。
SystemUI中,SystemUIApplication就是第一个被实例化的类。
在其中,定义了两组服务:
- 一类是所有用户共用的SystemUI服务,例如:Status Bar
- 一类是每个用户独有的服务
下面的两个数组记录了这两组服务
前面也提到,SystemUI抽取了功能模块的共性形成抽象类SystemUI.class,上图中所有列出的类型,均是SystemUI的子类实现。
接着说,在SystemUIApplication中,onCreate方法被调用:主要注册一个广播接收器,用以接收BOOT_COMPLETED广播,在接收到广播后,调用各模块的函数onBootCompleted。
你还记的SystemServer中启动SystemUI的代码不?那个目标是SystemUIService的Intent。
当SystemApplication家的onCreate执行完毕,就会去启动这个SystemUIService。按照规矩,此服务onCreate方法在启动时被调用。
不研究不知道,哇靠,这家伙只是个中转代理(给别人一个启动你的机会)而已~,不信你看,实际代码只有下面一行,看下图。
整个服务,真正干活的只有红框中的一句话。仔细瞅瞅,调用的是SystemUIApplication中的startServicesIfNeeded方法,转了一圈又回来了。
这就是启动各模块的地方。
private void startServicesIfNeeded(Class<?>[] services) {if (mServicesStarted) {return;}if (!mBootCompleted) {// check to see if maybe it was already completed long before we began// see ActivityManagerService.finishBooting()if ("1".equals(SystemProperties.get("sys.boot_completed"))) {// sys.boot_completed属性值,在系统boot完成后,AMS会对其进行设置mBootCompleted = true;if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");}}Log.v(TAG, "Starting SystemUI services for user " + Process.myUserHandle().getIdentifier() + ".");final int N = services.length;for (int i = 0; i < N; i++) {Class<?> cl = services[i];if (DEBUG) Log.d(TAG, "loading: " + cl);try {// SystemUIFactory类在6.0上还没有,是7.0上出现的,目的是为了提供可定制化的SystemUIObject newService = SystemUIFactory.getInstance().createInstance(cl);mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} catch (InstantiationException ex) {throw new RuntimeException(ex);}// 对数组中的每一个Service都进行初始化mServices[i].mContext = this;mServices[i].mComponents = mComponents;if (DEBUG) Log.d(TAG, "running: " + mServices[i]); mServices[i].start();if (mBootCompleted) {mServices[i].onBootCompleted();}}...
}
对于SystemUI App启动,这里总结了一张启动时序图给大家参考,如下所示:
进一步的话,就到了各个模块独自的初始化逻辑了。
这里我们单独对SystemBars的初始进行进一步的说明。
三、e.g. SystemBars
SystemBars主要包含了NavigationBar和StatusBar,不知道这两个Bar对应位置的同学可以看下第一篇『图文并茂的介绍:D』。
Show the code:
public class SystemBars extends SystemUI {private static final String TAG = "SystemBars"; private static final boolean DEBUG = false; private static final int WAIT_FOR_BARS_TO_DIE = 500; // in-process fallback implementation, per the product configprivate SystemUI mStatusBar; @Overridepublic void start() { if (DEBUG) Log.d(TAG, "start"); createStatusBarFromConfig();} @Overridepublic void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mStatusBar != null) { mStatusBar.dump(fd, pw, args);}} private void createStatusBarFromConfig() { if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");final String clsName = mContext.getString(R.string.config_statusBarComponent); if (clsName == null || clsName.length() == 0) {throw andLog("No status bar component configured", null);} Class<?> cls = null; try { cls = mContext.getClassLoader().loadClass(clsName);} catch (Throwable t) { throw andLog("Error loading status bar component: " + clsName, t);} try { mStatusBar = (SystemUI) cls.newInstance();} catch (Throwable t) { throw andLog("Error creating status bar component: " + clsName, t);} mStatusBar.mContext = mContext; mStatusBar.mComponents = mComponents; mStatusBar.start(); if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());} private RuntimeException andLog(String msg, Throwable t) {Log.w(TAG, msg, t);throw new RuntimeException(msg, t);}
}
这段代码说明如下:
- start方法由SystemUIApplication调用
- 调用createStatusBarFromConfig方法,根据配置文件中的信息来进行Status Bar的初始化
- 读取配置文件中实现类的类名。这个值于frameworks/base/packages/SystemUI/res/values/config.xml中定义。在手机中,其值是:com.android.systemui.statusbar.phone.StatusBar
- 通过类加载器加载对应的类
- 通过反射API创建对象实例
- 最后调用实例的start方法对其进行初始化。如果是手机设备,这里就是StatusBar.start方法
为什么要读取资源文件获取类名并通过反射来创建实例呢?
好处是:
这里将类名配置在资源文件中,那么对于Tv和Car这些不同的平台,可以不用修改任何的代码,只需要修改配置文件,便替换了系统中状态栏的实现,由此减少了模块间的耦合,也减少了系统的维护成本。
值得我们借鉴。
好了,SystemUI的启动到这里就结束了,具体SystemBars以及StatusBar都做了些什么,后续会进行跟进。
Android 8.0学习(27)--- SystemUI(二)启动流程和初始化相关推荐
- Android 8.0 学习(23)---recovery 流程分析
Android 8.0 recovery 流程分析 这里主要分析non A/B模式下的recovery流程 A/B模式下的recovery在boot中 后续会不断补充,如果有疏漏或者错误的地方,请 ...
- Android 9.0系统源码_SystemUI(一)SystemUI的启动流程
一.SystemUI 介绍 1.初步认识SystemUI Android 的 SystemUI 其实就是 Android 的系统界面,它包括了界面上方的状态栏 status bar,下方的导航栏Nav ...
- Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]
摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...
- Tensorflow2.0学习笔记(二)
Tensorflow2.0学习笔记(二)--Keras练习 文章目录 Tensorflow2.0学习笔记(二)--Keras练习 前言 二.使用步骤 1.实现步骤及代码 2.下载 Fashion MN ...
- Tensorflow2.0学习笔记(二)北大曹健老师教学视频第五讲
Tensorflow2.0学习笔记(二)北大曹健老师教学视频第五讲 返回目录 理论部分主要写点以前看吴恩达视频没有的或者不太熟悉的了. 5.1卷积计算过程 实际项目中的照片多是高分辨率彩色图,但待优化 ...
- Launcher启动流程及初始化
前言 前面我们学习了SystemServer的启动流程,也了解了AMS是如何启动起来并通过Binder注册到ServiceManger内的,OK,本文基于这俩篇基础继续来学习Launcher. Lau ...
- JPOM - Server启动流程脚本初始化源码解析
文章目录 地址 版本 Server启动流程&脚本初始化流程 地址 Gitee: https://gitee.com/dromara/Jpom 官网: https://jpom.io/ 一款简而 ...
- 分析Spring容器启动流程 Spring初始化
分析Spring容器启动流程 Spring初始化 每当启动Web容器时(例如Tomcat),会读取Web应用中的web.xml文件.以下这段代码就是启动Spring容器的关键代码. ContextLo ...
- Android 8.0 学习(26)---Android 8.0 SystemUI(一)
Android 8.0 SystemUI(一):图文并茂的介绍 : 文章已同步更新至微信公众号:猿湿Xoong 我擅长什么? 当我想到这个这个问题的时候,脑子里是一片空白的:哎呀,我什么都知道点,可是 ...
最新文章
- Centos系统上安装php遇到的错误解决方法集锦
- 意外发现:网盾升级后支持soso和有道
- bob-tong 字符串函数之Strtok()函数
- html表单提交不判断,请问jquery有方法可以判断一个表单提交之后结果是成功或不成功吗?...
- 5v继电器模块实物接线_电气工程师都收藏的西门子S71200PLC接线图设计大全
- csgo跳投指令_csgo跳投绑定指令
- Nginx配置单项SSL以及双向SSL
- canvas--绘制路径
- js并列排名之div图片加载
- 堆载预压弹性变形怎样计算公式_真空预压排水固结法原理特点与优缺点
- 什么是索引?怎么创建索引?索引的使用原则?
- 怎么制作U盘启动盘来安装系统
- 4D领导力打造卓越团队
- 【论文阅读】DNS隧道攻击检测算法整合
- 个人电脑网站的创建与发布
- html用九张图片做出九宫图,九宫切图软件 如何快速把照片做成九宫格切图
- 餐馆会员管理系统 - MySQL数据库课程设计
- 《乐队的夏天》刺猬乐队下半年音乐节巡演时间表
- docker-compose 安装多版本php
- python脚本AttributeError: module 'xxxx' has no attribute 'xxxxx'错误解决办法
热门文章
- 使用LD链接时候文件的顺序
- java中jnum i .length,java数组和多维数组
- linux nmon 进程io,linux监控占用磁盘IO进程的工具
- php表单密码由加密变明文,PHP 安全性漫谈 Linux+Apache+Mysql+PHP
- git获得当前分支url_笔记本拿出来!软件工程师必须要知道的Git命令语句大汇总...
- H5 Canvas maximum-scale图像模糊解决办法
- UWP锁、解屏后无法响应操作
- Android sdk 搭建
- 关于qq创始人----马化腾的一些琐事
- python面试题之补充缺失的代码