开机动画分为三个部分:

第一个开机画面是在内核启动的过程中出现的,它是一个静态的画面,在默认情况下,这个画面是不会出现的。

第二个开机画面是在init进程启动的过程中出现的,它也是一个静态的画面。

第三个开机画面是在系统服务启动的过程中出现的,它是一个动态的画面,就是使用比较多的bootanimation模块。

无论是哪一个画面,它们都是在一个称为帧缓冲区(frame buffer,简称fb)的硬件设备上进行渲染的。下图是开机动画从按下power键到开机动画结束的整个流程:

这个部分在代码中主要涉及的文件是:

/frameworks/base/cmds/bootanimation/Android.bp // 该模块的编译规则,在对系统进行全部编译的时候,会首先包含这个bp文件,然后等到编译这个模块时,根据bp文件中的定义,编译出指定的目标内容。

/frameworks/base/cmds/bootanimation/bootanim.rc       // rc文件,用于init主进程拉起该模块

/frameworks/base/cmds/bootanimation/BootAnimation.cpp// 该模块的核心代码

/frameworks/base/cmds/bootanimation/bootanimation_main.cpp // 该模块的主程序入口

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp  //通过它启动与关闭开机动画

安卓开机的第一个用户进程是Init进程,与开机动画进程相关的init进程会完成三件事:1、孵化出ueventd,logd,healthd等用户守护进程;2、启动servicemanager,开机动画等重要服务;3、孵化Zygote进程。首先从bp文件开始解析:

一、Android.bp

一般都是使用bp文件来进行预编译,关于开机动画中的Android.bp中的主要操作是:编译出bootanimation模块的可执行文件并将bootanimation对应的bootanim.rc编译到/system/etc/init目录中。

二、bootanim.rc

bootanim.rc文件中代码如下:

service bootanim /system/bin/bootanimation
//将该bin文件“挂载”到bootanim服务中,可以通过拉起bootanim服务,以执行该bin文件class core animation
//给服务指定为core和animation,这样方便操作多个服务同时启动或停止user graphics                  //在执行此服务之前先切换用户名,当前默认rootgroup graphics audio           //切换用户组disabled                       //服务不会自动运行,必须显式地通过服务器来启动oneshot                        //当此服务退出时不会自动重启ioprio rt 0                    //设置IO优先级为最高task_profiles MaxPerformance   //添加挂载点

添加的挂载点如下:

用来启动应用程序bootanimation的服务是disable的,即init进程在启动的时候,不会主动将应用程序bootanimation启动起来。

三、surfaceFlinger.rc

启动bootanimation是从surfaceFlinger这边来启动的。还是首先看到rc文件,因为init进程会根据这个rc文件规则,去启动位于目标设备/system/bin/surfaceflinger的可执行文件,该文件的内容如下:


四、main_surfaceflinger.cpp

该rc可执行文件的程序入口是surfaceflinger模块的main_surfaceflinger.cpp文件,其main函数,主要的时序图如下:

这部分主要工作就是新建一个SurfaceFlinger对象,然后调用其中的init函数,最后调用run函数。这个地方涉及了几个文件的方法调用,如下:

进入到SurfaceFlinger.cpp里的init()方法,可以看到开启了一个线程,进入这个线程文件/frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp里的内容:

线程体中通过设置系统控制属性ctl.start为bootanim,来启动前面bootanim.rc中定义的bootanim服务:service bootanim /system/bin/bootanimation,以执行bootanimation可执行文件。而设置系统属性service.bootanim.exit为0,则是为了后面终止bootanimation程序做准备,这时就将应用程序bootanimation启动起来了。

(当系统属性发生改变,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理的)


五、bootanimation_main.cpp

启动bootanimation可执行文件后,首先会执行到上面介绍过的bootanimation_main.cpp文件中的main函数:

里面的具体内容如下:

其中的bootAnimationDisabled()函数会检测系统属性,以获取是否播放开机动画的属性值并赋值给noBootAnimation,如果noBootAnimation 为false,则直接退出程序,不进行播放开机动画。否则接下来就会启动一个Binder线程池,并且创建一个BootAnimation对象。这个BootAnimation对象就是用来显示第三个开机画面的。由于BootAnimation对象在显示第三个开机画面的过程中,需要与SurfaceFlinger服务通信,因此,应用程序bootanimation就需要启动一个Binder线程池。调用在BootAnimationUtil.cpp文件中其中的 bootAnimationDisabled()方法如下:

