系统进入充电模式时,显示 充电画面,充电画面的代码在/system/core/charger/charger.c,下面对其关键代码进行分析
1)结构体
/*power_supply信息*/
struct power_supply {
/*链表节点*/
struct listnode list;
/*power_supply名称,如rk-ac/rk-usb/rk-bat*/
char name[256];
//power_supply类型,如Mains/USB/Battery
char type[32];
//状态,判断ac,battery或usb的 in/out
bool online;
bool valid;
char cap_path[PATH_MAX];
};
/*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];
//uevent fd,通过此fd读取kernel的power_supply信息
int uevent_fd;
//power_supply链表,存储各个power_supply信息
struct listnode supplies;
//供电源的数量
int num_supplies;
//充电源的数量
int num_supplies_online;
struct animation *batt_anim;
gr_surface surf_unknown;
//电池信息
struct power_supply *battery;
bool state;//the state of screen
};
2)main函数
int main(int argc, char **argv)
{
int ret;
struct charger *charger = &charger_state;
int64_t now = curr_time_ms() - 1;
int fd;
int i;
//初始化power_supply链表
list_init(&charger->supplies);
klog_init();
klog_set_level(CHARGER_KLOG_LEVEL);
//dump_last_kmsg();
LOGI("--------------- STARTING CHARGER MODE ---------------\n");
acquire_wake_lock(PARTIAL_WAKE_LOCK,"PowerManagerService");
gr_init();
gr_font_size(&char_width, &char_height);
//遍历/dev/input目录下的设备,将EV_REL和EV_KEY设备的信息保存到ev_fds[]等结构体中
ev_init(input_callback, charger);//参见下文3)
//创建一个socket用于接收kernel的uevent
fd = uevent_open_socket(64*1024, true);
if (fd >= 0) {
fcntl(fd, F_SETFL, O_NONBLOCK);
ev_add_fd(fd, uevent_callback, charger);//参见下文6)
}
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\n");
charger->surf_unknown = NULL;
}
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);
//主循环函数
event_loop(charger);
return 0;
}
//bootable/recovery/minui/events.c
int ev_init(ev_callback input_cb, void *data)
{
DIR *dir;
struct dirent *de;
int fd;
dir = opendir("/dev/input");
if(dir != 0) {
while((de = readdir(dir))) {
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
// fprintf(stderr,"/dev/input/%s\n", de->d_name);
if(strncmp(de->d_name,"event",5)) continue;
fd = openat(dirfd(dir), de->d_name, O_RDONLY);
if(fd < 0) continue;
/* read the evbits of the input device */
if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
close(fd);
continue;
}
/* TODO: add ability to specify event masks. For now, just assume
* that only EV_KEY and EV_REL event types are ever needed. */
if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {
close(fd);
continue;
}
ev_fds[ev_count].fd = fd;
ev_fds[ev_count].events = POLLIN;
ev_fdinfo[ev_count].cb = input_cb;
ev_fdinfo[ev_count].data = data;
ev_count++;
ev_dev_count++;
if(ev_dev_count == MAX_DEVICES) break;
}
}
return 0;
}
static int input_callback(int fd, short revents, void *data)
{
struct charger *charger = data;
struct input_event ev;
int ret;
//读取input_event信息
ret = ev_get_input(fd, revents, &ev);
if (ret)
return -1;
update_input_state(charger, &ev);
return 0;
}
static void update_input_state(struct charger *charger,
struct input_event *ev)
{
if (ev->type != EV_KEY)
return;
//按键code,按键value
set_key_callback(ev->code, ev->value, 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;
}
4)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);//参见下文5)
//处理充电事件
handle_power_supply_state(charger, now);//参见下文7)
/* do screen update last in case any of the above want to start
* screen transitions (animations, etc)
*/
update_screen_state(charger, now);
wait_next_event(charger, now);
}
}
static void handle_input_state(struct charger *charger, int64_t now)
{
process_key(charger, KEY_POWER, now);
if (charger->next_key_check != -1 && now > charger->next_key_check)
charger->next_key_check = -1;
}
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) {
if (key->down) {
int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
//重启系统
if (now >= reboot_timeout) {
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);
}
} else {
/* if the power key got released, force screen state cycle */
if (key->pending) {
request_suspend(false);
if(charger->state)
{
charger->state = false;
reset_animation(charger->batt_anim);
set_screen_state(SUSPEND);
//read_file(NEW_PATHS[0],lock_name,sizeof(lock_name));
}
else
{
charger->state = true;
charger->next_pwr_check = -1;
charger->next_screen_transition = -1;
kick_animation(charger->batt_anim);
set_screen_state(ON);
}
// kick_animation(charger->batt_anim);
}
}
}
key->pending = false;
}
6)uevent_callback函数
static int uevent_callback(int fd, short revents, void *data)
{
struct charger *charger = data;
if (!(revents & POLLIN))
return -1;
//调用handle_uevent_fd
return handle_uevent_fd(charger, fd);
}
static int handle_uevent_fd(struct charger *charger, int fd)
{
char msg[UEVENT_MSG_LEN+2];
int n;
if (fd < 0)
return -1;
while (true) {
struct uevent uevent;
n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN);
if (n <= 0)
break;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
continue;
msg[n] = '\0';
msg[n+1] = '\0';
//解析msg到uevent
parse_uevent(msg, &uevent);
//处理uevent,更新charger状态
process_uevent(charger, &uevent);
}
return 0;
}
//解析消息到uevent
static void parse_uevent(const char *msg, struct uevent *uevent)
{
/*************************************************************
消息示例
msg-消息
event-uevent
power supply-charger信息
msg=add@/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-bat
event { 'add', '/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-bat', 'power_supply', 'rk-bat', '', '' }
power supply rk-bat (Battery) (action=add num_online=0 num_supplies=1)
msg=add@/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-ac
event { 'add', '/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-ac', 'power_supply', 'rk-ac', '', '1' }
power supply rk-ac (Mains) online (action=add num_online=1 num_supplies=2)
msg=add@/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-usb
event { 'add', '/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-usb', 'power_supply', 'rk-usb', '', '0' }
power supply rk-usb (USB) offline (action=add num_online=1 num_supplies=3)
*
*/
//action = add / change /remove
uevent->action = "";
//path = /devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/
uevent->path = "";
//subsystem = power_supply
uevent->subsystem = "";
//ps_name = rk-ac / rk-battery /rk-usb
uevent->ps_name = "";
//ps_online = 0 / 1
uevent->ps_online = "";
//ps_type = ''
uevent->ps_type = "";
/* currently ignoring SEQNUM */
while (*msg) {
#ifdef DEBUG_UEVENTS
LOGV("uevent str: %s\n", msg);
#endif
if (!strncmp(msg, "ACTION=", 7)) {
msg += 7;
uevent->action = msg;
} else if (!strncmp(msg, "DEVPATH=", 8)) {
msg += 8;
uevent->path = msg;
} else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
msg += 10;
uevent->subsystem = msg;
} else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) {
msg += 18;
uevent->ps_name = msg;
} else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) {
msg += 20;
uevent->ps_online = msg;
} else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) {
msg += 18;
uevent->ps_type = msg;
}
/* advance to after the next \0 */
while (*msg++)
;
}
//LOGV
LOGI("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n",
uevent->action, uevent->path, uevent->subsystem,
uevent->ps_name, uevent->ps_type, uevent->ps_online);
}
//处理uevent信息,更新charger的power_supply状态
static void process_ps_uevent(struct charger *charger, struct uevent *uevent)
{
int online;
char ps_type[32];
struct power_supply *supply = NULL;
int i;
bool was_online = false;
bool battery = false;
bool usb = false;
//如果ps_type为空,则重新从驱动路径中获取ps_type
if (uevent->ps_type[0] == '\0') {
char *path;
int ret;
if (uevent->path[0] == '\0')
return;
/*
/sys/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-ac
/sys/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-bat
/sys/devices/platform/rk30_i2c.0/i2c-0/0-0062/power_supply/rk-usb
*/
//生成路径
ret = asprintf(&path, "/sys/%s/type", uevent->path);
if (ret <= 0)
return;
/*
type = Mains / Battery /USB
*/
//读取type
ret = read_file(path, ps_type, sizeof(ps_type));
free(path);
if (ret < 0)
return;
} else {
strlcpy(ps_type, uevent->ps_type, sizeof(ps_type));
}
//type == Battery
if (!strncmp(ps_type, "Battery", 7)){
battery = true;
}
//读取uevent的online值
online = atoi(uevent->ps_online);
//从charger的list查找name为ps_name的power_supply
supply = find_supply(charger, uevent->ps_name);
if (supply) {//list包含该power_supply
was_online = supply->online;
//更新charger的online状态
supply->online = online;
}
if (!strcmp(uevent->action, "add")) {
//该supply不在list中
if (!supply) {
//新建supply,拷贝uevent的信息到supply,然后添加到charger的list
//同时更新charger的num_supplies++
supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path,
online);
if (!supply) {
LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name,
uevent->ps_type, online);
return;
}
/* only pick up the first battery for now */
if (battery && !charger->battery)
charger->battery = supply;
//该supply已在list中
} else {
LOGE("supply '%s' already exists..\n", uevent->ps_name);
}
} else if (!strcmp(uevent->action, "remove")) {
if (supply) {
if (charger->battery == supply)
charger->battery = NULL;
//从list中移除该supply,并更新charger->num_supplies--
remove_supply(charger, supply);
supply = NULL;
}
//前面已更新了charger的online状态,此处不做任何动作
} else if (!strcmp(uevent->action, "change")) {
if (!supply) {
LOGE("power supply '%s' not found ('%s' %d)\n",
uevent->ps_name, ps_type, online);
return;
}
} else {
return;
}
/* allow battery to be managed in the supply list but make it not
* contribute to online power supplies. */
if (!battery) {
//online : 1 -> 0
if (was_online && !online)
charger->num_supplies_online--;
//online: 0 -> 1
else if (supply && !was_online && online)
charger->num_supplies_online++;
}
if(usb && !online){
charger->num_supplies_online = 0;
}
LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n",
uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline",
uevent->action, charger->num_supplies_online, charger->num_supplies);
}
7)handle_power_supply_state函数
static void handle_power_supply_state(struct charger *charger, int64_t now)
{
//充电源数量为0
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;
}
}