本文源代码基于 Android 7.0。
Framework 系列的第一篇就介绍了 Android 系统的启动架构,其中有介绍到,在 native 层,Init 进程会启动 ServiceManager (binder服务管家)、bootanimation (开机动画) 等重要服务。ServiceManager 已经在之前写过了,今天来写写 Android 的 bootanimation (开机动画)。
目录:
1. 启动架构图
Framework篇 - Android 系统介绍和架构一览
2. 开机启动画面
开机启动会显示 3 个画面:
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/
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
应用程序 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 proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp boot = new BootAnimation();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
新建一个 BootAnimation 实例,然后新建一个 Binder 线程池,因为 BootAnimation 在显示动画时要与 SurfaceFlinger 服务进程通信,所以要启个 Binder 线程池。
对于如何修改开机动画,更换素材,有兴趣的同学可以看看这篇文章:如何修改开机动画的两种方式剖析