android手机关机充电的过程就像一个我们看到的一样,插上充电接口->手机启动->屏幕进入log画面->再进入充电动画界面。
稍微有点开发经验的就可以大致了解到它的启动经历了从bootloader->kernal->充电动画应用。
所以我们可以先分析下在bootloader的状态获取。
APP_START(aboot)
.init = aboot_init,
在aboot_init 中可以就是bootloader的app了,它几乎实现了所有的最低层的逻辑,所以电源插上后,没有任何按键触发的或者没有相应的处理,一般会通过从flash或mmc启动内核。
boot_linux_from_mmc();
boot_linux_from_flash();
同理大家应该了解bootloader引导内核启动有一种通过命令行的传参的方式来告知内核一段信息,这个机制就不细说了,毕竟bootloader干了太多的事情,有将内核启动,有留下了遗言,实在辛苦。
void boot_linux(void *kernel, unsigned *tags,
const char *cmdline, unsigned machtype,
void *ramdisk, unsigned ramdisk_size)
上面的函数就是最后的晚餐开始。
update_cmdline((const char*)cmdline);
通过对cmdline 的最后的处理,
static const char *emmc_cmdline = " androidboot.emmc=true";
static const char *usb_sn_cmdline = " androidboot.serialno=";
static const char *efuse_cmdline = " androidboot.efuse=";
static const char *androidboot_mode = " androidboot.mode=";
static const char *display_cmdline = " mdss_mdp.panel=";
static const char *loglevel = " quiet";
static const char *battchg_pause = " androidboot.mode=charger";
static const char *auth_kernel = " androidboot.authorized_kernel=true";
static const char *secondary_gpt_enable = " gpt";
static const char *baseband_apq = " androidboot.baseband=apq";
static const char *baseband_msm = " androidboot.baseband=msm";
static const char *baseband_csfb = " androidboot.baseband=csfb";
static const char *baseband_svlte2a = " androidboot.baseband=svlte2a";
static const char *baseband_mdm = " androidboot.baseband=mdm";
static const char *baseband_sglte = " androidboot.baseband=sglte";
static const char *baseband_dsda = " androidboot.baseband=dsda";
static const char *baseband_dsda2 = " androidboot.baseband=dsda2";
static const char *baseband_sglte2 = " androidboot.baseband=sglte2";
通过选择性的对cmdline的拼接,就把遗言写好了,然后就是内核态了。
static void export_kernel_boot_props(void)
{
char tmp[PROP_VALUE_MAX];
int ret;
unsigned i;
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));
/* if this was given on kernel command line, override what we read
* before (e.g. from /proc/cpuinfo), if anything */
ret = property_get("ro.boot.hardware", tmp);
if (ret)
strlcpy(hardware, tmp, sizeof(hardware));
property_set("ro.hardware", hardware);
snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
property_set("ro.revision", tmp);
/* TODO: these are obsolete. We should delete them */
if (!strcmp(bootmode,"factory"))
property_set("ro.factorytest", "1");
else if (!strcmp(bootmode,"factory2"))
property_set("ro.factorytest", "2");
else
property_set("ro.factorytest", "0");
}
通过属性服务获取了bootmode。
is_charger = !strcmp(bootmode, "charger");
判断成功后就可以启动的一个叫
service charger /charger
class charger
的服务,
这个应用 charger就是实现充电动画的应用。
static struct healthd_mode_ops android_ops = {
.init = healthd_mode_android_init,
.preparetowait = healthd_mode_android_preparetowait,
.heartbeat = healthd_mode_nop_heartbeat,
.battery_update = healthd_mode_android_battery_update,
};
static struct healthd_mode_ops charger_ops = {
.init = healthd_mode_charger_init,
.preparetowait = healthd_mode_charger_preparetowait,
.heartbeat = healthd_mode_charger_heartbeat,
.battery_update = healthd_mode_charger_battery_update,
};
static struct healthd_mode_ops recovery_ops = {
.init = healthd_mode_nop_init,
.preparetowait = healthd_mode_nop_preparetowait,
.heartbeat = healthd_mode_nop_heartbeat,
.battery_update = healthd_mode_nop_battery_update,
};
三种状态下的操作方式。
其中healthd_mode_charger_init就是初始化充电图片。
void healthd_mode_charger_init(struct healthd_config* config)
{
int ret;
int charging_enabled = 1;
struct charger *charger = &charger_state;
int i;
int epollfd;
dump_last_kmsg();
LOGW("--------------- STARTING CHARGER MODE ---------------\n");
if (mode == NORMAL) {
/* check the charging is enabled or not */
ret = read_file_int(CHARGING_ENABLED_PATH, &charging_enabled);
if (!ret && !charging_enabled) {
/* if charging is disabled, reboot and exit power off charging */
LOGW("android charging is disabled, exit!\n");
android_reboot(ANDROID_RB_RESTART, 0, 0);
}
}
ret = ev_init(input_callback, charger);
if (!ret) {
epollfd = ev_get_epollfd();
healthd_register_event(epollfd, charger_event_handler);
}
ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < 0) {
LOGE("Cannot load battery_fail image\n");
charger->surf_unknown = NULL;
}
charger->batt_anim = &battery_animation;
for (i = 0; i < charger->batt_anim->num_frames; i++) {
struct frame *frame = &charger->batt_anim->frames[i];
//ret = res_create_surface(frame->name, &frame->surface);
ret = res_create_display_surface(frame->name, &frame->surface);
if (ret < 0) {
LOGE("Cannot load image %s\n", frame->name);
/* TODO: free the already allocated surfaces... */
charger->batt_anim->num_frames = 0;
charger->batt_anim->num_cycles = 1;
break;
}
}
/*
gr_surface* scale_frames;
int scale_count;
ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
if (ret < 0) {
LOGE("Cannot load battery_scale image\n");
charger->batt_anim->num_frames = 0;
charger->batt_anim->num_cycles = 1;
} else if (scale_count != charger->batt_anim->num_frames) {
LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
scale_count, charger->batt_anim->num_frames);
charger->batt_anim->num_frames = 0;
charger->batt_anim->num_cycles = 1;
} else {
for (i = 0; i < charger->batt_anim->num_frames; i++) {
charger->batt_anim->frames[i].surface = scale_frames[i];
}
}
*/
ev_sync_key_state(set_key_callback, charger);
charger->next_screen_transition = -1;
charger->next_key_check = -1;
charger->next_pwr_check = -1;
healthd_config = config;
}
这块代码主要实现就是初始化一个
static int healthd_init() {
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1) {
KLOG_ERROR(LOG_TAG,
"epoll_create failed; errno=%d\n",
errno);
return -1;
}
healthd_board_init(&healthd_config);
healthd_mode_ops->init(&healthd_config);
wakealarm_init();
uevent_init();
gBatteryMonitor = new BatteryMonitor();
gBatteryMonitor->init(&healthd_config);
return 0;
}
定时启动的函数。
static void healthd_mainloop(void) {
while (1) {
struct epoll_event events[eventct];
int nevents;
int timeout = awake_poll_interval;
int mode_timeout;
mode_timeout = healthd_mode_ops->preparetowait(); //刷图等动作
if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
timeout = mode_timeout;
nevents = epoll_wait(epollfd, events, eventct, timeout);
if (nevents == -1) {
if (errno == EINTR)
continue;
KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)(int))events[n].data.ptr)(events[n].events);
}
if (!nevents)
periodic_chores();
healthd_mode_ops->heartbeat();
}
return;
}