一、android正常开机流程、关机充电流程

在写这篇文章之前我们先看两个流程:正常开机流程,关机充电系统启动流程

1、正常开机流程,按开机键。

可大致分成三部分

(1)、OS_level:UBOOT、kenrel、init这三步完成系统启动;

(2)、Android_level:这部分完成android部的初始化;

(3)、Home Screen:这部分就是我们看到的launcher部分。


Android 10 MTK关机充电流程 安卓关机充电_android

2、关机充电系统启动流程

       与前面相比,这个流程只走到init这一部分,就没有往后走了,这部分我们会在后面的代码中分析。


Android 10 MTK关机充电流程 安卓关机充电_初始化_02

二、关机充电逻辑硬件逻辑

1、插入DC,charger IC从硬件上唤醒系统,相当于长按开机键开机。


Android 10 MTK关机充电流程 安卓关机充电_启动流程_03

下面这部分是charger IC连接系统的控制部分。


Android 10 MTK关机充电流程 安卓关机充电_初始化_04

三、软件逻辑。

DC插入,其实相当于关机状态下“按开机键”开机。第一步要走UBOOT、kernel 、android init这一流程。

1、UBOOT

       UBOOT启动代码我们不在这里详细分析,这里我们只要注意二个问题:

a:如何判断是DC插入;

b:设定setenv("bootargs", "androidboot.mode=charger"),androidboot.mode这个参数相当重要,这个参数决定系统是正常启动、还是关机充电状态。

Uboot/board/samsung/smdk4212/smkd4212.c




1. int board_late_init (void) 
2. { 
3. int keystate = 0; 
4. "check start mode\n"); 
5. if ((*(int *)0x10020800==0x19721212) || (*(int *)0x10020804==0x19721212) 
6. || (*(int *)0x10020808==0x19721212))//(1)、检查是否有DC插入; 
7. {




1. int board_late_init (void)  
2. {  
3. int keystate = 0;  
4. "check start mode\n");  
5. if ((*(int *)0x10020800==0x19721212) || (*(int *)0x10020804==0x19721212)  
6. || (*(int *)0x10020808==0x19721212)) //(1)、检查是否有DC插入;  
7. {  
8. "bootargs", "");//(2)、没有DC插入;  
9. else  {//DC插入  
10. int tmp=*(int *)0x11000c08;  
11. int *)0x10020800=*(int *)0x10020804=0x19721212;  
12. int *)0x11000c08=(tmp&(~0xc000))|0xc000;  
13.     udelay(10000);  
14. if ((*(int *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) {  
15. "bootargs", "androidboot.mode=charger");//(3)、设定bootargs为charger状态  
16. "charger mode\n");  
17. else {  
18. "bootargs", "");  
19.     }  
20. int *)0x11000c08=tmp;  
21.   }  
22. #ifdef CONFIG_CPU_EXYNOS4X12  
23. int charge_status=CheckBatteryLow();//(4)、检查电池电量;  
24. //(5)、检查按键状态;  
25. // fuse bootloader  
26. if(second_boot_info != 0) {  
27.         boot_symbol=1;  
28.         INF_REG2_REG =0x8;  
29.         run_command(CONFIG_BOOTCMD_FUSE_BOOTLOADER, NULL);  
30.     }  
31. if((INF_REG4_REG == 0xd)) {  
32. // reboot default  
33. char buf[10];  
34. "%d", CONFIG_BOOTDELAY);  
35. "bootdelay", buf);  
36. "reserved", NULL);  
37.         saveenv();  
38. else if((INF_REG4_REG == 0xe) || keystate == (0x1 | 0x2)) {//(6)、按键进入fastboot模式;  
39. // reboot bootloader  
40.         boot_symbol=1;  
41.         INF_REG2_REG =0x8;  
42. "BOOTLOADER - FASTBOOT\n");  
43. "reserved", "fastboot");  
44. "bootdelay", "0");  
45. else if((INF_REG4_REG == 0xf) || keystate == (0x1 | 0x2 | 0x4)) {//(7)、按键进入recovery模式;  
46. // reboot recovery  
47. "BOOTLOADER - RECOVERY\n");  
48.         boot_symbol=1;  
49.         INF_REG2_REG =0x8;  
50. "reserved", CONFIG_BOOTCMD_RECOVERY);  
51. "bootdelay", "0");  
52. else  
53. if(keystate == (0x1 | 0x4) || second_boot_info != 0 || partition_check()) {//(8)、按键进入卡升级模式;  
54. // 2nd boot  
55. "BOOTLOADER - 2ND BOOT DEVICE\n");  
56.         boot_symbol=1;  
57.         INF_REG2_REG =0x8;  
58. "bootcmd", CONFIG_BOOTCOMMAND);  
59. "reserved", CONFIG_BOOTCMD_FUSE_RELEASE);  
60. "bootdelay", "0");  
61. else {//(9)、正常启动;  
62. // normal case  
63. char buf[10];  
64. "%d", CONFIG_BOOTDELAY);  
65. "bootdelay", buf);  
66.     }  
67.     INF_REG4_REG = 0;  
68. return 0;  
69. }


