基于smdk4412在android4.0上分析充电logo

2019-07-14 00:05发布

最近手头上开始倒腾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 ");

  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 ");
  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 ");
  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 ", 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() ",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_tnow)
  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 ",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 theright-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_tnow)
  26. {
  27.     process_key(charger, KEY_POWER,now);

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

再看看对电池状态是如何判断的
点击(此处)折叠或打开
  1. static void handle_power_supply_state(struct charger*charger, int64_tnow)
  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) ",
  7.                  now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
  8.         } elseif (now>= charger->next_pwr_check){
  9.             LOGI("[%lld] shutting down ",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 timerif set */
  16.         if (charger->next_pwr_check!= -1) {
  17.             LOGI("[%lld] device plugged in: shutdown cancelled ",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 elechipscommoninitlogo.rle; 同时删除out argetproduct cc8900 amdisk.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 elechipscommon,删除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),最好先备份一下。