关机充电 分析 -- charger代码分析(Android4.2)
http://blog.csdn.net/u010223349/article/details/8822747
Android charger源代码位于system/core/charger目录下,代码量不大,下面就对charger代码作个简单的分析。
一、main函数
int main(int argc, char **argv)
{
int ret;
struct charger *charger = &charger_state; //charger_state是一个charger结构体对象,详见下文第二部分
int64_t now = curr_time_ms() - 1; //保存当前时间
int fd;
int i;
list_init(&charger->supplies); //初始化供电设备双向链表
klog_init(); //设置log输出设备,这里指向/dev/_ksmg_
klog_set_level(CHARGER_KLOG_LEVEL); //设备打印等级为6
dump_last_kmsg(); //把/dev/last_kmsg中的信息写到/dev/_kmsg_
LOGI("--------------- STARTING CHARGER MODE ---------------\n");
//android提供了一个库minui用于简单的UI输出,源码在bootable/recovery/minui中,
//gr_init()和gr_font_size()为minui库提供方法,gr_init()为UI输出作准备,gr_font_size()获得字体大小
gr_init();
gr_font_size(&char_width, &char_height);
//遍历/dev/input目录下的设备,将EV_REL和EV_KEY设备的信息保存到ev_fds[]等结构体中
ev_init(input_callback, charger);
fd = uevent_open_socket(64*1024, true); //创建一个socket用于接收kernel的uevent
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"); //让kernel重新发送event
//res_create_surface()为minui库中提供,用于将一张图片生成一个surface
//这里是生成了一个用于表示电池错误的surface
ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < 0) {
LOGE("Cannot load image\n");
charger->surf_unknown = NULL;
}
//充电画面由几张图片组成,每张图片被称为一帧,charger变量存放的是charger_state
//变量的指针,charger_state已被初始化过,但是每一个frame的surface字段仍没有初始化,
//下面这个循环就是初始化每个frame的surface
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);
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;
}
}
ev_sync_key_state(set_key_callback, charger); //详见下文第三部分
#ifndef CHARGER_DISABLE_INIT_BLANK
gr_fb_blank(true);
#endif
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);
//charger的核心,一个大的循环,详见下文第五部分
event_loop(charger);
return 0;
}
二、charger结构体
struct charger {
int64_t next_screen_transition;
int64_t next_key_check;
int64_t next_pwr_check;
struct key_state keys[KEY_MAX + 1]; //保存按键的状态
int uevent_fd; //接收kernel uevent的描述符
struct listnode supplies; //这个listnode用于建立charger对象的双向链表
int num_supplies; //供电设备的数量
int num_supplies_online; //正在连接的供电设备的数量
struct animation *batt_anim;
gr_surface surf_unknown;
struct power_supply *battery; //电池的信息
};
三、ev_sync_key_state()函数
int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data)
{
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
unsigned i;
int ret;
for (i = 0; i < ev_dev_count; i++) {
int code;
memset(key_bits, 0, sizeof(key_bits));
memset(ev_bits, 0, sizeof(ev_bits));
//测试ev_fds[]中的设备是否有key,如果没有key则continue
ret = ioctl(ev_fds[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
if (ret < 0 || !test_bit(EV_KEY, ev_bits))
continue;
//检测ev_fd[]中的设备key的状态
ret = ioctl(ev_fds[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);
if (ret < 0)
continue;
for (code = 0; code <= KEY_MAX; code++) {
//如果有键被触发,则调用set_key_callback, set_key_callback实现,详见下文第四部分
if (test_bit(code, key_bits))
set_key_cb(code, 1, data);
}
}
return 0;
}
四、set_key_callback()函数
set_key_callback()主要用于记录按键的状态,接受三个参数:code、value、data, code表示键值,value表示按键的状态,data是charger的指针。
static int set_key_callback(int code, int value, void *data)
{
struct charger *charger = data;
int64_t now = curr_time_ms();
int down = !!value;
if (code > KEY_MAX)
return -1;
/* ignore events that don't modify our state */
if (charger->keys[code].down == down)
return 0;
/* only record the down even timestamp, as the amount
* of time the key spent not being pressed is not useful */
if (down)
charger->keys[code].timestamp = now; //记录按下事件的时间
charger->keys[code].down = down; //记录按键的状态
charger->keys[code].pending = true;
if (down) {
LOGV("[%lld] key[%d] down\n", now, code);
} else {
int64_t duration = now - charger->keys[code].timestamp;
int64_t secs = duration / 1000;
int64_t msecs = duration - secs * 1000;
LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
code, secs, msecs);
}
return 0;
}
五、event_loop()函数
static void event_loop(struct charger *charger)
{
int ret;
while (true) {
int64_t now = curr_time_ms();
LOGV("[%lld] event_loop()\n", now);
handle_input_state(charger, now); //详见下文第六部分
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); //根据上面两个handle_设置的状态进行画面更新
//根据上面操作得到的时间间隔来poll设备,如果有事件,
//最后会调用set_key_callback()函数来保存按键的事件,供一次循环使用
wait_next_event(charger, now);
}
}
六、handle_input_state()函数
static void handle_input_state(struct charger *charger, int64_t now)
{
process_key(charger, KEY_POWER, now); //捕捉POWER键的事件,详见下文第七部分
if (charger->next_key_check != -1 && now > charger->next_key_check)
charger->next_key_check = -1;
}
七、process_key()函数
static void process_key(struct charger *charger, int code, int64_t now)
{
struct key_state *key = &charger->keys[code];
int64_t next_key_check;
if (code == KEY_POWER) {
//如果是POWER键,并且是按下事件,则判断是否是长按,
//长按则重启android正常进入系统,否则设置下次检测按键的时间, wait_next_event()会//用到
if (key->down) {
int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
if (now >= reboot_timeout) {
int fd = open("/sys/devices/platform/asoc_spi.1/spi_master/spi1/spi1.0/set_charger_status", O_RDWR);
write(fd, "0x1", strlen("0x1"));
close(fd);
LOGI("[%lld] rebooting\n", now);
android_reboot(ANDROID_RB_RESTART, 0, 0);
} else {
/* if the key is pressed but timeout hasn't expired,
* make sure we wake up at the right-ish time to check
*/
set_next_key_check(charger, key, POWER_ON_KEY_TIME);
}
//如果产生的不是POWER按键的事件,则显示充电动画
} else {
/* if the power key got released, force screen state cycle */
if (key->pending) {
request_suspend(false);
kick_animation(charger->batt_anim);
}
}
}
八、handle_power_supply_state()函数
static void handle_power_supply_state(struct charger *charger, int64_t now)
{
//如果当前没有连接供电设备,则在一定时间内重启android进入系统
if (charger->num_supplies_online == 0) {
request_suspend(false);
if (charger->next_pwr_check == -1) {
charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
} else if (now >= charger->next_pwr_check) {
LOGI("[%lld] shutting down\n", now);
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
} else {
/* otherwise we already have a shutdown timer scheduled */
}
//如果连接了充电设备,则显示充电画面
} else {
/* online supply present, reset shutdown timer if set */
if (charger->next_pwr_check != -1) {
LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
kick_animation(charger->batt_anim);
}
charger->next_pwr_check = -1;
}
}