Android开机logo一直都是各大产品定制的重点,如果IC厂家代码完善的话,那就很简单,直接把做好的logo文件放在预制好的文件夹就可以了。还有一些定制服务做得好的IC厂家,可能还会通过烧录软件直接修改升级包里面的logo文件,修改完毕后,直接烧录完事。
这些二次开发做得比较完善的IC厂家一般是各大平板电脑,手机方案商。但如果android代码并没得到很完善的优化怎么办?如在工业领域的android BSP。本人就遇到过这样的情况。Android logo的定制还是需要我们花费一番心机。
下面我们来分析一下android启动过程中logo的显示过程。鉴于不同的平台,可能还有IC厂家会在uboot里面显示开机logo,这部分在这篇文章里面不会介绍到。此文章介绍的是从内核logo,到init logo,到动态logo的过程。
首先,我们来看看内核logo:
打开内核logo 显示配置:
androidkernel boot logo
-> Device Drivers
-> Graphics support
-> Bootup logo (LOGO [=y])
[*] Standard 224-color Linux logo
保证.config文件里面几项被配置上
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_LOGO_ADVSIGNAGE_CLUT224 is not set
其代码和图片是在内核目录下的“drivers\video\logo”文件夹下,内核logo图片的方法可以到网上搜索,内核logo的代码和logo的制作方法这里就不做分析了。
接下来是init logo:
看到vendor.mk文件里面
PRODUCT_COPY_FILES += \
device/vendor/machine/initlogo.rle:root/initlogo.rle
相信一般的IC厂家都会用这样的做法,把init logo放到平台相关的目录下,然后在编译的时候拷贝,打包到boot.img 下。
接下来我们看看init logo的显示过程。
首先是init logo名字的定义,至于initlogo.rle的制作,可以参考网上的一些资料。有直接现成的制作软件。
system/core/init/init.h
#define INIT_IMAGE_FILE "/initlogo.rle"
在android init过程里面,执行到console_init_action的时候,会把initlogo.rle 加载到内存里面去,然后显示出来。其实为什么会在console_init_action 里面显示logo,这个函数的本意是用来初始化console, 也就是串口的。其实本人也不是很清楚Google为什么要把init logo的显示放到这个函数里面实现,也没看出有什么特殊的含义,如果有人了解,可以告知。
System/core/init/init.c
647 static int console_init_action(int nargs, char **args)
648 {
649 int fd;
650
651 if (console[0]) {
652 snprintf(console_name, sizeof(console_name), "/dev/%s", console);
653 }
654
655 fd = open(console_name, O_RDWR);
656 if (fd >= 0)
657 have_console = 1;
658 close(fd);
662 if( load_565rle_image(INIT_IMAGE_FILE) ) {
665 fd = open("/dev/ttymxc0", O_WRONLY);
666 if (fd >= 0) {
667 const char *msg;
668 msg = "\n"
669 "\n"
670 "\n"
671 "\n"
672 "\n"
673 "\n"
674 "\n" // console is 40 cols x 30 lines
675 "\n"
676 "\n"
677 "\n"
678 "\n"
679 "\n"
680 "\n"
681 "\n"
682 " A N D R O I D ";
683 write(fd, msg, strlen(msg));
684 close(fd);
685 }
686 }
687 return 0;
688 }
其中load_565rle_image是在system/core/init/logo.c里面定义,如果有兴趣,可以去看看里面做了什么动作。
最后是动态logo的显示过程:
首先还是vendor.mk文件:
PRODUCT_COPY_FILES += \
device/vendor/machine/bootanimation.zip:system/media/bootanimation.zip
跟init logo的做法一样,拷贝到特定的目录下,至于制作的方法,网上也有资料供参考。
接下来,在framework的代码里面会定义bootanimation.zip的存放路径
55 #define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
56 #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
57 #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
至于为什么会定义了三个名称的路径?大家可以去研究一下,这里就不进行详细分析了。
接下来是加载logo的动作
280 if ((encryptedAnimation &&
281 (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
282 (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
283
284 ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
285 (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
286
287 ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
288 (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
289 mAndroidAnimation = false;
290 }
以上是加载logo的过程,这过程里面,如果加载logo成功,会把mAndroidAnimation设置为false,如果mAndroidAnimation为false,就会播放定制好的动态logo的动画,不然,就播放android原始的android动态logo。如下:
bool BootAnimation::threadLoop()
{
bool r;
if (mAndroidAnimation) {
r = android();
} else {
r = movie();
}
动态logo的显示开始与结束是由SurfaceFlinger来控制,控制过程是通过设置“service.bootanim.exit”属性的值来完成。
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
653 void SurfaceFlinger::startBootAnim() {
654 // start boot animation
655 property_set("service.bootanim.exit", "0");
656 property_set("ctl.start", "bootanim");
657 }
显示开始后,SurfaceFlinger会把“service.bootanim.exit”属性设置为0。然后“service.bootanim.exit”会在BootAnimation.cpp里面进行判断,确定是启动了动态logo,才会申请关闭logo。
frameworks/base/cmds/bootanimation/BootAnimation.cpp
383 void BootAnimation::checkExit() {
384 // Allow surface flinger to gracefully request shutdown
385 char value[PROPERTY_VALUE_MAX];
386 property_get(EXIT_PROP_NAME, value, "0");
387 int exitnow = atoi(value);
388 if (exitnow) {
389 requestExit();
390 }
391 }
在启动完成后,SurfaceFlinger在bootFinished方法里面最后把“service.bootanim.exit”属性设置为1.
296 void SurfaceFlinger::bootFinished()
297 {
298 const nsecs_t now = systemTime();
299 const nsecs_t duration = now - mBootTime;
300 ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
301 mBootFinished = true;
302
303 // wait patiently for the window manager death
304 const String16 name("window");
305 sp<IBinder> window(defaultServiceManager()->getService(name));
306 if (window != 0) {
307 window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
308 }
309
310 // stop boot animation
311 // formerly we would just kill the process, but we now ask it to exit so it
312 // can choose where to stop the animation.
313 property_set("service.bootanim.exit", "1");
314 }
分析到这里,如果想知道更加详细的过程,可以查看android里面相应的代码。