充电的代码和图标在system/core/charger中,会编译成名字为charger的可执行文件,打包进ramdisk中,在init.rc中脚本启动:
[java] view plain copy print ?
1. on charger
2. 0
3. export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
4. export LD_LIBRARY_PATH /vendor/lib:/system/lib
5. setprop sys.usb.config adb
6.
7. service charger /charger
8. disabled
on charger
setprop ro.boot.charger.emmc 0
export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /vendor/lib:/system/lib
setprop sys.usb.config adb
service charger /charger
disabled
on charger会触发该服务执行,所以现在要分析的就是on charger是如被何触发的。
在system/core/init/init.c中:
[java] view plain copy print ?
1. is_charger = !strcmp(bootmode, "charger");
2. 。。。。。。
3. if
4. "charger", action_add_queue_tail);
5. else
6. "early-boot", action_add_queue_tail);
7. "boot", action_add_queue_tail);
8. }
is_charger = !strcmp(bootmode, "charger");
。。。。。。
if (is_charger) {
action_for_each_trigger("charger", action_add_queue_tail);
} else {
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
}
可见,要触发charger, is_charger为真即可,即bootmode为“charger”,所以继续跟踪代码:
[java] view plain copy print ?
1. struct {
2. const char
3. const char
4. const char
5. } prop_map[] = {
6. // { "ro.boot.serialno", "ro.serialno", "", },
7. "ro.boot.mode", "ro.bootmode", "unknown", },
8. "ro.boot.baseband", "ro.baseband", "unknown", },
9. "ro.boot.bootloader", "ro.bootloader", "unknown", },
10. };
11.
12. for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
13. ret = property_get(prop_map[i].src_prop, tmp);
14. if (ret > 0)
15. property_set(prop_map[i].dest_prop, tmp);
16. else
17. property_set(prop_map[i].dest_prop, prop_map[i].def_val);
18. }
19.
20. ret = property_get("ro.boot.console", tmp);
21. if
22. strlcpy(console, tmp, sizeof(console));
23.
24. /* save a copy for init's usage during boot */
25. property_get("ro.bootmode", tmp);
26. strlcpy(bootmode, tmp, sizeof(bootmode));
struct {
const char *src_prop;
const char *dest_prop;
const char *def_val;
} prop_map[] = {
// { "ro.boot.serialno", "ro.serialno", "", },
{ "ro.boot.mode", "ro.bootmode", "unknown", },
{ "ro.boot.baseband", "ro.baseband", "unknown", },
{ "ro.boot.bootloader", "ro.bootloader", "unknown", },
};
for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
ret = property_get(prop_map[i].src_prop, tmp);
if (ret > 0)
property_set(prop_map[i].dest_prop, tmp);
else
property_set(prop_map[i].dest_prop, prop_map[i].def_val);
}
ret = property_get("ro.boot.console", tmp);
if (ret)
strlcpy(console, tmp, sizeof(console));
/* save a copy for init's usage during boot */
property_get("ro.bootmode", tmp);
strlcpy(bootmode, tmp, sizeof(bootmode));
读取“ro.bootmode”得到的,但是“ro.bootmode”的属性又是通过"ro.boot.mode"来设置的。
而这个属性是读取/proc/cmdline参数,最终在import_kernel_nv函数中设置的:
[java] view plain copy print ?
1. if (!strcmp(name,"qemu")) {
2. strlcpy(qemu, value, sizeof(qemu));
3. else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
4. const char *boot_prop_name = name + 12;
5. char
6. int
7.
8. "ro.boot.%s", boot_prop_name);
9. if
10. property_set(prop, value);
11. }
12. }
if (!strcmp(name,"qemu")) {
strlcpy(qemu, value, sizeof(qemu));
} else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
const char *boot_prop_name = name + 12;
char prop[PROP_NAME_MAX];
int cnt;
cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
if (cnt < PROP_NAME_MAX)
property_set(prop, value);
}
}
命令行是kernel传进来的,所以要进入驱动中去了。
在kernel/drivers/power/rk29_charger_display.c文件中:
[java] view plain copy print ?
1. static void add_bootmode_charger_to_cmdline(void)
2. {
3. char *pmode=" androidboot.mode=charger";
4. //int off = strlen(saved_command_line);
5. char *new_command_line = kzalloc(strlen(saved_command_line) + strlen(pmode) + 1, GFP_KERNEL);
6. "%s%s", saved_command_line, pmode);
7. saved_command_line = new_command_line;
8. //strcpy(saved_command_line+off,pmode);
9.
10. //int off = strlen(boot_command_line);
11. //strcpy(boot_command_line+off,pmode);
12.
13. "Kernel command line: %s\n", saved_command_line);
14. }
static void add_bootmode_charger_to_cmdline(void)
{
char *pmode=" androidboot.mode=charger";
//int off = strlen(saved_command_line);
char *new_command_line = kzalloc(strlen(saved_command_line) + strlen(pmode) + 1, GFP_KERNEL);
sprintf(new_command_line, "%s%s", saved_command_line, pmode);
saved_command_line = new_command_line;
//strcpy(saved_command_line+off,pmode);
//int off = strlen(boot_command_line);
//strcpy(boot_command_line+off,pmode);
printk("Kernel command line: %s\n", saved_command_line);
}
终于看到了,就是在这里设置了androidboot.mode=charger属性。
继续跟进什么条件下才设置该属性,发现关机充电情况下,设置该属性,机子运行charger执行文件;这时候如果电源键按下超过两秒,charger执行文件重启机子,把标记设置为BOOT_MODE_CHARGE;重启后在驱动中,判断电量如果小于5%(可以修改该值),继续进入charger模式;否则不再设置androidboot.mode=charger属性,系统不会再执行charger文件,系统进入正常启动。
[java] view plain copy print ?
1. on charger
2. 0
3. export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
4. export LD_LIBRARY_PATH /vendor/lib:/system/lib
5. setprop sys.usb.config adb
6.
7. service charger /charger
8. disabled
on charger
setprop ro.boot.charger.emmc 0
export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /vendor/lib:/system/lib
setprop sys.usb.config adb
service charger /charger
disabled
on charger会触发该服务执行,所以现在要分析的就是on charger是如被何触发的。
在system/core/init/init.c中:
[java] view plain copy print ?
1. is_charger = !strcmp(bootmode, "charger");
2. 。。。。。。
3. if
4. "charger", action_add_queue_tail);
5. else
6. "early-boot", action_add_queue_tail);
7. "boot", action_add_queue_tail);
8. }
is_charger = !strcmp(bootmode, "charger");
。。。。。。
if (is_charger) {
action_for_each_trigger("charger", action_add_queue_tail);
} else {
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
}
可见,要触发charger, is_charger为真即可,即bootmode为“charger”,所以继续跟踪代码:
[java] view plain copy print ?
1. struct {
2. const char
3. const char
4. const char
5. } prop_map[] = {
6. // { "ro.boot.serialno", "ro.serialno", "", },
7. "ro.boot.mode", "ro.bootmode", "unknown", },
8. "ro.boot.baseband", "ro.baseband", "unknown", },
9. "ro.boot.bootloader", "ro.bootloader", "unknown", },
10. };
11.
12. for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
13. ret = property_get(prop_map[i].src_prop, tmp);
14. if (ret > 0)
15. property_set(prop_map[i].dest_prop, tmp);
16. else
17. property_set(prop_map[i].dest_prop, prop_map[i].def_val);
18. }
19.
20. ret = property_get("ro.boot.console", tmp);
21. if
22. strlcpy(console, tmp, sizeof(console));
23.
24. /* save a copy for init's usage during boot */
25. property_get("ro.bootmode", tmp);
26. strlcpy(bootmode, tmp, sizeof(bootmode));
struct {
const char *src_prop;
const char *dest_prop;
const char *def_val;
} prop_map[] = {
// { "ro.boot.serialno", "ro.serialno", "", },
{ "ro.boot.mode", "ro.bootmode", "unknown", },
{ "ro.boot.baseband", "ro.baseband", "unknown", },
{ "ro.boot.bootloader", "ro.bootloader", "unknown", },
};
for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
ret = property_get(prop_map[i].src_prop, tmp);
if (ret > 0)
property_set(prop_map[i].dest_prop, tmp);
else
property_set(prop_map[i].dest_prop, prop_map[i].def_val);
}
ret = property_get("ro.boot.console", tmp);
if (ret)
strlcpy(console, tmp, sizeof(console));
/* save a copy for init's usage during boot */
property_get("ro.bootmode", tmp);
strlcpy(bootmode, tmp, sizeof(bootmode));
读取“ro.bootmode”得到的,但是“ro.bootmode”的属性又是通过"ro.boot.mode"来设置的。
而这个属性是读取/proc/cmdline参数,最终在import_kernel_nv函数中设置的:
[java] view plain copy print ?
1. if (!strcmp(name,"qemu")) {
2. strlcpy(qemu, value, sizeof(qemu));
3. else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
4. const char *boot_prop_name = name + 12;
5. char
6. int
7.
8. "ro.boot.%s", boot_prop_name);
9. if
10. property_set(prop, value);
11. }
12. }
if (!strcmp(name,"qemu")) {
strlcpy(qemu, value, sizeof(qemu));
} else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
const char *boot_prop_name = name + 12;
char prop[PROP_NAME_MAX];
int cnt;
cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
if (cnt < PROP_NAME_MAX)
property_set(prop, value);
}
}
命令行是kernel传进来的,所以要进入驱动中去了。
在kernel/drivers/power/rk29_charger_display.c文件中:
[java] view plain copy print ?
1. static void add_bootmode_charger_to_cmdline(void)
2. {
3. char *pmode=" androidboot.mode=charger";
4. //int off = strlen(saved_command_line);
5. char *new_command_line = kzalloc(strlen(saved_command_line) + strlen(pmode) + 1, GFP_KERNEL);
6. "%s%s", saved_command_line, pmode);
7. saved_command_line = new_command_line;
8. //strcpy(saved_command_line+off,pmode);
9.
10. //int off = strlen(boot_command_line);
11. //strcpy(boot_command_line+off,pmode);
12.
13. "Kernel command line: %s\n", saved_command_line);
14. }
static void add_bootmode_charger_to_cmdline(void)
{
char *pmode=" androidboot.mode=charger";
//int off = strlen(saved_command_line);
char *new_command_line = kzalloc(strlen(saved_command_line) + strlen(pmode) + 1, GFP_KERNEL);
sprintf(new_command_line, "%s%s", saved_command_line, pmode);
saved_command_line = new_command_line;
//strcpy(saved_command_line+off,pmode);
//int off = strlen(boot_command_line);
//strcpy(boot_command_line+off,pmode);
printk("Kernel command line: %s\n", saved_command_line);
}
终于看到了,就是在这里设置了androidboot.mode=charger属性。
继续跟进什么条件下才设置该属性,发现关机充电情况下,设置该属性,机子运行charger执行文件;这时候如果电源键按下超过两秒,charger执行文件重启机子,把标记设置为BOOT_MODE_CHARGE;重启后在驱动中,判断电量如果小于5%(可以修改该值),继续进入charger模式;否则不再设置androidboot.mode=charger属性,系统不会再执行charger文件,系统进入正常启动。