(1)、检查是否有DC插入;




1. if ((*(int *)0x10020800==0x19721212) || (*(int *)0x10020804==0x19721212) 
2. (*(int *)0x10020808==0x19721212))




1. if ((*(int *)0x10020800==0x19721212) || (*(int *)0x10020804==0x19721212)  
2. int *)0x10020808==0x19721212))


这部分检查寄存器的值。

(2)、没有DC插入;

(3)、设定bootargs为charger状态


1. if ((*(int *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) { 
2. "bootargs", "androidboot.mode=charger");



1. if ((*(int *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) {  
2. "bootargs", "androidboot.mode=charger");



 

这是这部分的重点,如果能过寄存器判断是DC插入,把androidboot.mode设定为charger状态。

以下这部分根据需要加入,通过判断不同的情况进入不同的功能,如fastboot\revovery…………,这部分不做详细解释。

(4)、检查电池电量;

    这个在正常开机状态下,如果检测电量太低,则不开机,这部分代码就不做分析。

(5)、检查按键状态;

      我们这个平台有几种模式:fastboot\recovery\卡升级等……

(6)、按键进入fastboot模式;

(7)、按键进入recovery模式;

(8)、按键进入卡升级模式

(9)、正常启动;

2、kernel

这部分和正常启动是一样的。

3、init

前面所有的描述其实只有一点和正常启动不太一样,那就是在UBOOT中把androidboot.mode设定为charger状态,内核正常流程启动,然后到init时要对charger这种状态处理。

system\core\init\init.c




1. int main(int argc,char **argv) 
2. { 
3.     ……………… 
4. "early-init", action_add_queue_tail); 
5.  
6. "wait_for_coldboot_done"); 
7. "property_init"); 
8. "keychord_init"); 
9. "console_init");  //(1)、显示initlogo.rle,也就是android第二张图片; 
10. "set_init_properties"); 
11.  
12. /* execute all the boot actions to get us started */ 
13. "init", action_add_queue_tail); 
14.  
15. /* skip mounting filesystems in charger mode */ 
16. if (strcmp(bootmode, "charger") != 0) {//(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化; 
17. "early-fs", action_add_queue_tail); 
18. "fs", action_add_queue_tail); 
19. "post-fs", action_add_queue_tail); 
20. "post-fs-data", action_add_queue_tail); 
21.     } 
22.  
23. "property_service_init"); 
24. "signal_init"); 
25. "check_startup"); 
26.  
27. if (!strcmp(bootmode,"charger")) {//(3)、如果为charger,则调用charger.c。 
28. "charger", action_add_queue_tail); 
29. else { 
30. "early-boot", action_add_queue_tail); 
31. "boot", action_add_queue_tail); 
32.     } 
33. …………………… 
34. }




1. int main(int argc, char **argv)  
2. {  
3.     ………………  
4. "early-init", action_add_queue_tail);  
5.   
6. "wait_for_coldboot_done");  
7. "property_init");  
8. "keychord_init");  
9. "console_init");  //(1)、显示initlogo.rle,也就是android第二张图片;  
10. "set_init_properties");  
11.   
12. /* execute all the boot actions to get us started */  
13. "init", action_add_queue_tail);  
14.   
15. /* skip mounting filesystems in charger mode */  
16. if (strcmp(bootmode, "charger") != 0) {//(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化;  
17. "early-fs", action_add_queue_tail);  
18. "fs", action_add_queue_tail);  
19. "post-fs", action_add_queue_tail);  
20. "post-fs-data", action_add_queue_tail);  
21.     }  
22.   
23. "property_service_init");  
24. "signal_init");  
25. "check_startup");  
26.   
27. if (!strcmp(bootmode, "charger")) {//(3)、如果为charger,则调用charger.c。  
28. "charger", action_add_queue_tail);  
29. else {  
30. "early-boot", action_add_queue_tail);  
31. "boot", action_add_queue_tail);  
32.     }  
33. ……………………  
34. }


