最近手头上开始倒腾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)函数
点击(
此处)折叠或打开
- printf("check start mode
");
- //-->antaur
- if ((*(int*)0x10020800==0x19721212)|| (*(int*)0x10020804==0x19721212)
- || (*(int*)0x10020808==0x19721212)){
- setenv ("bootargs","");
- } else{
- int tmp=*(int*)0x11000c08;
- *(int*)0x10020800=*(int*)0x10020804=0x19721212;
- *(int*)0x11000c08=(tmp&(~0xc000))|0xc000;
- udelay(10000);
- if ((*(int*)0x11000c04& 0x80)!=0x80&& INF_REG4_REG!= 0xf){
- setenv ("bootargs","androidboot.mode=charger");////检测到有DC插入
- printf("charger mode
");
- } else{
- setenv ("bootargs","");
- }
- *(int*)0x11000c08=tmp;
- }
当前我的PMU是MAX77686,支持关机状态下插入DC自动开机,这里 setenv ("bootargs", "androidboot.mode=charger");这句很重要,设置了androidboot.mode=charger,这个到时在init.c文件读取,你就理解为将这个变量写到某个文件中去了(你可以尝试打开/proc/cmdline),好了,uboot的话注意这里就可以了之后kernel正常启动,
2、 接着我们进入system/core/init/init.c
点击(
此处)折叠或打开
- int main(int argc, char**argv)
- {
- // 下面的代码开始建立各种用户空间的目录,如/dev、/proc、/sys等
- mkdir("/dev", 0755);
- mkdir("/proc", 0755);
- mkdir("/sys", 0755);
- // 处理内核命令行,关于bootmode变量会在这里得到相应的值
- import_kernel_cmdline(0, import_kernel_nv);
- chmod("/proc/cmdline", 0440);
- get_hardware_name(hardware,&revision);
- snprintf(tmp, sizeof(tmp),"/init.%s.rc", hardware);
-
- queue_builtin_action(console_init_action,"console_init");//显示initlogo.rle,也就是android第二张图片;
- queue_builtin_action(set_init_properties_action,"set_init_properties");
- // 在charger模式下略过mount文件系统的工作
- if(strcmp(bootmode,"charger") != 0){
- 。。。。。。。
- }
-
-
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
点击(
此处)折叠或打开
- int main(int argc, char**argv)
- {
-
- list_init(&charger->supplies);
- klog_init();
- klog_set_level(CHARGER_KLOG_LEVEL);
- dump_last_kmsg();
- gr_init();//初始化graphics
- gr_font_size(&char_width,&char_height);//初始化buf大小
- ev_init(input_callback, charger);//初始化按键,相关代码可以在bootable/recovery/minui/event.c
- fd = uevent_open_socket(64*1024,true);
//??这里我理解打开一种通信机制的方式
- if (fd>= 0){
- fcntl(fd, F_SETFL, O_NONBLOCK);
- ev_add_fd(fd, uevent_callback, charger);
- }
- charger->uevent_fd= fd;
- coldboot(charger,"/sys/class/power_supply","add");
- ret = res_create_surface("charger/battery_fail",&charger->surf_unknown);
- if (ret< 0) {
- LOGE("Cannot load image
");
- charger->surf_unknown= NULL;
- }
- for (i= 0; i < charger->batt_anim->num_frames; i++){
//显示充电logo
- struct frame *frame = &charger->batt_anim->frames[i];
- ret = res_create_surface(frame->name,&frame->surface);
- if (ret< 0) {
- LOGE("Cannot load image %s
", frame->name);
- /* TODO: free the already allocated surfaces...*/
- charger->batt_anim->num_frames= 0;
- charger->batt_anim->num_cycles= 1;
- break;
- }
- }
- ev_sync_key_state(set_key_callback, charger);
- gr_fb_blank(true);
- charger->next_screen_transition= now - 1;
- charger->next_key_check= -1;
- charger->next_pwr_check= -1;
- reset_animation(charger->batt_anim);
- kick_animation(charger->batt_anim);
- event_loop(charger); //循环函数,主要就是更新logo、以及检测按键状态
- return 0;
- }
4、 这里我主要分析下event_loop()函数
点击(
此处)折叠或打开
- static void event_loop(struct charger *charger)
- {
- int ret;
- while (true){
- int64_t now = curr_time_ms();//获取当前的时间,这和流程中的检测超时相关
- LOGV("[%lld] event_loop()
",now);
- handle_input_state(charger,now);//检测按键是否有按下,里面有个函数process_key
- handle_power_supply_state(charger,now);//检测当前电池的状态(是否充电)
- /*do screen update last in case any of the above
want to start
- * screen transitions (animations, etc)
- */
- update_screen_state(charger,now);//刷充电logo
- wait_next_event(charger,now);
- }
- }
看下对按键是如何做处理的
点击(
此处)折叠或打开
- static void process_key(struct charger *charger, int code, int64_tnow)
- {
- struct key_state *key = &charger->keys[code];
- int64_t next_key_check;
- if (code== KEY_POWER){
- if (key->down){
- int64_t reboot_timeout = key->timestamp+ POWER_ON_KEY_TIME;//
- if (now >= reboot_timeout){
- LOGI("[%lld] rebooting
",now);
- android_reboot(ANDROID_RB_RESTART, 0, 0);
//检测到长按power key 重启机器
- } else {
- /*if the key is pressed but timeout hasn't
expired,
- * make sure we wake up at theright-ish time to check
- */
- set_next_key_check(charger, key, POWER_ON_KEY_TIME);
- }
- } else{
- /*if the power key got released, force screen state cycle*/
- if (key->pending)
- kick_animation(charger->batt_anim);
- }
- }
- key->pending= false;
- }
- static void handle_input_state(struct charger*charger, int64_tnow)
- {
- process_key(charger, KEY_POWER,now);
- if (charger->next_key_check!= -1 &&now > charger->next_key_check)
- charger->next_key_check= -1;
- }
再看看对电池状态是如何判断的
点击(
此处)折叠或打开
- static void handle_power_supply_state(struct charger*charger, int64_tnow)
- {
- if (charger->num_supplies_online== 0){
- if (charger->next_pwr_check== -1) {
- charger->next_pwr_check= now + UNPLUGGED_SHUTDOWN_TIME;
- LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)
",
- now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
- } elseif (now>= charger->next_pwr_check){
- LOGI("[%lld] shutting down
",now);
- android_reboot(ANDROID_RB_POWEROFF, 0, 0);
//如果拔掉了DC则系统关机
- } else{
- /* otherwise we already have a shutdown timer scheduled*/
- }
- } else{
- /* online supply present, reset shutdown timerif set */
- if (charger->next_pwr_check!= -1) {
- LOGI("[%lld] device plugged in: shutdown cancelled
",now);
- kick_animation(charger->batt_anim);
- }
- charger->next_pwr_check= -1;
- }
- }
好了,大致的流程代码里面应该都有叙述了,等下得分析下为何一进入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),最好先备份一下。