Chinaunix首页 | 论坛 | 博客
  • 博客访问: 512533
  • 博文数量: 92
  • 博客积分: 3146
  • 博客等级: 中校
  • 技术积分: 2314
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-27 10:20
文章分类

全部博文(92)

文章存档

2014年(3)

2013年(17)

2012年(16)

2011年(22)

2010年(34)

分类: Android平台

2013-10-29 11:43:51

最近手头上开始倒腾smdk4412 android的开发,以前都是研究S5PC110 android2.3,拿到样机就发现logo和以前有很多的不一样的,这一次kernel的logo差不多是在程序一进入kernel就显示了,而第二张logo是系统下的*.lre文件,之后才是动画,尤其是充电的logo更是和以前不一样了,以前android2.3的时候我都是在uboot的时候初始化LCD之后,将图片转换成数组的形式然后一个个的点去填充。然后就对比了下当前系统是如何实现的,首先简单的看下系统关于充电logo显示的流程图,看这个应该一目了然了吧

1、 首先对uboot当前检测mode看下代码,在smdk4212.c文件的 int board_late_init (void)函数

点击(此处)折叠或打开

  1. printf("check start mode\n");

  2. //-->antaur
  3.   if ((*(int *)0x10020800==0x19721212) || (*(int *)0x10020804==0x19721212)
  4. || (*(int *)0x10020808==0x19721212)) {
  5.     setenv ("bootargs", "");
  6.   } else {
  7.     int tmp=*(int *)0x11000c08;
  8.     *(int *)0x10020800=*(int *)0x10020804=0x19721212;
  9.     *(int *)0x11000c08=(tmp&(~0xc000))|0xc000;
  10.     udelay(10000);
  11.     if ((*(int *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) {
  12.         setenv ("bootargs", "androidboot.mode=charger"); ////检测到有DC插入
  13.         printf("charger mode\n");
  14.     } else {
  15.         setenv ("bootargs", "");
  16.     }
  17.     *(int *)0x11000c08=tmp;
  18.   }
     当前我的PMU是MAX77686,支持关机状态下插入DC自动开机,这里 setenv ("bootargs", "androidboot.mode=charger");这句很重要,设置了androidboot.mode=charger,这个到时在init.c文件读取,你就理解为将这个变量写到某个文件中去了(你可以尝试打开/proc/cmdline),好了,uboot的话注意这里就可以了之后kernel正常启动,

2、 接着我们进入system/core/init/init.c

点击(此处)折叠或打开

  1. int main(int argc, char **argv)
  2. {
  3.         // 下面的代码开始建立各种用户空间的目录,如/dev、/proc、/sys等
  4.     mkdir("/dev", 0755);
  5.     mkdir("/proc", 0755);
  6.     mkdir("/sys", 0755);

  7.         // 处理内核命令行,关于bootmode变量会在这里得到相应的值
  8.     import_kernel_cmdline(0, import_kernel_nv);
  9.      chmod("/proc/cmdline", 0440);
  10.     get_hardware_name(hardware, &revision);
  11.     snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
  12.  
  13.     queue_builtin_action(console_init_action, "console_init"); //显示initlogo.rle,也就是android第二张图片;
  14.     queue_builtin_action(set_init_properties_action, "set_init_properties");

  15.      // 在charger模式下略过mount文件系统的工作
  16.     if (strcmp(bootmode, "charger") != 0) {
  17.        。。。。。。。
  18.     }
  19.   
  20.     if (!strcmp(bootmode, "charger")) {//如果为charger,则调用charger.c

            action_for_each_trigger("charger", action_add_queue_tail);

        } 


3、 如果检测到当前mode为charger mode的话,调用system/core/charger/charger.c

点击(此处)折叠或打开

  1. int main(int argc, char **argv)
  2. {
  3.   
  4.     list_init(&charger->supplies);

  5.     klog_init();
  6.     klog_set_level(CHARGER_KLOG_LEVEL);

  7.     dump_last_kmsg();

  8.     gr_init();//初始化graphics
  9.     gr_font_size(&char_width, &char_height);//初始化buf大小

  10.     ev_init(input_callback, charger);//初始化按键,相关代码可以在bootable/recovery/minui/event.c

  11.     fd = uevent_open_socket(64*1024, true); //??这里我理解打开一种通信机制的方式
  12.     if (fd >= 0) {
  13.         fcntl(fd, F_SETFL, O_NONBLOCK);
  14.         ev_add_fd(fd, uevent_callback, charger);
  15.     }
  16.     charger->uevent_fd = fd;
  17.     coldboot(charger, "/sys/class/power_supply", "add");

  18.     ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
  19.     if (ret < 0) {
  20.         LOGE("Cannot load image\n");
  21.         charger->surf_unknown = NULL;
  22.     }

  23.     for (i = 0; i < charger->batt_anim->num_frames; i++) {  //显示充电logo
  24.         struct frame *frame = &charger->batt_anim->frames[i];

  25.         ret = res_create_surface(frame->name, &frame->surface);
  26.         if (ret < 0) {
  27.             LOGE("Cannot load image %s\n", frame->name);
  28.             /* TODO: free the already allocated surfaces... */
  29.             charger->batt_anim->num_frames = 0;
  30.             charger->batt_anim->num_cycles = 1;
  31.             break;
  32.         }
  33.     }

  34.     ev_sync_key_state(set_key_callback, charger);

  35.     gr_fb_blank(true);

  36.     charger->next_screen_transition = now - 1;
  37.     charger->next_key_check = -1;
  38.     charger->next_pwr_check = -1;
  39.     reset_animation(charger->batt_anim);
  40.     kick_animation(charger->batt_anim);

  41.     event_loop(charger); //循环函数,主要就是更新logo、以及检测按键状态

  42.     return 0;
  43. }
4、 这里我主要分析下event_loop()函数

点击(此处)折叠或打开

  1. static void event_loop(struct charger *charger)
  2. {
  3.     int ret;

  4.     while (true) {
  5.         int64_t now = curr_time_ms();//获取当前的时间,这和流程中的检测超时相关

  6.         LOGV("[%lld] event_loop()\n", now);
  7.         handle_input_state(charger, now);//检测按键是否有按下,里面有个函数process_key
  8.         handle_power_supply_state(charger, now);//检测当前电池的状态(是否充电)

  9.         /* do screen update last in case any of the above want to start
  10.          * screen transitions (animations, etc)
  11.          */
  12.         update_screen_state(charger, now);//刷充电logo

  13.         wait_next_event(charger, now);
  14.     }
  15. }
看下对按键是如何做处理的

点击(此处)折叠或打开

  1. static void process_key(struct charger *charger, int code, int64_t now)
  2. {
  3.     struct key_state *key = &charger->keys[code];
  4.     int64_t next_key_check;

  5.     if (code == KEY_POWER) {
  6.         if (key->down) {
  7.             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;//
  8.             if (now >= reboot_timeout) {
  9.                 LOGI("[%lld] rebooting\n", now);
  10.                 android_reboot(ANDROID_RB_RESTART, 0, 0); //检测到长按power key 重启机器
  11.             } else {
  12.                 /* if the key is pressed but timeout hasn't expired,
  13.                  * make sure we wake up at the right-ish time to check
  14.                  */
  15.                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
  16.             }
  17.         } else {
  18.             /* if the power key got released, force screen state cycle */
  19.             if (key->pending)
  20.                 kick_animation(charger->batt_anim);
  21.         }
  22.     }

  23.     key->pending = false;
  24. }

  25. static void handle_input_state(struct charger *charger, int64_t now)
  26. {
  27.     process_key(charger, KEY_POWER, now);

  28.     if (charger->next_key_check != -1 && now > charger->next_key_check)
  29.         charger->next_key_check = -1;
  30. }

再看看对电池状态是如何判断的

点击(此处)折叠或打开

  1. static void handle_power_supply_state(struct charger *charger, int64_t now)
  2. {
  3.     if (charger->num_supplies_online == 0) {
  4.         if (charger->next_pwr_check == -1) {
  5.             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
  6.             LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
  7.                  now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
  8.         } else if (now >= charger->next_pwr_check) {
  9.             LOGI("[%lld] shutting down\n", now);
  10.             android_reboot(ANDROID_RB_POWEROFF, 0, 0);  //如果拔掉了DC则系统关机
  11.         } else {
  12.             /* otherwise we already have a shutdown timer scheduled */
  13.         }
  14.     } else {
  15.         /* online supply present, reset shutdown timer if set */
  16.         if (charger->next_pwr_check != -1) {
  17.             LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
  18.             kick_animation(charger->batt_anim);
  19.         }
  20.         charger->next_pwr_check = -1;
  21.     }
  22. }
好了,大致的流程代码里面应该都有叙述了,等下得分析下为何一进入kernel就可以显示logo了


附:关于如何更换系统*.lre的logo,从别人那里复制了过来:

1). 制作当前屏幕像素的图片(模拟器默认为1024*768)
 使用PS制作一张1024*168的图片,保存时选“保存为 Web 所用格式”,然后在弹开的窗口上,“预设”项选择“PNG-24”,保存为android_logo.png(

注:好像只支持png-24,其他格式生成的rle文件显示不正常,有兴趣大家可以再验证一下。

2). 将图片转换为raw格式
 使用linux下的ImageMagick自带的convert命令,进行raw格式转换,命令为:
  convert -depth 8 android_logo.png rgb:android_logo.raw

注:ubuntu 10.04 默认已经安装ImgageMagick工具,如果当前系统没有安装,可以执行下面的命令安装:
  sudo apt-get install imagemagick

3). 将raw格式转化为rle文件
 需要用到android编译后的rgb2565工具,在android/out/host/linux-x86/bin目录下(android为当前源码所在目录),转换命令如下:
 rgb2565 -rle < android_logo.raw > initlogo.rle

4).

