内核源代码目录:/Volumes/android-kernel/source/goldfish
Android源代码目录:/Volumes/android/source
一、开机画面的简单介绍
网上有许多资料都提到,Android设备的开机画面分为三个画面,即:Linux内核Logo,Android启动Logo,Android动态画面。经过研究分析,Android设备默认只显示Android动画,那么如何显示内核Logo和启动Logo呢?和两条编译配置有关:
- CONFIG_FRAMEBUFFER_CONSOLE:打开该配置选项,就可以显示Android启动Logo。但出现问题:默认情况下是Android文字和Android动画交替闪烁。
- CONFIG_LOGO:打开该配置选项,并且CONFIG_FRAMEBUFFER_CONSOLE也开启的情况下,可以显示内核Logo。此项无问题。
这样的情况下,制作出来的Android内核不只是在启动时出现闪烁,而且运行后也会么一直这么闪烁,本文后面将介绍如何解决这个问题。
二、定制内核Logo
内核Logo默认是一个Linux企鹅图标,该图标只支持224种颜色,图标格式为:ppm。在Android内核源代码中的路径为:drivers/video/logo/logo_linux_clut224.ppm。所以,我们只需要替换此图标,则重新编译即可。
2.1、安装netpbm工具
Mac OS
X下没有直接生成PPM格式图片的工具,可用netpbm转换。要安装netpbm工具,请先安装MacPorts,本文不描述如何安装和使用MacPorts,可在网上搜索安装和使用教程。
sudo port selfupdtae是让MacPorts先自我更新,sudo port install netpbm安装netpbm。
# sudo port selfupdate
# sudo port install netpbm
2.2、PPM图片转换
将预先做好的图片(假定为:MyLinux.png),转换为logo_linux_clut224.ppm格式:
# pngtopnm MyLinux.png > logo_linux_clut.pnm
# pnmquant 224 logo_linux_clut.pnm > logo_linux_clut224.pnm
# pnmtoplainpnm logo_linux_clut224.pnm > logo_linux_clut224.ppm
# cp logo_linux_clut224.ppm /Volumes/android-kernel/source/goldfish/drivers/video/logo/
2.3、配置
许多教程中描述了使用make
menuconfig来定制CONFIG_FRAMEBUFFER_CONSOLE和CONFIG_LOGO两个变量,这是一种方法,但在Mac环境中,make
menuconfig不能正常运行,总是出现ncurses的相关库找不到,折腾了很久之后,放弃使用make menuconfig。
还有一种方法是使用make config,但这种方法要按N次回车,并仔细对比选项,太费事了。这里介绍一种快速的方法:
在编译内核的时候,我们使用了make goldfish_armv7_defconfig来配置的,只要将该默认配置修改一下,加入上面两个配置项至这个默认配置中,重新运行即可。命令如下:
# cd /Volumes/android-kernel/source/goldfish
# vi arch/arm/configs/goldfish_armv7_defconfig
在文件末尾加入:
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
按 wq 保存退出。
2.4、去掉光标
开启FRAME_BUFFER_CONSOLE后,会显示光标,需要修改源码解决,网上的方案比较复杂,经研究,这里介绍一个简单方法:
# vi drivers/video/console/softcursor.c
找到soft_cursor(...)函数,只留最后一句:return 0; 其他行注释掉:
int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
/* struct fbcon_ops *ops = info->fbcon_par;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int i, size, dsize, s_pitch, d_pitch;
struct fb_image *image;
u8 *src, *dst;
...
fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height);
image->data = dst;
info->fbops->fb_imageblit(info, image);
*/ return 0;
}
2.5、编译
# export PATH=/Volumes/android/source/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.7/bin/:$PATH
# make
goldfish_armv7_defconfig
# make -j16
编译完成后,会在最后显示如下内容:
...
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
2.6、运行
运行如下指令:
运行可以成功显示开机Logo,但出现Android文字和Android动画交替闪烁的情况。
# emulator -kernel arch/arm/boot/zImage
这个问题是由于启用CONFIG_FRAMEBUFFER_CONSOLE编译项后,init进程如果找不到“initlogo.rle”,就会进入text
console模式,而后面的第三屏为动画的图形模式,从而造成两个界面交替闪烁的情况。分析过程如下:
先进入Android源代码根目录,注意不是内核目录。
找到console_init_action函数,这个是console启动函数,代码如下:先进入Android源代码根目录,注意不是内核目录。
# vi /Volumes/android/source/system/core/init/init.c
...
static int console_init_action(int nargs, char **args)
{
int fd;
if (console[0]) {
snprintf(console_name, sizeof(console_name), "/dev/%s", console);
}
fd = open(console_name, O_RDWR);
if (fd >= 0)
have_console = 1;
close(fd);
if( load_565rle_image(INIT_IMAGE_FILE) ) {
fd = open("/dev/tty0", O_WRONLY);
if (fd >= 0) {
const char *msg;
msg = "\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n" // console is 40 cols x 30 lines
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
" A N D R O I D ";
write(fd, msg, strlen(msg));
close(fd);
}
}
return 0;
}
可以看到console_init_action函数会调用load_565rle_image函数来装入initlogo.rle文件,load_565rle_image函数在system/core/init/logo.c中。打开后的代码如下:
...
/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
int load_565rle_image(char *fn)
{
struct FB fb;
struct stat s;
unsigned short *data, *bits, *ptr;
unsigned count, max;
int fd;
if (vt_set_mode(1))
return -1;
fd = open(fn, O_RDONLY);
if (fd < 0) {
ERROR("cannot open '%s'\n", fn);
goto fail_restore_text;
}
...
munmap(data, s.st_size);
fb_update(&fb);
fb_close(&fb);
close(fd);
unlink(fn);
return 0;
fail_unmap_data:
munmap(data, s.st_size);
fail_close_file:
close(fd);
fail_restore_text:
vt_set_mode(0);
return -1;
}
由上面的代码可以看出,当装入initlogo.rle失败后,就走到fail_restore_text了,然后调用vt_set_mode(0),恢复成文本模式了。
现在问题找到了,是因为找不到initlogo.rle,系统回到text模式了。解决问题的方案有两个:- 制作initlogo.rle,即Android启动静态画面,见后文。
- 如果我不想要initlogo.rle怎么办呢?很简单,修改源代码。注释掉上面代码中的fail_restore_text:
后面一句vt_set_mode(0);这样即使找不到initlogo.rle,也会进入图形模式,重新make,问题解决。
# cd /Volumes/android/source # vi system/core/init/logo.c
... /* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ int load_565rle_image(char *fn) { ... munmap(data, s.st_size); fb_update(&fb); fb_close(&fb); close(fd); unlink(fn); return 0; fail_unmap_data: munmap(data, s.st_size); fail_close_file: close(fd); fail_restore_text: /*vt_set_mode(0)*/; return -1; }
# make -j16
三、定制Android启动Logo
Android启动时的静态画面为initlogo.rle文件,具体制作过程如下:
3.1 安装ImageMagick工具
此工具用于将png图片转换成raw文件,安装过程如下:
# sudo port install ImageMagick
安装完成后,convert指令将可以使用。
3.2 编译to2565.c,生成rgb2565工具
to565.c是Android自带的工具,用于将raw文件转换为rle文件。编译过程如下:
# cd /Volumes/android/source/build/tools/rgb2565/
# gcc -O2 -Wall -Wno-unused-parameter -o rgb2565 to565.c
3.3 制作initlogo.rle文件
先用Photoshop等软件制作一张与手机分辨率相同大小的图片(模拟器的分辨率为320*480),假定保存的文件名为:initlogo.png。为了看到运行变化,initlogo.png不要和内核Logo的图片一样。
# cd initlogo.png目录
# convert -depth 8 initlogo.png rgb:initlogo.raw
#
/Volumes/android/source/build/tools/rgb2565/rgb2565 -rle <initlogo.raw> initlogo.rle
# cp initlogo.rle /Volumes/android/source/out/target/product/generic/root/
3.4 重新编译
为确保成功,先删除ramdisk.img。
# cd
/Volumes/android/source
# rm out/target/product/generic/ramdisk.img
# make -j16
编译完成后,运行。
# cd
/Volumes/android-kernel/source/golefish
# emulator -kernel arch/arm/boot/zImage
这时,你应该看到先启动内核Logo,再启动此静态画面,最后启动Android动画了。
四、定制Android开机动画
其实,默认情况下,前面的内核Logo和Andriod的启动Logo是看不见的,如果没有特别需要,是不需要定制的。但Android开机动画默认情况下是能看见的,因此,此动画定制的可能性要大的多。而且,定制开机动画也要容易,没有前面那么多复杂的步骤,这应该是谷歌考虑到此屏幕基本都要被定制才弄成这么简单吧。
4.1 仿Android自带的动画
即Android默认的动画,此动画由两张图片组成:android-logo-mask.png,android-logo-shine.png,mask是由空心的android文字组成,即一个黑色的块,中间用Android文字挖空,这张图片是作为遮罩放在前端。shine则是一个发光的图片,放在mask的后面,通过循环移动shine,就成为Android发光动画。
用Photoshop修改这两张图片,保存在frameworks/base/core/res/assets/images目录下,文件名不变,再make即可。这个涉及资源重新编译,编译过程比较长,耐心等待。
bootanimation.zip可以放在/system/media目录或者放在/data/local目录下,/data/local目录下的优先使用。这两个目录在播放上也稍有区别,/system/media可以无限播放,/data/local只能播放10秒。
bootanimation.zip解压后的结构如下:
第二行:p 1 0 part0 p为标志符,表示将part0目录里的图片,播放一次,间隔时间为0秒。
第三行:p 0 0 part1 p为标志符,表示将part1目录里的图片,重复播放,间隔时间为0秒。
上面的目录和文件准备好后,执行以下指令:
将打好的bootanimation.zip包,拷贝到/system/media目录,再用make snod重新生成。再运行查看效果。
4.2 帧动画
帧动画是指由多帧图片组成的动画。这个设置是最简单的,以致于手机ROOT后,就可以在手机里直接下载一个bootanimation.zip,替换掉/system/media/bootanimation.zip,就能换掉这个开机动画。bootanimation.zip可以放在/system/media目录或者放在/data/local目录下,/data/local目录下的优先使用。这两个目录在播放上也稍有区别,/system/media可以无限播放,/data/local只能播放10秒。
bootanimation.zip解压后的结构如下:
- desc.txt
- part0
- 0000.png
- 0001.png
- ...
- part1
- 0000.png
- 0001.png
- ...
part0,part1是两个存放动画帧系列图片的目录。desc.txt是一个文本文件,文件的内容如下:320 480 30
p 1 0 part0
p 0 0 part1
第一行:320 480 30 表示播放分辨率为320*480,30表示每秒播放30帧图片。第二行:p 1 0 part0 p为标志符,表示将part0目录里的图片,播放一次,间隔时间为0秒。
第三行:p 0 0 part1 p为标志符,表示将part1目录里的图片,重复播放,间隔时间为0秒。
上面的目录和文件准备好后,执行以下指令:
# cd bootanimation所在目录 # zip -0 -r ../bootanimation.zip ./* # cp ../bootanimation.zip /Volumes/android/source/out/target/product/generic/system/media/ # make snod先CD进入bootanimation目录后,再执行zip压缩指令,保证不会将bootanimation目录打进包内。-0 表示只存储,不压缩,-r 表示包括子目录
将打好的bootanimation.zip包,拷贝到/system/media目录,再用make snod重新生成。再运行查看效果。
# cd
/Volumes/android-kernel/source/golefish
# emulator -kernel arch/arm/boot/zImage
下面是(自上而下依次为内核Logo,启动Logo,启动动画):
没有评论:
发表评论