安卓底层开发学习经验第十九期

这一期我们来学习Android bootanim 的一个启动过程
首先我们来看一下 Android bootanim 的一个启动过程:首先我们会在 init.rc 中定义一个 bootanim 的服务,这个服务在最开始是被 disable 掉的,是因为我们 Android 的显示需要依赖于 Android 系统的 surface 管理服务,所以我们必须等待整个显示的硬件初始化完成,软件初始化完成,然后才能真正的试用 Android 的显示机制去做显示,而这个机制就是依赖于我们 surface 的服务。当显示这个服务初始化完成之后,第一件事就是调用 start 命令,将 bootanim 这个服务启动,然后 bootanim 得到我们的 surfaceflinge 服务,然后去刷开机界面,这是就能看到屏幕上有显示,这个现实并不是 zygote 启动主 lunch 的一个显示,这个显示是使用 OpenGLES 这种操作实现的。首先他会得到 surfaceflinge 中的一层,然后调用 OpenGL 显示的操作,去把他相应的一些图片刷出来,这个就是 bootanim 的一个显示过程。
那么当我们打开一个 Android 设备,手机或者电视,在打开之后会有第一幅图片,这个图片都是我们在 uboot 或者内核中来显示的第一幅图,给人的第一印象就是启动很快,因为 UI 很快刷出来,也就是那个闪烁一次的 Android 图片,这个界面就是 bootanim 来操作的,他调用的是 OpenGLES 的一些操作来显示的,在显示过程中我们会发现,当我们的祝 home 界面启动之后,我们这些刷简单 Android 图片的这些界面就会消失,这个过程是因为当 system_server 他启动系统 HomeUI 的时候关闭了 bootanim 。这就是我们整个 Android 系统启动过程中 UI 显示的一个过程。
下面我们来看一下 bootanim 的一个启动和退出的框架图

在这个框架图中,我们会涉及到下面几个服务,第一个是我们的 init 进程,第二个是 surfaceflinge Service 服务,第三个是 bootanim 服务,第四个是 Zygote 进程,最后一个就是 System_service 服务,我们来看一下他们整个交互流程是怎样的。
首先我们的 init 进程会创建 surfaceflinge Service 和我们的 Zygote 服务,而 surfaceflinge Service 这个服务主要是初始化我们显示部分,管理我们显示的分层。当我们 surfaceflinge  这个服务初始化完成之后,他就会调用我们的 startBootAnim ,他调用的过程就是启动 bootanimation ,启动之后他就开始和我们的 surfaceflinge Service 进行交互,然后得到一个显示的层,然后他会根据自己的一个显示机制去刷新我们的屏幕。在做这些相关操作的同时,我们的 init 进程还孵化出了我们的 zygote 服务,而我们的 zygote 服务,它主要是创建我们 java 层的主要服务和应用,其中最主要的服务就是我们的 System_service 服务,他用于启动我们整个 Android 系统 java 层的服务,在我们启动过程中会启动一个 ActvityManagerService 服务,它用来管理我们所有的应用,在启动过程中,他最后会调用 startHomeActivityLocked 这个应用,他就会真正的启动我们系统的一个 lunch ,在启动过程中,他会申请一个相关的显示,而这个显示是由 WindowManagerService 来完成的。当我们的 startHomeActivityLocked 启动完成之后,他就会向我们的 WindowManagerService 发送一个消息,这个消息就是我们的 bootFinished ,也就是我们整个系统可以正常运行了,调用这个之后我们的 WindowManagerService 就会向 surfaceflinge Service 这个服务发送一个消息,这个消息就是 bootFinished ,当我们的 surfaceflinge Service 拿到这个消息之后,他会做一件事情,将我们的 service.bootanim.exit 设置成 1 ,而我们的 bootanimation 在不断刷新界面过程中,会实时检查 service.bootanim.exit 的值,如果这个值是 1 ,那么 bootanimation 就会退出当前刷新,因为我们系统的主 UI 已经起来了,他的使命也就完成了,然后就会显示 Android 系统的主 lunch ,这就是我们 bootanim 的一个启动过程。
下面我们再来看一下 bootanim 的一个工作流程

首先我们会创建一个bootanimation 的一个对象,然后调用他的 readyToRun 来做一下初始化工作,主要是申请一个 surface ,然后初始化 opengles ,这个过程我们还要和 surfaceflinge Service 打一个交道,当我们的初始化完成之后,就会根据我们的系统设置来决定是使用 Android 这种方式来进行显示,还是用 movie 来进行显示,这两种方式显示的过程是一样的,只不过显示内容是不一样的,我们的显示内容是一个 zip 包的格式,这个包会有我们的图片文件,我们的 png 文件,然后还有一个相关的配置,也就是我们的 configure 文件,当我们显示之前,我们首先会得到整个显示文件的信息,包括显示的大小,长和宽,以及显示的帧率,和我们显示图片的资源。配置之后,我们就会调用 opengles 的一些方法,然后再对我们这些图像进行处理,真正的显示。在显示过程中我们也会检查我们退出的 priority ,当我们检查到 priority 的设置为 true 的话,那我们就会直接退出,这些就是 bootanimation 的一个工作流程。
下面我们打开我们的 bootanimation 的代码,他的源文件在 frameworks/base/cmds/bootanimation/bootanimation_main.cpp

