Android有三种启动画面
1. 在kernel framebuffer驱动中的logo, 具体参见kernel/drivers/video/fbmem.c,这是最早的静态启动画面
2. init进程加载的启动画面,具体参考android/system/core/init/init.c 中load_565rle_image的实现
3. bootanimation动画,一般来说init.rc中会有下面一段:
service bootanim /system/bin/bootanimation
user graphics
group graphics
disabled
oneshot
bootanimation的实现参考frameworks/base/cmds/bootanimation/目录,这个进程会显示一段动画
这里要描述的是第二种开机画面
1 load_565rle_image源码
105 int load_565rle_image(char *fn) 106 { 107 struct FB fb; 108 struct stat s; 109 unsigned short *data, *bits, *ptr; 110 unsigned count, max; 111 int fd; 112 113 if (vt_set_mode(1)) 114 return -1; 115 116 fd = open(fn, O_RDONLY); 117 if (fd < 0) { 118 ERROR("cannot open '%s'\n", fn); 119 goto fail_restore_text; 120 } 121 122 if (fstat(fd, &s) < 0) { 123 goto fail_close_file; 124 } 125 126 data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); 127 if (data == MAP_FAILED) 128 goto fail_close_file; 129 130 if (fb_open(&fb)) 131 goto fail_unmap_data; 132 133 max = fb_width(&fb) * fb_height(&fb); 134 ptr = data; 135 count = s.st_size; 136 bits = fb.bits; 137 while (count > 3) { 138 unsigned n = ptr[0]; 139 if (n > max) 140 break; 141 android_memset16(bits, ptr[1], n << 1); 142 bits += n; 143 max -= n; 144 ptr += 2; 145 count -= 4; 146 } 147 148 munmap(data, s.st_size); 149 fb_update(&fb); 150 fb_close(&fb); 151 close(fd); 152 unlink(fn); 153 return 0; 154 155 fail_unmap_data: 156 munmap(data, s.st_size); 157 fail_close_file: 158 close(fd); 159 fail_restore_text: 160 vt_set_mode(0); 161 return -1; 162 } 163
2 rle图像文件格式
load_565rle_image 函数的输入参数是一个rle文件,该函数会把这个文件内容转换为rgb565,写入framebuffer。
以下百度百科来的rle简介 http://baike.baidu.com/view/18819.htm?fromTaglist
--------------------
RLE全称(run-length encoding),翻译为游程编码,又译行程长度编码,又称变动长度编码法(run coding),在控制论中对于二值图像而言是一种编码方法,对连续的黑、白像素数(游程)以不同的码字进行编码。游程编码是一种简单的非破坏性资料压缩法,其好处是加压缩和解压缩都非常快。其方法是计算连续出现的资料长度压缩之。
-------------------
RLE文件格式为 [count(2 bytes), color(2 bytes)], count最大为65535;color为RGB565, 当然也可以是YUV422,我觉得只要是2bytes以下的都可以,但是由于最终我们写入到framebuffer中的都是RGB565,从效率的角度,rle文件的color值为RGB565最好。
3 写入framebuffer
load_565rel_image 源码第141行:写入n个像素点,像素点的color值是rle中的原始数据,这对于rgb565的framebuffer没有问题,但是如果framebuffer是RGB32(ARGB),就无法工作了。解决办法是做个转换,把2bytes的RGB565转换为4 bytes的ARGB 即可。
上代码
#define rgb32_r(rle) (((rle & 0xf800) >> 11) << 3) #define rgb32_g(rle) (((rle & 0x07e0) >> 5 << 2)) #define rgb32_b(rle) (((rle & 0x001f) << 3)) #define rgb32(rle) (rgb32_r(rle) << 16 | rgb32_g(rle) << 8 | rgb32_b(rle) << 0) unsigned int *bits; bits = (unsigned int *)fb.bits; while (count > 3) { unsigned n = ptr[0]; if (n > max) break; out = rgb32(ptr[1]); android_memset32(bits, out, n << 2); bits += n; max -= n; ptr += 2; count -= 4;
a) 先用GMIP生成一个800X480的png文件,为什么是800x480,图片大小必须和屏大小一致,至于是不是png无所谓,只要有工具能转为RGB565即可
b) convert命令png为RGB565: convert -depth 8 android_logo.png rgb:android_logo.raw
c) 转换RGB565为rle文件:rgb2565 -rle < android_logo.raw > initlogo.rle
5. 替换ramdisk中的initlogo.rle,重新启动即可看到新的启动画面
注意load_565rle_image 152行 unlink(fn)会删除initlogo.rle文件,进入系统后,会发现/initlogo.rle文件已经被删除了,这样可以节约一点ramdisk文件系统的内存空间,
对于ramdisk做rootfs,这没有问题,因为ramdisk镜像本身并没有被修改
但是如果根文件系统是其他文件系统,就需要把unlink(fn)注释掉,以防止initlog.rle被永久删除。
android/system/core/init/logo.c 可扩展性并不是很好,代码假定framebuffer是RGB565,实际上我接触到的就有其他格式的FB,比如YUYV和ARGB,如果碰到这种情况就要对这个文件代码做修改