Android开机启动的时候会有一个logo出现,它对应的源代码位于/system/core/init/目录下的logo.c中:

下面是我注释过的代码:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <linux/fb.h> #include <linux/kd.h> #include "init.h" #ifdef ANDROID #include <cutils/memory.h> #else void android_memset16(void *_ptr, unsigned short val, unsigned count) { unsigned short *ptr = _ptr; count >>= 1; while(count--) *ptr++ = val; } #endif struct FB { unsigned short *bits; unsigned size; int fd; struct fb_fix_screeninfo fi; struct fb_var_screeninfo vi; }; #define fb_width(fb) ((fb)->vi.xres) #define fb_height(fb) ((fb)->vi.yres) #define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2) static int fb_open(struct FB *fb)//打开framebuffer设备 { //fd对应设备文件为 /dev/graphics/fb0 fb->fd = open("/dev/graphics/fb0", O_RDWR); if (fb->fd < 0) return -1; if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) goto fail; if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) goto fail; //对fd对应的Framebuffer大小进行mmap fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0); if (fb->bits == MAP_FAILED) goto fail; return 0; fail: close(fb->fd); return -1; } static void fb_close(struct FB *fb)//关闭framebuffer { munmap(fb->bits, fb_size(fb)); close(fb->fd); } /* there's got to be a more portable way to do this ... */ static void fb_update(struct FB *fb) { fb->vi.yoffset = 1; ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); fb->vi.yoffset = 0; ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); } //设置终端显示模式:Graphics or Text? static int vt_set_mode(int graphics) { int fd, r; fd = open("/dev/tty0", O_RDWR | O_SYNC); if (fd < 0) return -1; //设置图片还是文字 r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT)); close(fd); return r; } /* 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)) //打开Graphics显示模式 return -1; //判断是否能够打开INIT_IMAGE_FILE fd = open(fn, O_RDONLY); if (fd < 0) { ERROR("cannot open '%s'/n", fn); //如果不行就恢复Text显示模式 goto fail_restore_text; } if (fstat(fd, &s) < 0) { goto fail_close_file; } /*在用户空间调用mmap,相当于在进程中开辟了文件的存储IO映射 data为返回的映射地址,把图片文件内容映射到存储区 */ data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); if (data == MAP_FAILED) goto fail_close_file; if (fb_open(&fb)) goto fail_unmap_data; max = fb_width(&fb) * fb_height(&fb); ptr = data; count = s.st_size; bits = fb.bits; while (count > 3) { unsigned n = ptr[0]; if (n > max) break; //将ptr对应的图片写到bits对应的framebuffer中,细节不追究了 android_memset16(bits, ptr[1], n << 1); bits += n; max -= n; ptr += 2; count -= 4; } munmap(data, s.st_size); fb_update(&fb); fb_close(&fb); close(fd); unlink(fn); //删除fn ? return 0; fail_unmap_data: //munmap释放申请的内存映射IO munmap(data, s.st_size); fail_close_file: close(fd); fail_restore_text: vt_set_mode(0); //返回-1,于是就直接显示"Android"字样! return -1; }

分析如下:

Android开机的第一个进程为init,在它的实现文件,即init.c中,会通过调用函数load_565rle_image(INIT_IMAGE_FILE)来实现开机启动显示logo的。而上述这个函数是在同目录下的logo.c中实现的。

在load_565rle_image()这个主函数中先调用vt_set_mode()来设定终端的显示方式,默认是使用终端的graphics显示方式,通过对开/dev/tty0设备文件调用ioctl系统调用来设定,但是如果不能打开load_565rle_image(INIT_IMAGE_FILE)中指定的INIT_IMAGE_FILE图片文件时,就直接将/dev/tty0设置为Text显示模式,然后直接返回,执行init.c中后面的代码(直接向/dev/tty0设备写入"Android"字样的logo,这也就是默认的启动logo,很没有创意,哈哈!)

但是如果存在INIT_IMAGE_FILE这个图片文件的话,就会在load_565rle_image中通过调用mmap,将图片文件映射到当前进程的存储空间中,接着就又调用fb_open()函数来打开linux framebuufer对应的设备文件 /dev/graphics/fb0 ,并把framebuffer也通过mmap映射到存储空间,于是就在后面调用android_memset16()来写入图片,从android_memset16()这样函数的参数就可以看出,程序的目的就是要把ptr对应的图片存储空间地址所对应的字节,写到bits对应的framebuffer对应的存储空间中。写Framebuffer具体细节就不追究了,可能牵涉到Framebuffer原理的一些知识。

而在init.h文件中:

#define INIT_IMAGE_FILE"/initlogo.rle"

说明了图片文件的位置和默认的文件名,这样就可以自定义开机显示画面了,哈哈!!!

总结:显示开机logo,如果使用图片的话就是通过mmap,将图片内容写到Framebuffer存储映射空间来完成的;而如果只是显示Text的话,就是直接和/dev/tty0打交道了。分析完毕!!

更多相关文章

  1. NPM 和webpack 的基础使用
  2. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  3. android ListView 属性
  4. 自定义控件attrs文件里的属性
  5. Android保存32位BMP格式图片
  6. 关于Chromium的Android(安卓)Studio使用
  7. 解决Android模拟器打不开的问题!...
  8. Android开源图表库介绍
  9. Android(安卓)屏幕设置

随机推荐

  1. parsing XML: unbound prefix
  2. Android(安卓)解析 HTML
  3. Flutter --> D8: Invoke-customs are onl
  4. Android(安卓)布局之RelativeLayout
  5. Android(安卓)的 MVVM 之 LiveData源码研
  6. android chrome iframe设置src属性无法启
  7. Android(安卓)中文api,Debug签名证书过期(E
  8. imageView 的 android:maxHeight,maxWidt
  9. Android(安卓)平滑和立体翻页效果2
  10. android JNI 调用