(1)、显示initlogo.rle,也就是android第二张图片;

queue_builtin_action(console_init_action,"console_init");调用console_init_action




1. static int console_init_action(int nargs,char **args) 
2. { 
3. int fd; 
4. char tmp[PROP_VALUE_MAX]; 
5. if (console[0]) { 
6. sizeof(tmp), "/dev/%s", console); 
7.         console_name = strdup(tmp); 
8.     } 
9.     fd = open(console_name, O_RDWR); 
10. if (fd >= 0) 
11.         have_console = 1; 
12.     close(fd); 
13. if( load_565rle_image(INIT_IMAGE_FILE) ) {//这里定义rle文件的名称#define INIT_IMAGE_FILE "/initlogo.rle" 
14. "/dev/tty0", O_WRONLY); 
15. if (fd >= 0) {//如果没有这张图片,就显示android字样,在屏幕左上角; 
16. const char *msg; 
17. "\n" 
18. "\n" 
19. "\n"  // console is 40 cols x 30 lines 
20. "\n" 
21. "\n" 
22. "\n" 
23. "\n" 
24. "\n" 
25. "\n" 
26. "\n" 
27. "             A N D R O I D "; 
28.             write(fd, msg, strlen(msg)); 
29.             close(fd); 
30.         } 
31.     } 
32. return 0; 
33. }



1. static int console_init_action(int nargs, char **args)  
2. {  
3. int fd;  
4. char tmp[PROP_VALUE_MAX];  
5. if (console[0]) {  
6. sizeof(tmp), "/dev/%s", console);  
7.         console_name = strdup(tmp);  
8.     }  
9.     fd = open(console_name, O_RDWR);  
10. if (fd >= 0)  
11.         have_console = 1;  
12.     close(fd);  
13. if( load_565rle_image(INIT_IMAGE_FILE) ) {//这里定义rle文件的名称#define INIT_IMAGE_FILE "/initlogo.rle"  
14. "/dev/tty0", O_WRONLY);  
15. if (fd >= 0) {//如果没有这张图片,就显示android字样,在屏幕左上角;  
16. const char *msg;  
17. "\n"  
18. "\n"  
19. "\n"  // console is 40 cols x 30 lines  
20. "\n"  
21. "\n"  
22. "\n"  
23. "\n"  
24. "\n"  
25. "\n"  
26. "\n"  
27. "             A N D R O I D ";  
28.             write(fd, msg, strlen(msg));  
29.             close(fd);  
30.         }  
31.     }  
32. return 0;  
33. }


(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化;




1. /* skip mounting filesystems in charger mode */ 
2. if (strcmp(bootmode, "charger") != 0) { 
3. "early-fs", action_add_queue_tail); 
4. "fs", action_add_queue_tail); 
5. "post-fs", action_add_queue_tail); 
6. "post-fs-data", action_add_queue_tail); 
7. }



1. /* skip mounting filesystems in charger mode */  
2. if (strcmp(bootmode, "charger") != 0) {  
3. "early-fs", action_add_queue_tail);  
4. "fs", action_add_queue_tail);  
5. "post-fs", action_add_queue_tail);  
6. "post-fs-data", action_add_queue_tail);  
7. }