我们来看一下main 函数,首先会得到一个 priority ,看是否要显示我们的 bootanimation ,如果说我们的 noBootAnimation 是假的话,那么我们就要做一个 bootanimation 的显示过程,首先我们会创建一个 ProcessState 对象,然后启动我们一个线程池,创建了一个 bootanimation 的对象,在创建过程中,我们就会把这个对象添加到线程池中,然后去做一下相关工作,在这个 new BootAnimation 过程中,他会做下面的操作,这个函数继承了 Thread 这个类,这个类呢,当我们初始化的时候会有一个强指针,也就是强制的执行 onFirstRef 这个函数,在这里边他会做一些相关的操作,做完之后他还会做一个 readyToRun 的工作

readyToRun 第一个就会和我们的 surfaceflinge 服务做一个交互,拿到一个显示的层,他会创建一个 surfaceComposerClient ,这就是我们 surface 的一个客户端,然后通过 binder 机制向我们的 surfaceservice 拿到显示的层,拿到之后他会创建一个显示的宽和高,以及各式,并且把显示的 layer 也给设置上,设置好之后就会开始做一些 opengles 的工作,这些工作都是标准的 opengles 的函数当我们把 opengles 初始化完成之后,代码就会决定,我们是使用 Android 的方式还是使用 movie 的方式来刷新界面,他在这里会判断下面几个目录,我们来看一下他们的定义

如果有这个 system/media/bootanimation-encrypted.zip 包的话,那么我们启动的时候就会刷新这个 zip 包,如果说我们的 zip 包是 system/media/bootanimation.zip 的话,那么就会刷新这个包,如果 zip 包时 date/local/bootanimation.zip 的话,那么就会刷新这个包,如果没有,那么我们就会刷新我们 Android 默认的 zip 包。
当我们判断完之后呢,我们的 mZip 对象就会是一个全局的,所以他会保存起来,然后在这里边如果有一个条件为真的话,那么我们就会调用我们 movie 的方法去刷新界面,当我们把这个 init 所有初始化完成之后呢,我们就会进入到我们的 threadLoop ,他会在这里真正的刷新我们的界面,

这个 mAndroidAnimation 变量,决定了我们是使用 Android 方法还是 movie 的方法来刷新界面,我们在这里应该是使用的 movie 的方法,下面我们来看一下 movie 的方法。

这个方法第一个就是拿到我们的zip 包,然后进行一下相关的分析,包括我们的配置文件,以及图片信息,然后会解析我们的配置文件,包括我们显示的宽度、高度、帧率,以及后面所显示的一个频率。当我们把配置文件解析完成之后,就开始获取到我们一些图片的信息,这个就是我们获取图片信息的一个过程,把这些图片全部加载过来,加载完成之后我们就会用 opengles 将屏幕进行清屏,然后就会用一个 for 循环不断地刷新界面,这些刷新的过程都是调用 opengles 的过程,我们在刷新的过程中还会不断地检查我们的环境变量是否已经设置为退出,当我们检查完退出之后,我们的刷新过程也就完成了,然后退出 movie ,然后做一些清理工作,然后直接返回,返回之后我们整个 bootanimation 的启动过程以及刷新过程就结束了,这个服务也就停止了,这就是 bootanimation 的一个执行过程。
下面我们来看 surfaceflingeservice 是如何来启动和停止 bootanimation 的。我们来打开 frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp ,找到他的 main 函数

首先他也会初始化一个 ProcessState ,这个就是 binder 的一个机制,然后会启动一个线程池,启动完之后创建了一个 surfaceflinger 的一个对象,当这个对象创建完之后会调用他的 init 方法。这个 init 方法主要是对我们 opengles 做一些设置,根据我们硬件的配置来设置我们的参数,当我们整个 surfaceflinger 初始化完成之后呢,在最后就会调用 startBootAnim ,它主要做了两件事情,第一设置我们的 service.bootanim.exit 0 ,也就是现在需要不断地刷新我们的屏幕,第二个就是启动了我们的 bootanim 这个服务,我们启动 bootanim 用的就是 startBootAnim 这个方法。我们 bootanim 的退出也是在这个类中来实现的,当我们的主 lunch 启动之后呢,他就会向我们的 surfaceflinger 来发送消息,说我们的 boot 已经 finished ,这时候我们的 surfaceflingerservice 就会调用我们的 bootFinished 来将我们的 bootanim 停止,他停止所做的事情就是将我们的 service.bootanim.exit 设置为 1 ,设置好之后我们的 bootanim 就退出了。这就是 bootanimation 启动、执行、退出的一个过程。
下面我们来看一下 bootanimation.zip 这个包里面的内容,和配置文件的一个格式,首先要切到 adb 下把我们板子上的这个包给 pull 下来

然后我们来看一下这个文件,我们先将他解压出来,

可以看到他有三个文件,我们来看一下desc.txt

我们再来看一下这些数字代表什么意思

我们的 part0 part1 就是我们显示的图片,我们就不再看了
这样我们就会知道,我们 bootanimation.zip 的格式了

下面我们来看一下如何制作我们的 bootanimation.zip ,首先我们要替换显示的图片,然后按自己的喜好来修改 desc.txt 的配置,修改完之后我们就直接压缩这个 zip 包,压缩时要注意格式为存储的格式,不能直接压缩
现在我们自己的zip 压缩包就弄完了,我们可以在板子上替换成自己的压缩包,那么在开机时就会显示我们自己的图片了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值