waitForSurfaceFlinger()方法主要做的事是将binder客户端的消息传递给service manager再由service manager寻找一个等待与sufaceFlinger通信的服务。


六、BootAnimation.cpp

在bootAnimation_main中有一个关键的类BootAnimation,这个类属于BootAnimation.cpp文件,解析该文件可以看的BootAnimation类的主要调用关系如下:

BootAnimation类继承了Thread类和IBinder::DeathRecipient类,其中 mSession是BootAnimation类的一个成员变量,它的类型为SurfaceComposerClient,是用来和SurfaceFlinger执行Binder进程间通信。

1、开机动画的启动

onFirstRef()—— 属于其父类RefBase,该函数在强引用sp新增引用计数時调用,就是当有sp包装的类初始化的时候调用;

根据源码可以看到,BootAnimation类间接地继承了RefBase类,并且重写了RefBase类的成员函数onFirstRef,当一个BootAnimation对象第一次被智能指针引用时,这个BootAnimation对象的成员函数onFirstRef就会被调用。BootAnimation类继承了Thread类,当BootAnimation类的成员函数onFirstRef调用了父类Thread的成员函数run之后,系统就会创建一个线程,这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些Thread执行前的初始化工作:

后面再调用BootAnimation类的成员函数threadLoop来显示开机画面,每个线程类都要实现的,在这里定义thread的执行内容。这个函数如果返回true,且没有调用requestExit(),则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。

显示完成之后,就会销毁前面所创建的EGLContext对象mContext、EGLSurface对象mSurface,以及EGLDisplay对象mDisplay等。android()方法里主要是使用方法绘制安卓字样,这边的退出使用的是checkExit();一般使用自定义动画播放,因此主要看一下movie方法里的主要调用方法:

这里使用了loadAnimation()方法:

在loadAnimation方法使用后,播放动画,使用playAnimation方法:

2、开机动画的结束

在playAnimation方法和android方法中都有一个checkExit方法来负责检查是否退出动画;

这边主要是检测service.bootanim.exit的值,当属性值为1的时候,开机动画会requestExit,从而结束开机动画。这个属性值的更改主要涉及以下内容:

开机动画的结束是由系统进程启动AMS管理调度启动Launcher后结束的,因为安卓系统启动首先是启动init进程,init进程启动systemServer进程,该进程启动系统服务AMS,WMS,PMS,IMS,因此首先看到SystemServer.java文件中main方法,调用了run(),而run()中又调用了startBootstrapServices()方法:

启动了ActivityManagerService服务和ActivityTaskManagerService(安卓10以后分出来主要负责Activity的管理和调度),在这个方法中并未启动Launcher,因此往下继续看代码,到startOtherServices方法中,会通知AMS开启systemReady()方法

到ActivityManagerService.java中找到systemReady方法,在这个方法中将Launcher启动起来,当

launcher的主线程处于空闲时,就会向ActivityTaskManagerService发送一个activityIdle的消息:

这个地方的activityIdleInternal是ActivityStackSupervisor.java里的方法,与开机动画相关的方法如下:

这里面的checkFinishBootingLocked()方法会检测开机是否结束:

这个方法是会直接进入到postFinishBooting()中,这个postFinishBooting方法是属于ActivityTaskManagerService.java中:

这个方法中调用了ActivityTaskManagerInternal里的两个抽象类,其中finishBooting是由AMS

enableScreenAfterBoot()方法在ActivityTaskManagerService被重写了如下:

可以看到这里调用了WindowManagerService.java里方法,如下:

在这个方法里又调用了performEnableScreen()如下:

其中调用了 checkBootAnimationCompleteLocked,这里会一直等开机动画结束,才会向AMS 发送bootAnimationComplete。没有接收到解锁广播,FallbakHome 会一直运行。

设置为1以后,是通过handle将数据传输,看到handleMessage()方法:

这里的bootAnimationComplete方法是ActivityManagerService.java里的

在这里看到finishBooting方法,finishBooting里面先判断开机动画有没有结束,如果没有结束,直接返回。如果已经结束,则经过一些处理,最后发送开机广播BOOT_COMPLETED。

如果开机动画停止,此时stop bootanim并且将service.bootanim.exit的值设为1。

在performEnableScreen()方法中跟surfaceFlinger进行通信,告知surfaceFlinger开机动画结束了

