Android 12 开机动画代码与流程详解
开机动画分为三个部分:
第一个开机画面是在内核启动的过程中出现的,它是一个静态的画面,在默认情况下,这个画面是不会出现的。
第二个开机画面是在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 开机动画代码与流程详解相关推荐
- RK3399 Android 8.1 开机动画制作全流程详解
文章目录 一.开机动画包 二.开机动画图片 三.desc.txt编写规范 四.开机动画临时生效 五.开机动画内置系统 一.开机动画包 N个文件夹和一个desc.txt. 文件夹中是开机动画的图片资源, ...
- android开机动画视频教程,【Android开机动画制作教程】开机动画文件组成及其详解释疑!...
[开机动画位置] 安卓原版系统开机动画位置: system/media/bootanimation.zip或者data/local/bootanimation.zip 这两处的区别在于动画放在syst ...
- android系统加载主题的流程,详解Android布局加载流程源码
一.首先看布局层次 看这么几张图 我们会发现DecorView里面包裹的内容可能会随着不同的情况而变化,但是在Decor之前的层次关系都是固定的.即Activity包裹PhoneWindow,Phon ...
- Android 11---WMS之横竖屏切换流程详解之一
本文以Activity.setRequestedOrientation为入口梳理下横竖屏切换的详细流程. 代码均是基于最新的11.0版本. 第一篇主要讲了横竖屏切换时的准备操作: 更新方向,执 ...
- Android App Bundles相关概念及开发流程详解
本文会根据官网的介绍,结合自己的一些理解,来阐述Android App Bundles的相关概念和开发流程. 主要参考文章如下. https://developer.android.com/guide ...
- android三种动画的区别,TranslateAnimation详解
Android JDK为我们提供了4种动画效果,分别是: AlphaAnimation,RotateAnimation, ScaleAnimation, TranslateAnimation.今天我想 ...
- Vuex实战项目—ToDoList代码及流程详解
ToDoList实战 一.安装依赖 二.全部代码 文件夹结构 三.流程步骤 1.列表数据的动态加载 2.文本输入框的双向同步 3.添加事项的操作 4.删除功能 5.复选框状态的绑定 6.修改复选框的是 ...
- Android App启动流程详解
前言:在之前的文章中已经写了apk的打包流程.安装流程,今天就是梳理一下apk系列的最后的流程--app启动流程.经过今天的梳理以后咱们就可以对apk包是怎么编译生成的.apk是怎么被安装到安卓手机的 ...
- android的启动动画,Android系统开机动画的一生
前言 在上篇文章[Android从上电到加载launcher,都发生了啥]中,简单介绍了Android系统从上电到加载launcher的流程,但比较粗略,特别是init之后,开机动画如何启动,又如何结 ...
最新文章
- js 设计模式与继承学习
- 安卓开发小知识 - 3
- c+和python先学哪个比较好-python和c,应该先学哪个?
- Python之web开发(三):python使用django框架搭建网站之SQLserver数据库连接
- python os 文件操作 getcwd()方法
- 交流电路中的功率和功率因数
- mysql临时关闭索引功能_MYSQL中常用的强制性操作(例如强制索引)
- python对图片颜色校正_使用Python PIL更改图像色调
- dropdownlist ajax联动,asp.net省市三级联动的DropDownList+Ajax的三种框架(aspnet/Jquery/ExtJs)示例...
- 为什么你的 JavaScript 代码如此冗长?!
- springboot集成购买阿里的rocketmq
- wsl2 Ubuntu安装Anaconda3
- H264、H265编码概念及I帧P帧B帧
- lpddr3 阻抗_LPDDRx的总结
- 股票交易费的计算---沪A版
- java switch case 跳转_java 在switch结构中的case1如何跳转到case2
- 卷积神经网络 - 汇聚层
- Linux查找文件重复内容
- vrchat模型保存_轻松简单自己上传VRChat的Avatar
- openwrt怎么做ap_终于把无线AP鸡肋的系统刷成openwrt,从此山鸡变凤凰!
热门文章
- 计算机的自动播放功能有什么用,电脑问题---关闭自动播放功能.doc
- HTML5手机移动端手势音乐播放器源码
- 云服务器为什么要设置防火墙?怎么设置防火墙?
- CAD关于标注样式删除标注样式(com接口网页版)
- 微信公众号网页上点击放大图片浏览,解决方案
- linux服务器 更新显卡驱动
- 基于FPGA的PCI接口电路设计
- OneNote 使用(持续更新)
- 在下面的c语言语句中存在错误的是,在下面的C语言语句中,存在错误的是int a=b=10;...
- JS 触发 validate 校验方法