(3)、如果为charger,则调用charger.c




    1. action_for_each_trigger("charger", action_add_queue_tail);



    1. action_for_each_trigger("charger", action_add_queue_tail);

     


    我们在后面细分charger这部分。

    4、charger.c

    这部分就是我们充电部分,充电画面显示的实现。

    system\core\charger\charger.c



    1. int main(int argc,char **argv) 
    2. { 
    3. ……………… 
    4.     klog_set_level(CHARGER_KLOG_LEVEL); 
    5.     dump_last_kmsg(); 
    6. "--------------- STARTING CHARGER MODE ---------------\n"); 
    7.  
    8.     gr_init(); 
    9. //(1)、初始化graphics,包括buf大小; 
    10.  
    11. //(2)初始化按键; 
    12.     
    13. fd = uevent_open_socket(64*1024, true); 
    14. if (fd >= 0) { 
    15.         fcntl(fd, F_SETFL, O_NONBLOCK); 
    16.         ev_add_fd(fd, uevent_callback, charger); 
    17.     } 
    18.  
    19.     charger->uevent_fd = fd; 
    20. "/sys/class/power_supply","add");//(3)、创建/sys/class/power_supply结点,把socket信息通知应用层; 
    21.      
    22. ret = res_create_surface("charger/battery_fail", &charger->surf_unknown); 
    23. if (ret < 0) { 
    24. "Cannot load image\n"); 
    25.         charger->surf_unknown = NULL; 
    26.     } 
    27. for (i = 0; i < charger->batt_anim->num_frames; i++) {//(4)、这里是显示charger logo,res_create_surface显示图片函数; 
    28. struct frame *frame = &charger->batt_anim->frames[i]; 
    29.         ret = res_create_surface(frame->name, &frame->surface); 
    30. if (ret < 0) { 
    31. "Cannot load image %s\n", frame->name); 
    32. /* TODO: free the already allocated surfaces... */ 
    33.             charger->batt_anim->num_frames = 0; 
    34.             charger->batt_anim->num_cycles = 1; 
    35. break; 
    36.         } 
    37.     } 
    38. ev_sync_key_state(set_key_callback, charger); 
    39. true); 
    40.  
    41.     charger->next_screen_transition = now - 1; 
    42.     charger->next_key_check = -1; 
    43.     charger->next_pwr_check = -1; 
    44.     reset_animation(charger->batt_anim); 
    45.     kick_animation(charger->batt_anim); 
    46. //(5)、event_loop循环,电池状态,检测按键是否按下; 
    47. return 0; 
    48.  
    49. }




    1. int main(int argc, char **argv)  
    2. {  
    3. ………………  
    4.     klog_set_level(CHARGER_KLOG_LEVEL);  
    5.     dump_last_kmsg();  
    6. "--------------- STARTING CHARGER MODE ---------------\n");  
    7.   
    8.     gr_init();  
    9. //(1)、初始化graphics,包括buf大小;  
    10.   
    11. //(2)初始化按键;  
    12.      
    13. fd = uevent_open_socket(64*1024, true);  
    14. if (fd >= 0) {  
    15.         fcntl(fd, F_SETFL, O_NONBLOCK);  
    16.         ev_add_fd(fd, uevent_callback, charger);  
    17.     }  
    18.   
    19.     charger->uevent_fd = fd;  
    20. "/sys/class/power_supply", "add");//(3)、创建/sys/class/power_supply结点,把socket信息通知应用层;  
    21.       
    22. ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);  
    23. if (ret < 0) {  
    24. "Cannot load image\n");  
    25.         charger->surf_unknown = NULL;  
    26.     }  
    27. for (i = 0; i < charger->batt_anim->num_frames; i++) {//(4)、这里是显示charger logo,res_create_surface显示图片函数;  
    28. struct frame *frame = &charger->batt_anim->frames[i];  
    29.         ret = res_create_surface(frame->name, &frame->surface);  
    30. if (ret < 0) {  
    31. "Cannot load image %s\n", frame->name);  
    32. /* TODO: free the already allocated surfaces... */  
    33.             charger->batt_anim->num_frames = 0;  
    34.             charger->batt_anim->num_cycles = 1;  
    35. break;  
    36.         }  
    37.     }  
    38. ev_sync_key_state(set_key_callback, charger);  
    39. true);  
    40.   
    41.     charger->next_screen_transition = now - 1;  
    42.     charger->next_key_check = -1;  
    43.     charger->next_pwr_check = -1;  
    44.     reset_animation(charger->batt_anim);  
    45.     kick_animation(charger->batt_anim);  
    46. //(5)、event_loop循环,电池状态,检测按键是否按下;  
    47. return 0;  
    48.   
    49. }
    1.  


    (1)、初始化graphics,包括buf大小

    android/bootable/recovery/minui/graphics.c

    gr_init():minui/graphics.c[settty0 to graphic mode, open fb0],设制tty0为图形模式,打开fb0;



    1. int gr_init(void) 
    2. { 
    3.     gglInit(&gr_context); 
    4.     GGLContext *gl = gr_context; 
    5.     gr_init_font(); 
    6. "/dev/tty0", O_RDWR | O_SYNC); 
    7. if (gr_vt_fd < 0) { 
    8. // This is non-fatal; post-Cupcake kernels don't have tty0. 
    9. "can't open /dev/tty0"); 
    10.  
    11. else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) { 
    12. // However, if we do open tty0, we expect the ioctl to work. 
    13. "failed KDSETMODE to KD_GRAPHICS on tty0"); 
    14.         gr_exit(); 
    15. return -1; 
    16.     } 
    17.     gr_fb_fd = get_framebuffer(gr_framebuffer); 
    18. if (gr_fb_fd < 0) { 
    19.         gr_exit(); 
    20. return -1; 
    21.     } 
    22.     get_memory_surface(&gr_mem_surface); 
    23. "framebuffer: fd %d (%d x %d)\n", 
    24.             gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); 
    25. /* start with 0 as front (displayed) and 1 as back (drawing) */ 
    26.     gr_active_fb = 0; 
    27.     set_active_framebuffer(0); 
    28.     gl->colorBuffer(gl, &gr_mem_surface); 
    29.     gl->activeTexture(gl, 0); 
    30.     gl->enable(gl, GGL_BLEND); 
    31.     gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA); 
    32. true); 
    33. false); 
    34. return 0; 
    35.  
    36. }




    1. int gr_init(void)  
    2. {  
    3.     gglInit(&gr_context);  
    4.     GGLContext *gl = gr_context;  
    5.     gr_init_font();  
    6. "/dev/tty0", O_RDWR | O_SYNC);  
    7. if (gr_vt_fd < 0) {  
    8. // This is non-fatal; post-Cupcake kernels don't have tty0.  
    9. "can't open /dev/tty0");  
    10.   
    11. else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) {  
    12. // However, if we do open tty0, we expect the ioctl to work.  
    13. "failed KDSETMODE to KD_GRAPHICS on tty0");  
    14.         gr_exit();  
    15. return -1;  
    16.     }  
    17.     gr_fb_fd = get_framebuffer(gr_framebuffer);  
    18. if (gr_fb_fd < 0) {  
    19.         gr_exit();  
    20. return -1;  
    21.     }  
    22.     get_memory_surface(&gr_mem_surface);  
    23. "framebuffer: fd %d (%d x %d)\n",  
    24.             gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);  
    25. /* start with 0 as front (displayed) and 1 as back (drawing) */  
    26.     gr_active_fb = 0;  
    27.     set_active_framebuffer(0);  
    28.     gl->colorBuffer(gl, &gr_mem_surface);  
    29.     gl->activeTexture(gl, 0);  
    30.     gl->enable(gl, GGL_BLEND);  
    31.     gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);  
    32. true);  
    33. false);  
    34. return 0;  
    35.   
    36. }



    (2)android/bootable/recovery/minui/events.c

    ev_init():minui/events.c[open /dev/input/event*]打开 /dev/input/event*

    这部分是在,充电状态下,按键操作的初始化,比如:短按显示充电logo,长按开机,初始化代码如下。




    1. int ev_init(ev_callback input_cb,void *data) 
    2. { 
    3.     DIR *dir; 
    4. struct dirent *de; 
    5. int fd; 
    6. "/dev/input");//打开驱动结点; 
    7. if(dir != 0) { 
    8. while((de = readdir(dir))) { 
    9. long ev_bits[BITS_TO_LONGS(EV_MAX)]; 
    10. //            fprintf(stderr,"/dev/input/%s\n", de->d_name); 
    11. if(strncmp(de->d_name,"event",5))continue; 
    12.             fd = openat(dirfd(dir), de->d_name, O_RDONLY); 
    13. if(fd < 0) continue; 
    14. /* read the evbits of the input device */ 
    15. if (ioctl(fd, EVIOCGBIT(0,sizeof(ev_bits)), ev_bits) < 0) { 
    16.                 close(fd); 
    17. continue; 
    18.             } 
    19. /* TODO: add ability to specify event masks. For now, just assume
    20.              * that only EV_KEY and EV_REL event types are ever needed. */ 
    21. if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) { 
    22.                 close(fd); 
    23. continue; 
    24.             } 
    25.             ev_fds[ev_count].fd = fd; 
    26.             ev_fds[ev_count].events = POLLIN; 
    27.             ev_fdinfo[ev_count].cb = input_cb; 
    28.             ev_fdinfo[ev_count].data = data; 
    29.             ev_count++; 
    30.             ev_dev_count++; 
    31. if(ev_dev_count == MAX_DEVICES)break; 
    32.         } 
    33.     } 
    34. return 0; 
    35. }




    1. int ev_init(ev_callback input_cb, void *data)  
    2. {  
    3.     DIR *dir;  
    4. struct dirent *de;  
    5. int fd;  
    6. "/dev/input");//打开驱动结点;  
    7. if(dir != 0) {  
    8. while((de = readdir(dir))) {  
    9. long ev_bits[BITS_TO_LONGS(EV_MAX)];  
    10. //            fprintf(stderr,"/dev/input/%s\n", de->d_name);  
    11. if(strncmp(de->d_name,"event",5)) continue;  
    12.             fd = openat(dirfd(dir), de->d_name, O_RDONLY);  
    13. if(fd < 0) continue;  
    14. /* read the evbits of the input device */  
    15. if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {  
    16.                 close(fd);  
    17. continue;  
    18.             }  
    19. /* TODO: add ability to specify event masks. For now, just assume
    20.              * that only EV_KEY and EV_REL event types are ever needed. */  
    21. if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {  
    22.                 close(fd);  
    23. continue;  
    24.             }  
    25.             ev_fds[ev_count].fd = fd;  
    26.             ev_fds[ev_count].events = POLLIN;  
    27.             ev_fdinfo[ev_count].cb = input_cb;  
    28.             ev_fdinfo[ev_count].data = data;  
    29.             ev_count++;  
    30.             ev_dev_count++;  
    31. if(ev_dev_count == MAX_DEVICES) break;  
    32.         }  
    33.     }  
    34. return 0;  
    35. }


    (3)、创建/sys/class/power_supply结点,把socket信息通知应用层

    uevent_open_socket这个函数是通过kobject_uevent的方式通知的应用层,就是往一个socket广播一个消息,只需要在应用层打开socket监听NETLINK_KOBJECT_UEVENT组的消息,就可以收到了,主要是创建了socket接口获得uevent的文件描述符,然后触发/sys/class/power_supply目录及其子目录下的uevent,然后接受并创建设备节点,至此设备节点才算创建。

    (4)、这里显示charger logo,res_create_surface显示图片函数;

    res_create_surface:minui/resource.c[create surfaces for all bitmaps used later, include icons, bmps]

    创建surface为所以的位图,包括图标、位图。  这些图片的位置为:system\core\charger\images


    Android 10 MTK关机充电流程 安卓关机充电_初始化_05

    (5)、event_loop循环,电池状态,检测按键是否按下;

    5、event_loop

           这个函数判断按键状态,DC是否插拔。如果长按开机:执行android_reboot(ANDROID_RB_RESTART,0, 0);如果拔出DC:执行android_reboot(ANDROID_RB_POWEROFF,0, 0);



    1. static void event_loop(struct charger *charger) 
    2. { 
    3. int ret; 
    4. while (true) { 
    5. //(1)、获得当前时间; 
    6. "[%lld] event_loop()\n", now); 
    7. //(2)、检查按键状态; 
    8. // (3)、检查DC是否拔出; 
    9. /* do screen update last in case any of the above want to start
    10.          * screen transitions (animations, etc)
    11.          */ 
    12. //(4)、对按键时间状态标志位的判断,显示不同电量的充电logo; 
    13.         wait_next_event(charger, now); 
    14.     } 
    15. }
    1.  



    1. static void event_loop(struct charger *charger)  
    2. {  
    3. int ret;  
    4. while (true) {  
    5. //(1)、获得当前时间;  
    6. "[%lld] event_loop()\n", now);  
    7. //(2)、检查按键状态;  
    8. // (3)、检查DC是否拔出;   
    9. /* do screen update last in case any of the above want to start
    10.          * screen transitions (animations, etc)
    11.          */  
    12. //(4)、对按键时间状态标志位的判断,显示不同电量的充电logo;   
    13.         wait_next_event(charger, now);  
    14.     }  
    15. }


    (1)、获得当前时间;

    int64_t now = curr_time_ms();

           这个时间来判断,有没有屏幕超时,如果超时关闭屏幕充电logo显示。

    (2)、检查按键状态;



    1. static void handle_input_state(struct charger *charger, int64_t now) 
    2. { 
    3.     process_key(charger, KEY_POWER, now); 
    4. if (charger->next_key_check != -1 && now > charger->next_key_check) 
    5.         charger->next_key_check = -1; 
    6. } 
    7. 我们再看下:process_key(charger, KEY_POWER, now); 
    8. static void process_key(struct charger *charger,int code, int64_t now) 
    9. { 
    10. ……………… 
    11. if (code == KEY_POWER) { 
    12. if (key->down) { 
    13.             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME; 
    14. if (now >= reboot_timeout) {//如果长按power键,就重新启动,也就是重启开机; 
    15. "[%lld] rebooting\n", now); 
    16. //重启命令; 
    17.             } 
    18.     ……………… 
    19.     } 
    20.  
    21. false; 
    22. }




    1. static void handle_input_state(struct charger *charger, int64_t now)  
    2. {  
    3.     process_key(charger, KEY_POWER, now);  
    4. if (charger->next_key_check != -1 && now > charger->next_key_check)  
    5.         charger->next_key_check = -1;  
    6. }  
    7. 我们再看下:process_key(charger, KEY_POWER, now);  
    8. static void process_key(struct charger *charger, int code, int64_t now)  
    9. {  
    10. ………………  
    11. if (code == KEY_POWER) {  
    12. if (key->down) {  
    13.             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;  
    14. if (now >= reboot_timeout) {//如果长按power键,就重新启动,也就是重启开机;  
    15. "[%lld] rebooting\n", now);  
    16. //重启命令;  
    17.             }  
    18.     ………………  
    19.     }  
    20.   
    21. false;  
    22. }


    (3)、检查DC是否拔出;

    handle_power_supply_state(charger, now);




    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. "[%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. "[%lld] shutting down\n", now); 
    10. //如果DC拔出,则关机; 
    11.         }  
    12. ……………… 
    13. }



    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. "[%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. "[%lld] shutting down\n", now);  
    10. //如果DC拔出,则关机;  
    11.         }   
    12. ………………  
    13. }


    (4)、对按键时间状态标志位的判断,显示不同电量的充电logo;

    update_screen_state(charger, now);

    这个函数比较长了,其实做用就是:我们在状态的过程中,充电logo的电量是要增加的,比如电量是20%时,要从第一格开始闪烁;如果是80%时,则要从第三格开始闪烁,电量显示就是通过这个函数来计算实现的。



    1. static void update_screen_state(struct charger *charger, int64_t now) 
    2. { 
    3. struct animation *batt_anim = charger->batt_anim; 
    4. int cur_frame; 
    5. int disp_time; 
    6.  
    7. if (!batt_anim->run || now < charger->next_screen_transition) 
    8. return; 
    9.  
    10. /* animation is over, blank screen and leave */ 
    11. if (batt_anim->cur_cycle == batt_anim->num_cycles) { 
    12.         reset_animation(batt_anim); 
    13.         charger->next_screen_transition = -1; 
    14. true); 
    15. "[%lld] animation done\n", now); 
    16. return; 
    17.     } 
    18.  
    19.     disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time; 
    20.  
    21. /* animation starting, set up the animation */ 
    22. if (batt_anim->cur_frame == 0) { 
    23. int batt_cap; 
    24. int ret; 
    25.  
    26. "[%lld] animation starting\n", now); 
    27.         batt_cap = get_battery_capacity(charger); 
    28. if (batt_cap >= 0 && batt_anim->num_frames != 0) { 
    29. int i; 
    30.  
    31. /* find first frame given current capacity */ 
    32. for (i = 1; i < batt_anim->num_frames; i++) { 
    33. if (batt_cap < batt_anim->frames[i].min_capacity) 
    34. break; 
    35.             } 
    36.             batt_anim->cur_frame = i - 1; 
    37.  
    38. /* show the first frame for twice as long */ 
    39.             disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2; 
    40.         } 
    41.  
    42.         batt_anim->capacity = batt_cap; 
    43.     } 
    44.  
    45. /* unblank the screen  on first cycle */ 
    46. if (batt_anim->cur_cycle == 0) 
    47. false); 
    48.  
    49. /* draw the new frame (@ cur_frame) */ 
    50.     redraw_screen(charger); 
    51.  
    52. /* if we don't have anim frames, we only have one image, so just bump
    53.      * the cycle counter and exit
    54.      */ 
    55. if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) { 
    56. "[%lld] animation missing or unknown battery status\n", now); 
    57.         charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME; 
    58.         batt_anim->cur_cycle++; 
    59. return; 
    60.     } 
    61.  
    62. /* schedule next screen transition */ 
    63.     charger->next_screen_transition = now + disp_time; 
    64.  
    65. /* advance frame cntr to the next valid frame
    66.      * if necessary, advance cycle cntr, and reset frame cntr
    67.      */ 
    68.     batt_anim->cur_frame++; 
    69.  
    70. /* if the frame is used for level-only, that is only show it when it's
    71.      * the current level, skip it during the animation.
    72.      */ 
    73. while (batt_anim->cur_frame < batt_anim->num_frames && 
    74.            batt_anim->frames[batt_anim->cur_frame].level_only) 
    75.         batt_anim->cur_frame++; 
    76. if (batt_anim->cur_frame >= batt_anim->num_frames) { 
    77.         batt_anim->cur_cycle++; 
    78.         batt_anim->cur_frame = 0; 
    79.  
    80. /* don't reset the cycle counter, since we use that as a signal
    81.          * in a test above to check if animation is over
    82.          */ 
    83.     } 
    84. }



    1. static void update_screen_state(struct charger *charger, int64_t now)  
    2. {  
    3. struct animation *batt_anim = charger->batt_anim;  
    4. int cur_frame;  
    5. int disp_time;  
    6.   
    7. if (!batt_anim->run || now < charger->next_screen_transition)  
    8. return;  
    9.   
    10. /* animation is over, blank screen and leave */  
    11. if (batt_anim->cur_cycle == batt_anim->num_cycles) {  
    12.         reset_animation(batt_anim);  
    13.         charger->next_screen_transition = -1;  
    14. true);  
    15. "[%lld] animation done\n", now);  
    16. return;  
    17.     }  
    18.   
    19.     disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;  
    20.   
    21. /* animation starting, set up the animation */  
    22. if (batt_anim->cur_frame == 0) {  
    23. int batt_cap;  
    24. int ret;  
    25.   
    26. "[%lld] animation starting\n", now);  
    27.         batt_cap = get_battery_capacity(charger);  
    28. if (batt_cap >= 0 && batt_anim->num_frames != 0) {  
    29. int i;  
    30.   
    31. /* find first frame given current capacity */  
    32. for (i = 1; i < batt_anim->num_frames; i++) {  
    33. if (batt_cap < batt_anim->frames[i].min_capacity)  
    34. break;  
    35.             }  
    36.             batt_anim->cur_frame = i - 1;  
    37.   
    38. /* show the first frame for twice as long */  
    39.             disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;  
    40.         }  
    41.   
    42.         batt_anim->capacity = batt_cap;  
    43.     }  
    44.   
    45. /* unblank the screen  on first cycle */  
    46. if (batt_anim->cur_cycle == 0)  
    47. false);  
    48.   
    49. /* draw the new frame (@ cur_frame) */  
    50.     redraw_screen(charger);  
    51.   
    52. /* if we don't have anim frames, we only have one image, so just bump
    53.      * the cycle counter and exit
    54.      */  
    55. if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {  
    56. "[%lld] animation missing or unknown battery status\n", now);  
    57.         charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;  
    58.         batt_anim->cur_cycle++;  
    59. return;  
    60.     }  
    61.   
    62. /* schedule next screen transition */  
    63.     charger->next_screen_transition = now + disp_time;  
    64.   
    65. /* advance frame cntr to the next valid frame
    66.      * if necessary, advance cycle cntr, and reset frame cntr
    67.      */  
    68.     batt_anim->cur_frame++;  
    69.   
    70. /* if the frame is used for level-only, that is only show it when it's
    71.      * the current level, skip it during the animation.
    72.      */  
    73. while (batt_anim->cur_frame < batt_anim->num_frames &&  
    74.            batt_anim->frames[batt_anim->cur_frame].level_only)  
    75.         batt_anim->cur_frame++;  
    76. if (batt_anim->cur_frame >= batt_anim->num_frames) {  
    77.         batt_anim->cur_cycle++;  
    78.         batt_anim->cur_frame = 0;  
    79.   
    80. /* don't reset the cycle counter, since we use that as a signal
    81.          * in a test above to check if animation is over
    82.          */  
    83.     }  
    84. }


    下面是不能容量时显示logo的函数:



    1. static struct frame batt_anim_frames[] = { 
    2.     { 
    3. "charger/battery_0", 
    4.         .disp_time = 750, 
    5.         .min_capacity = 0, 
    6.     }, 
    7.     { 
    8. "charger/battery_1", 
    9.         .disp_time = 750, 
    10.         .min_capacity = 20, 
    11.     }, 
    12.     { 
    13. "charger/battery_2", 
    14.         .disp_time = 750, 
    15.         .min_capacity = 40, 
    16.     }, 
    17.     { 
    18. "charger/battery_3", 
    19.         .disp_time = 750, 
    20.         .min_capacity = 60, 
    21.     }, 
    22.     { 
    23. "charger/battery_4", 
    24.         .disp_time = 750, 
    25.         .min_capacity = 80, 
    26. true, 
    27.     }, 
    28.     { 
    29. "charger/battery_5", 
    30.         .disp_time = 750, 
    31.         .min_capacity = BATTERY_FULL_THRESH, 
    32.     }, 
    33. };