一、概述
为了在项目中对安卓系统进行定制化,需要将其开机动画进行修改,因此,上网搜了一堆原理教程,这里就根据自己的理解进行梳理,有任何错漏,欢迎指正。
二、开机动画原理
安卓系统完整的启动过程具体如下:
1. 启动BootLoader
2. 加载系统内核
3. 启动Init和其它重要守护进程
4. 启动Zygote进程
5. 启动Runtime进程,初始化Service Manager。启动SystemService
6. 启动HomeLaucher
7. 启动其它应用程序
这里我们要关注的是第3点,启动Init和其它重要守护进程。
在系统内核加载完成之后,系统启动第一个用户进程,即Init进程。Init进程一启动就根据init.rc和init.hardware.rc(hardware为具体硬件名称)脚本文件执行需要启动的命令及服务。
在init.rc启动服务过程中,直接启动了一个SurfaceFlinger服务。SurfaceFlinger服务用于管理安卓系统应用端所有的surface,每个应用相当于客户端,surfaceFlinger相当于服务端,客户端完成图形处理之后,请求SurfaceFlinger显示到屏幕上。
启动surfaceFlinger的过程中,调用了开机动画的应用程序bootanim,使得开机动画能够进行显示;当启动结束时,surfaceFlinger会请求bootanim退出,然后开机过程结束。
这里的启动过程就是如上所述的那样,下面看看源码是如何写的。
1、init.rc启动SurfaceFlinger服务
代码位置:\android42\device\softwinner\wing-common\init.rc(该源码为cubieboard2配套源码,下同)。
# Set this property so surfaceflinger is not started by system_init
setprop system_init.startsurfaceflinger 0
service surfaceflinger /system/bin/surfaceflinger
class main
user system
group graphics drmrpc
onrestart restart zygote
这部分代码设置了surfaceflinger在init进程中启动及启动surfaceflinger。具体细节如下:
1)设置surfaceflinger在init进程中启动
在android系统中核心的Service(如surfaceFlinger)都由ServiceManager管理,核心Service启动一般是在SystemServer来启动。而这里的setprop语句用于设置属性值,将system_init.startsurfaceflinger设置为0时,表示系统将在init进程中启动surfaceflinger,不需要再SystemServer中启动。
可参考SystemServer启动SurfaceFlinger服务的代码:
代码位置:\android42\frameworks\base\cmds\system_server\library\system_init.cpp
extern "C" status_t system_init()
{
…
char propBuf[PROPERTY_VALUE_MAX];
//获取init.rc中的system_init.startsurfaceflinger属性。
//若该属性为1,则启动SurfceFlinger服务。
//若为0,表示该服务已在init进程中启动。
property_get("system_init.startsurfaceflinger", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
// Start the SurfaceFlinger
SurfaceFlinger::instantiate();
}
…
}
2)Init.rc启动surfaceflinger
该部分脚本代码遵循Android Init Language规范,该规范可参考官网中http://www.kandroid.org/online-pdk/guide/bring_up.html的介绍,或者在android42\system\core\init\ReadMe.txt中。
这里定义了surfaceflinger为init进程中的一个服务及其相应的文件位置,并将其归为main类,在此类中,所有服务同时启动。在surfaceflinger服务重新启动时,重启zygote服务。
2、启动surfaceFlinger服务。
入口函数源码位于:
android42\frameworks\native\cmds\surfaceflinger\main_surfaceflinger.cpp
int main(int argc, char** argv) {
SurfaceFlinger::publishAndJoinThreadPool(true);
// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);
return 0;
}
该部分将SurfaceFlinger服务在ServiceManager中进行注册并启动。
在surfaceFlinger服务启动之后,它会调用startBootAnim()来启动开机动画。
代码位置:
android42\frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
status_t SurfaceFlinger::readyToRun()
{
…
// start boot animation
startBootAnim();
…
}
void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}
void SurfaceFlinger::bootFinished()
{
…
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
property_set("service.bootanim.exit", "1");
…
}
其中startBootAnim()通过ctl.start启动bootanim的应用程序。
在bootFinished()中通过service.bootanim.exit请求bootanim自动退出。
此外,在adb shell中,可通过命令“setprop ctl.start bootanim”启动开机动画;命令“setprop ctl.stop bootanim”停止开机动画。
3、运行bootanim应用程序。
具体bootanim应用程序的源码位于:
android42\frameworks\base\cmds\bootanimation\
包括:bootanimation_main.cpp(应用程序入口),BootAnimation.cpp(应用程序实现),BootAnimation.h(头文件)。
在bootanimation_main.cpp中,实现了与SurfaceFlinger的绑定并启动开机动画实现的应用程序。源代码如下:
int main(int argc, char** argv)
{
#if defined(HAVE_PTHREADS)
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
#endif
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
ALOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation();
boot->playBootMusic("/system/media/boot.wav");
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
在main函数中,首先获取init.rc/build.prop中debug.sf.nobootanimation的值是否为0。该值为0则执行开机动画程序,该值为1则不执行。默认情况下该文件中没有这个属性,在该函数中,当没有这个属性时,获取到的值将其设置为0。即系统是默认执行开机动画程序。
开机动画应用程序源码为BootAnimation.cpp,具体如下:
//定义用户自定义开机动画文件位置
#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
//线程启动初始化函数
status_t BootAnimation::readyToRun() {
…
//判断是否存在用户自定义开机动画文件,若存在,则将mAndroidAnimation设置为false
if ((encryptedAnimation &&
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
mAndroidAnimation = false;
}
…
}
//线程循环函数。
//若mAndroidAnimation为true,则调用android(),这是安卓系统默认的开机动画
//会根据/frameworks/base/core/res/assets/images/android-logo-mask.png,///frameworks/base/core/res/assets /images/android-logo-shine.png的两张图
//片,通过代码控制达到动画效果。
//若mAndroidAnimation为false,则显示用户自定义的动画。
bool BootAnimation::threadLoop()
{
bool r;
if (mAndroidAnimation) {
r = android();
} else {
r = movie();
}
}
具体开机动画控制的相关函数,可参考具体代码。
从代码中可以看出:为了显示自定义的开机动画效果,需要确保:
1)init.rc/build.prop中没有debug.sf.nobootanimation属性,或者该属性值为0。
2)/data/local/或者/system/media/文件夹中有bootanimation.zip。
4、bootanimation.zip说明。
此处对bootanimation.zip进行说明,里面的内容是:
注意:此处不能有上层文件夹。
其中,desc.txt的文本内容为
1280 720 40
p 0 0 part0
p 0 0 part1
第一行:数字的含义分别是屏幕宽度,屏幕长度,帧数(每秒多少帧);
第二行:第一项是标识符,p表示该行是该animation的一个part;
第二项是循环次数,1表示循环一次,0表示无限循环;
第三项是两次循环之间的间隔时间;
第四项是对应的目录名。
压缩是需要用存储的方式,否则程序无法读取内容。
1.windows使用winrar打包,选择ZIP 格式,压缩标准要选“储存”;
2. linux下,zip -0 -r ../bootanimation.zip ./*
linux命令使用-0 指定压缩等级为最低等级stored,即只归档不压缩,否则可能由于包格式问题引起动画显示为黑屏。
此外还应注意打包之后需要修改其运行权限,否则无法正常显示。
在shell中运行:chmod 777 bootanimation.zip
三、在CubieBoard2上修改步骤
参照《A10_android内容定制说明文档V2.1》上的说明,压缩相应的动画文件bootanimation.zip并进行权限修改,存放在\android42\device\softwinner\smfy-super3\media\目录下,进行系统编译,固件下载。
此外,也可以将bootanimation.zip存放在系统的/data/local/或者/system/media/文件夹中,无需编译即可实现开机动画效果。