其中使用了IsurfaceComposer,于是到ISurfaceComposer.cpp查看对BOOT_FINISHED(也就是FIRST_CALL_TRANSACTION)的处理,可以看到在BnSurfaceComposer::onTransact方法中:

这里会调用bootFinished函数,这个bootFinished函数的具体实现是在SurfaceFlinger.cpp中

在这个方法中可以看到该属性值是由WMS通信得到的,此时查看surfaceFlinger.cpp里对bootFinished方法的调用,其中在binderDied方法对其进行了false处理,此时当开机动画结束后在BootAnimation.cpp中binderDied()方法,这个方法是当对象死掉或者其他情况导致该Binder结束时,就会回调binderDied()方法;这部分和SurfaceComposerClient类内部有一个实现了ISurfaceComposerClient接口的Binder代理对象mClient,这个Binder代理对象引用了SurfaceFlinger服务,SurfaceComposerClient类就是通过它来和SurfaceFlinger服务通信的。由于BootAnimation类引用了SurfaceFlinger服务,因此,当SurfaceFlinger服务意外死亡时,BootAnimation类就需要得到通知,并执行binderDied函数:

至此,开机动画的整个流程结束。

七、附录

BootAnimation.cpp方法主要作用表:

onFirstRef

建立BootAnimation进程与surfaceFlinger进程的通信,及加载资源

DisplayEventCallback

进行事件的处理以及调用surfaceComposerClient里的getPhysicalDisplayToken()进行物理屏幕的显示

TimeCheckThread

超时检测机制线程

addTimeDirWatch

增加时间监测

android

安卓原生动画播放方法

binderDied

当Binder机制的客户端死掉,导致了该Binder结束,会回调此方法(此处一般指surfaceflinger)

checkExit

检测开机动画是否停止

doThreadLoop

超时检测线程的执行函数

drawClock

绘制时钟进行当前时间的显示

findBootAnimationFile

主要是初始化 mZipFileName

findBootAnimationFileInternal

将mZipFileName存入索引

getEglConfig

绘制目标framebuffer的配置属性及显示窗口内容

handleEvent

handle事件,更新UI操作信息

handleViewport

负责图表视图中可见的内容

initFont

加载字体资源

initTexture

加载系统默认UI资源,通过decodeImage来解码图片,并显示在SurfaceLayer之上

limitSurfaceSize

该方法的作用是将width和height限制在设备GPU支持的范围内

loadAnimation

解析资源,加载动画文件,这里的mZipFileName就是在readyToRun中获取的动画文件位置

movie

自定义的开机动画

parseAnimationDesc

解析读取desc.txt文件,设置相应animation参数

parseColor

解析颜色

parsePosition

解析位置

parseTextCoord

解析文本坐标

playAnimation

会拿到 mAnimation的图片,还有desc.txt中定义的图片分辨率,帧率等信息,依次播放part0,part1中图片,合成Surface,然后调用eglSwapBuffers(mDisplay, mSurface);动图给显示设备.

preloadAnimation

加载开机动画资源文件

preloadZip

用于图像的预加载阶段

processDisplayEvents

处理显示事件

readFile

读取文件

readyToRun

判断开机动画的压缩包是否存在,主要是对opengl工作环境进行初始化,初始化EGL环境,为送图做准备工作,做一个动画播放的预操作

releaseAnimation

释放动画资源

resizeSurface

调整开机动画的surface大小

threadLoop

显示开机画面,每个线程类都要实现的,在这里定义thread的执行内容。这个函数如果返回true,且没有调用requestExit(),则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。

updateIsTimeAccurate

记录最新修改的时间

decodeImage

解析图像信息,并存储

initTexture

加载系统默认UI资源,通过decodeImage来解码图片,并显示在SurfaceLayer之上

AImageDecoder_createFromBuffer 把来自字符串或者缓冲区(buffer)对象的图像数据创建为一个图像内存

kill( getpid(), SIGKILL )杀掉父进程 让子进程被init进程接管 这样就能保证不被清理 然后再 通过AM命令发生广播启动其它服务