修改:tcc8923_20120127/device/telechips/m805_892x/device.mk

添加下面一行:

PRODUCT_COPY_FILES += \

device/telechips/common/initlogo.rle:root/initlogo.rle

意思是复制rle文件到ramdisk.img

5、替换文件device\telechips\common\initlogo.rle;

同时删除out\target\product\tcc8900\ramdisk.img,ramdisk-recovery.img,再重新编译,就可以了

第二种方法:

到目前为止,启动需要显示的图像已经做好了,就是initlogo.rle,注意文件名必须是这个,如果想改文件名,需要修改

android/system/core/init/init.h中的宏:
 #define INIT_IMAGE_FILE "/initlogo.rle"

============================================================================================

下面需要将initlogo.rle加入的android文件系统中
以下的4,5,6,7,需要先进行如下设置,把initlogo.rle放入device\telechips\common\,删除ramdisk.img之类的相关的文件重新make即可。

4). 找到ramdisk.img文件(android/out/target/product/generic/ramdisk.img),将文件名改为ramdisk.img.gz,然后使用下面的命令解压:
 gunzip ramdisk.img.gz
 解压后得到ramdisk.img,可能有人要问,怎么文件名又改回去了?其实不然,使用file ramdisk.img查看一下就知道了:
 解压前:ramdisk.img: gzip compressed data, from Unix
 解压后:ramdisk.img: ASCII cpio archive (SVR4 with no CRC)
 跑题了,还是说正事儿。

5). 使用cpio提取文件:
 新建一个temp目录:
 mkdir temp
 cd temp
 cpio -i -F ../ramdisk.img

6). 导出文件列表:
 cpio -i -t -F ../ramdisk.img > list

注:list是一个文本文件,里面存储了ramdisk.img的文件结构,我们需要在这个文件中加入initlogo.rle这一行,修改后的文件如下
 data

default.prop

dev

init

init.goldfish.rc

init.rc

initlogo.rle

proc

sbin

sbin/adbd

sys

system
7). 生成ramdisk.img
 cpio -o -H newc -O ramdisk.img < list

注:根据list文件的描述,生成ramdisk.img文件

8). 用ramdisk.img覆盖sdk目录下的ramdisk.img(android-sdk-windows/platforms/android-2.1/images/ramdisk.img),最好先备份一下。




阅读(4095) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~