本文源代码基于 Android 7.0。
Framework 系列的第一篇就介绍了 Android 系统的启动架构,其中有介绍到,在 native 层,Init 进程会启动 ServiceManager (binder服务管家)、bootanimation (开机动画) 等重要服务。ServiceManager 已经在之前写过了,今天来写写 Android 的 bootanimation (开机动画)。
目录:
- 启动架构图
- 开机启动画面
- 开机动画
1. 启动架构图
Framework篇 - Android 系统介绍和架构一览
2. 开机启动画面
开机启动会显示 3 个画面:
- 1. Linux 内核的静态启动画面。
- 2. Init 进程启动过程中出现的静态画面。
- 3. 系统服务启动过程中出现的动态画面 - bootanimation。
- 2.1 Linux 内核的静态启动画面
Bootloader 启动 Linux 内核时的启动画面 (Linux 小企鹅的画面)。
在默认情况下,这个画面是不会出现的 (Android 1.5及以上版本已经取消加载图片),除非在编译内核的时候,启用以下两个编译选项:
CONFIG_FRAMEBUFFER_CONSOLE、CONFIG_LOGO
第一个编译选项表示内核支持帧缓冲区控制台,它对应的配置菜单项为:
Device Drivers —> Graphics support —> Console display driver support —> Framebuffer Console support。
第二个编译选项表示内核在启动的过程中,需要显示LOGO,它对应的配置菜单项为:
Device Drivers —> Graphics support —> Bootup logo。
内核源码:
/kernel/goldfish/drivers/video/
/kernel/goldfish/drivers/video/logo/
- 2.2 Init 进程启动过程中出现的静态画面
Android 系统 Init 进程启动过程中的画面。
第二个开机画面的内容是由文件 initlogo.rle 来指定的,如果文件 initlogo.rle 文件不存在,或者在显示它的过程中出现异常,那么 Android 就以文本的方式来显示第二个开机画面,即向编号为 0 的控制台 (/dev/tty0) 输出 "ANDROID" 这7个字符。
系统源码:
/system/core/init/
/system/core/init/init.c
/system/core/init/logo.c
- 2.3 系统服务启动过程中出现的动态画面 - bootanimation
应用程序 bootanimation 显示的动画。
bootanimation 程序会检查系统制定目录下是否存在动画文件 (.zip 文件),如果不存在,则显示的第三个开机画面是 Android 系统默认的开机动画 (明暗闪烁的 Android Logo),否则的话,第三个开机画面就是由用户自定义的开机动画。
一般定制的都是 bootanimation。
3. 开机动画
内核起来后会启动第一个进程,即 Init 进程。Init 进程会根据 init.rc 配置启动 surfaceflinger 进程。开机动画是在 SurfaceFlinger 实例通过调用 startBootAnim() 启动的。
service surfaceflinger /system/bin/surfaceflinger
class main
user system
group graphics drmrpc
onrestart restart zygote
/native/services/surfaceflinger/SurfaceFlinger.cpp
/**
* SurfaceFlinger的init函数
*
* 主要功能:
*
* 初始化EGL相关;
* 创建HWComposer对象;
* 初始化非虚拟显示屏;
* 启动app和sf两个EventThread线程;
* 启动开机动画;
*
* 另外,当应用和sf的vsync偏移量一致时,则只创建一个EventThread线程;否则会创建两个DispSyncSource对象,分别是用于绘制(app)和合成(SurfaceFlinger)。
*/
void SurfaceFlinger::init() {
// ...
// initialize our drawing state
// 初始化绘图状态
mDrawingState = mCurrentState;
// set initial conditions (e.g. unblank default device)
// 初始化显示设备
initializeDisplays();
// start boot animation
// 启动开机动画【2.10】
startBootAnim();
ALOGV("Done initializing");
}
/**
* 启动开机动画
*
* 通过控制ctl.start属性,设置成bootanim值,则触发init进程来创建开机动画进程bootanim,
* 到此,则开始显示开机过程的动画。
*/
void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}
通过 ctl.start 的命令,init 进程就会启动 bootanim 进程,动画就开始播放了。
bootanimation 的实现 - bootanimation_main.cpp:
/base/cmds/bootanimation/bootanimation_main.cpp
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
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();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
新建一个 BootAnimation 实例,然后新建一个 Binder 线程池,因为 BootAnimation 在显示动画时要与 SurfaceFlinger 服务进程通信,所以要启个 Binder 线程池。
对于如何修改开机动画,更换素材,有兴趣的同学可以看看这篇文章:如何修改开机动画的两种方式剖析