Android 12 开机动画代码与流程详解相关推荐

  1. RK3399 Android 8.1 开机动画制作全流程详解

    文章目录 一.开机动画包 二.开机动画图片 三.desc.txt编写规范 四.开机动画临时生效 五.开机动画内置系统 一.开机动画包 N个文件夹和一个desc.txt. 文件夹中是开机动画的图片资源, ...

  2. android开机动画视频教程,【Android开机动画制作教程】开机动画文件组成及其详解释疑!...

    [开机动画位置] 安卓原版系统开机动画位置: system/media/bootanimation.zip或者data/local/bootanimation.zip 这两处的区别在于动画放在syst ...

  3. android系统加载主题的流程,详解Android布局加载流程源码

    一.首先看布局层次 看这么几张图 我们会发现DecorView里面包裹的内容可能会随着不同的情况而变化,但是在Decor之前的层次关系都是固定的.即Activity包裹PhoneWindow,Phon ...

  4. Android 11---WMS之横竖屏切换流程详解之一

    本文以Activity.setRequestedOrientation为入口梳理下横竖屏切换的详细流程.     代码均是基于最新的11.0版本. 第一篇主要讲了横竖屏切换时的准备操作: 更新方向,执 ...

  5. Android App Bundles相关概念及开发流程详解

    本文会根据官网的介绍,结合自己的一些理解,来阐述Android App Bundles的相关概念和开发流程. 主要参考文章如下. https://developer.android.com/guide ...

  6. android三种动画的区别,TranslateAnimation详解

    Android JDK为我们提供了4种动画效果,分别是: AlphaAnimation,RotateAnimation, ScaleAnimation, TranslateAnimation.今天我想 ...

  7. Vuex实战项目—ToDoList代码及流程详解

    ToDoList实战 一.安装依赖 二.全部代码 文件夹结构 三.流程步骤 1.列表数据的动态加载 2.文本输入框的双向同步 3.添加事项的操作 4.删除功能 5.复选框状态的绑定 6.修改复选框的是 ...

  8. Android App启动流程详解

    前言:在之前的文章中已经写了apk的打包流程.安装流程,今天就是梳理一下apk系列的最后的流程--app启动流程.经过今天的梳理以后咱们就可以对apk包是怎么编译生成的.apk是怎么被安装到安卓手机的 ...

  9. android的启动动画,Android系统开机动画的一生

    前言 在上篇文章[Android从上电到加载launcher,都发生了啥]中,简单介绍了Android系统从上电到加载launcher的流程,但比较粗略,特别是init之后,开机动画如何启动,又如何结 ...

最新文章

  1. js 设计模式与继承学习
  2. 安卓开发小知识 - 3
  3. c+和python先学哪个比较好-python和c,应该先学哪个?
  4. Python之web开发(三):python使用django框架搭建网站之SQLserver数据库连接
  5. python os 文件操作 getcwd()方法
  6. 交流电路中的功率和功率因数
  7. mysql临时关闭索引功能_MYSQL中常用的强制性操作(例如强制索引)
  8. python对图片颜色校正_使用Python PIL更改图像色调
  9. dropdownlist ajax联动,asp.net省市三级联动的DropDownList+Ajax的三种框架(aspnet/Jquery/ExtJs)示例...
  10. 为什么你的 JavaScript 代码如此冗长?!
  11. springboot集成购买阿里的rocketmq
  12. wsl2 Ubuntu安装Anaconda3
  13. H264、H265编码概念及I帧P帧B帧
  14. lpddr3 阻抗_LPDDRx的总结
  15. 股票交易费的计算---沪A版
  16. java switch case 跳转_java 在switch结构中的case1如何跳转到case2
  17. 卷积神经网络 - 汇聚层
  18. Linux查找文件重复内容
  19. vrchat模型保存_轻松简单自己上传VRChat的Avatar
  20. openwrt怎么做ap_终于把无线AP鸡肋的系统刷成openwrt,从此山鸡变凤凰!

热门文章

  1. 计算机的自动播放功能有什么用,电脑问题---关闭自动播放功能.doc
  2. HTML5手机移动端手势音乐播放器源码
  3. 云服务器为什么要设置防火墙?怎么设置防火墙?
  4. CAD关于标注样式删除标注样式(com接口网页版)
  5. 微信公众号网页上点击放大图片浏览,解决方案
  6. linux服务器 更新显卡驱动
  7. 基于FPGA的PCI接口电路设计
  8. OneNote 使用(持续更新)
  9. 在下面的c语言语句中存在错误的是,在下面的C语言语句中,存在错误的是int a=b=10;...
  10. JS 触发 validate 校验方法