Home | History | Annotate | Download | only in charger
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define DEBUG_UEVENTS
     18 #define CHARGER_KLOG_LEVEL 6
     19 
     20 #include <dirent.h>
     21 #include <errno.h>
     22 #include <fcntl.h>
     23 #include <linux/input.h>
     24 #include <stdbool.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <sys/poll.h>
     29 #include <sys/stat.h>
     30 #include <sys/types.h>
     31 #include <sys/un.h>
     32 #include <time.h>
     33 #include <unistd.h>
     34 
     35 #include <sys/socket.h>
     36 #include <linux/netlink.h>
     37 
     38 #include <cutils/android_reboot.h>
     39 #include <cutils/klog.h>
     40 #include <cutils/list.h>
     41 #include <cutils/misc.h>
     42 #include <cutils/uevent.h>
     43 
     44 #include "minui/minui.h"
     45 
     46 #ifndef max
     47 #define max(a,b) ((a) > (b) ? (a) : (b))
     48 #endif
     49 
     50 #ifndef min
     51 #define min(a,b) ((a) < (b) ? (a) : (b))
     52 #endif
     53 
     54 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
     55 
     56 #define MSEC_PER_SEC            (1000LL)
     57 #define NSEC_PER_MSEC           (1000000LL)
     58 
     59 #define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
     60 #define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
     61 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
     62 
     63 #define BATTERY_FULL_THRESH     95
     64 
     65 #define LAST_KMSG_PATH          "/proc/last_kmsg"
     66 #define LAST_KMSG_MAX_SZ        (32 * 1024)
     67 
     68 #define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
     69 #define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
     70 #define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
     71 
     72 struct key_state {
     73     bool pending;
     74     bool down;
     75     int64_t timestamp;
     76 };
     77 
     78 struct power_supply {
     79     struct listnode list;
     80     char name[256];
     81     char type[32];
     82     bool online;
     83     bool valid;
     84     char cap_path[PATH_MAX];
     85 };
     86 
     87 struct frame {
     88     const char *name;
     89     int disp_time;
     90     int min_capacity;
     91     bool level_only;
     92 
     93     gr_surface surface;
     94 };
     95 
     96 struct animation {
     97     bool run;
     98 
     99     struct frame *frames;
    100     int cur_frame;
    101     int num_frames;
    102 
    103     int cur_cycle;
    104     int num_cycles;
    105 
    106     /* current capacity being animated */
    107     int capacity;
    108 };
    109 
    110 struct charger {
    111     int64_t next_screen_transition;
    112     int64_t next_key_check;
    113     int64_t next_pwr_check;
    114 
    115     struct key_state keys[KEY_MAX + 1];
    116     int uevent_fd;
    117 
    118     struct listnode supplies;
    119     int num_supplies;
    120     int num_supplies_online;
    121 
    122     struct animation *batt_anim;
    123     gr_surface surf_unknown;
    124 
    125     struct power_supply *battery;
    126 };
    127 
    128 struct uevent {
    129     const char *action;
    130     const char *path;
    131     const char *subsystem;
    132     const char *ps_name;
    133     const char *ps_type;
    134     const char *ps_online;
    135 };
    136 
    137 static struct frame batt_anim_frames[] = {
    138     {
    139         .name = "charger/battery_0",
    140         .disp_time = 750,
    141         .min_capacity = 0,
    142     },
    143     {
    144         .name = "charger/battery_1",
    145         .disp_time = 750,
    146         .min_capacity = 20,
    147     },
    148     {
    149         .name = "charger/battery_2",
    150         .disp_time = 750,
    151         .min_capacity = 40,
    152     },
    153     {
    154         .name = "charger/battery_3",
    155         .disp_time = 750,
    156         .min_capacity = 60,
    157     },
    158     {
    159         .name = "charger/battery_4",
    160         .disp_time = 750,
    161         .min_capacity = 80,
    162         .level_only = true,
    163     },
    164     {
    165         .name = "charger/battery_5",
    166         .disp_time = 750,
    167         .min_capacity = BATTERY_FULL_THRESH,
    168     },
    169 };
    170 
    171 static struct animation battery_animation = {
    172     .frames = batt_anim_frames,
    173     .num_frames = ARRAY_SIZE(batt_anim_frames),
    174     .num_cycles = 3,
    175 };
    176 
    177 static struct charger charger_state = {
    178     .batt_anim = &battery_animation,
    179 };
    180 
    181 static int char_width;
    182 static int char_height;
    183 
    184 /* current time in milliseconds */
    185 static int64_t curr_time_ms(void)
    186 {
    187     struct timespec tm;
    188     clock_gettime(CLOCK_MONOTONIC, &tm);
    189     return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
    190 }
    191 
    192 static void clear_screen(void)
    193 {
    194     gr_color(0, 0, 0, 255);
    195     gr_fill(0, 0, gr_fb_width(), gr_fb_height());
    196 };
    197 
    198 #define MAX_KLOG_WRITE_BUF_SZ 256
    199 
    200 static void dump_last_kmsg(void)
    201 {
    202     char *buf;
    203     char *ptr;
    204     unsigned sz = 0;
    205     int len;
    206 
    207     LOGI("\n");
    208     LOGI("*************** LAST KMSG ***************\n");
    209     LOGI("\n");
    210     buf = load_file(LAST_KMSG_PATH, &sz);
    211     if (!buf || !sz) {
    212         LOGI("last_kmsg not found. Cold reset?\n");
    213         goto out;
    214     }
    215 
    216     len = min(sz, LAST_KMSG_MAX_SZ);
    217     ptr = buf + (sz - len);
    218 
    219     while (len > 0) {
    220         int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
    221         char yoink;
    222         char *nl;
    223 
    224         nl = memrchr(ptr, '\n', cnt - 1);
    225         if (nl)
    226             cnt = nl - ptr + 1;
    227 
    228         yoink = ptr[cnt];
    229         ptr[cnt] = '\0';
    230         klog_write(6, "<6>%s", ptr);
    231         ptr[cnt] = yoink;
    232 
    233         len -= cnt;
    234         ptr += cnt;
    235     }
    236 
    237     free(buf);
    238 
    239 out:
    240     LOGI("\n");
    241     LOGI("************* END LAST KMSG *************\n");
    242     LOGI("\n");
    243 }
    244 
    245 static int read_file(const char *path, char *buf, size_t sz)
    246 {
    247     int fd;
    248     size_t cnt;
    249 
    250     fd = open(path, O_RDONLY, 0);
    251     if (fd < 0)
    252         goto err;
    253 
    254     cnt = read(fd, buf, sz - 1);
    255     if (cnt <= 0)
    256         goto err;
    257     buf[cnt] = '\0';
    258     if (buf[cnt - 1] == '\n') {
    259         cnt--;
    260         buf[cnt] = '\0';
    261     }
    262 
    263     close(fd);
    264     return cnt;
    265 
    266 err:
    267     if (fd >= 0)
    268         close(fd);
    269     return -1;
    270 }
    271 
    272 static int read_file_int(const char *path, int *val)
    273 {
    274     char buf[32];
    275     int ret;
    276     int tmp;
    277     char *end;
    278 
    279     ret = read_file(path, buf, sizeof(buf));
    280     if (ret < 0)
    281         return -1;
    282 
    283     tmp = strtol(buf, &end, 0);
    284     if (end == buf ||
    285         ((end < buf+sizeof(buf)) && (*end != '\n' && *end != '\0')))
    286         goto err;
    287 
    288     *val = tmp;
    289     return 0;
    290 
    291 err:
    292     return -1;
    293 }
    294 
    295 static int get_battery_capacity(struct charger *charger)
    296 {
    297     int ret;
    298     int batt_cap = -1;
    299 
    300     if (!charger->battery)
    301         return -1;
    302 
    303     ret = read_file_int(charger->battery->cap_path, &batt_cap);
    304     if (ret < 0 || batt_cap > 100) {
    305         batt_cap = -1;
    306     }
    307 
    308     return batt_cap;
    309 }
    310 
    311 static struct power_supply *find_supply(struct charger *charger,
    312                                         const char *name)
    313 {
    314     struct listnode *node;
    315     struct power_supply *supply;
    316 
    317     list_for_each(node, &charger->supplies) {
    318         supply = node_to_item(node, struct power_supply, list);
    319         if (!strncmp(name, supply->name, sizeof(supply->name)))
    320             return supply;
    321     }
    322     return NULL;
    323 }
    324 
    325 static struct power_supply *add_supply(struct charger *charger,
    326                                        const char *name, const char *type,
    327                                        const char *path, bool online)
    328 {
    329     struct power_supply *supply;
    330 
    331     supply = calloc(1, sizeof(struct power_supply));
    332     if (!supply)
    333         return NULL;
    334 
    335     strlcpy(supply->name, name, sizeof(supply->name));
    336     strlcpy(supply->type, type, sizeof(supply->type));
    337     snprintf(supply->cap_path, sizeof(supply->cap_path),
    338              "/sys/%s/capacity", path);
    339     supply->online = online;
    340     list_add_tail(&charger->supplies, &supply->list);
    341     charger->num_supplies++;
    342     LOGV("... added %s %s %d\n", supply->name, supply->type, online);
    343     return supply;
    344 }
    345 
    346 static void remove_supply(struct charger *charger, struct power_supply *supply)
    347 {
    348     if (!supply)
    349         return;
    350     list_remove(&supply->list);
    351     charger->num_supplies--;
    352     free(supply);
    353 }
    354 
    355 static void parse_uevent(const char *msg, struct uevent *uevent)
    356 {
    357     uevent->action = "";
    358     uevent->path = "";
    359     uevent->subsystem = "";
    360     uevent->ps_name = "";
    361     uevent->ps_online = "";
    362     uevent->ps_type = "";
    363 
    364     /* currently ignoring SEQNUM */
    365     while (*msg) {
    366 #ifdef DEBUG_UEVENTS
    367         LOGV("uevent str: %s\n", msg);
    368 #endif
    369         if (!strncmp(msg, "ACTION=", 7)) {
    370             msg += 7;
    371             uevent->action = msg;
    372         } else if (!strncmp(msg, "DEVPATH=", 8)) {
    373             msg += 8;
    374             uevent->path = msg;
    375         } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
    376             msg += 10;
    377             uevent->subsystem = msg;
    378         } else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) {
    379             msg += 18;
    380             uevent->ps_name = msg;
    381         } else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) {
    382             msg += 20;
    383             uevent->ps_online = msg;
    384         } else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) {
    385             msg += 18;
    386             uevent->ps_type = msg;
    387         }
    388 
    389         /* advance to after the next \0 */
    390         while (*msg++)
    391             ;
    392     }
    393 
    394     LOGV("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n",
    395          uevent->action, uevent->path, uevent->subsystem,
    396          uevent->ps_name, uevent->ps_type, uevent->ps_online);
    397 }
    398 
    399 static void process_ps_uevent(struct charger *charger, struct uevent *uevent)
    400 {
    401     int online;
    402     char ps_type[32];
    403     struct power_supply *supply = NULL;
    404     int i;
    405     bool was_online = false;
    406     bool battery = false;
    407 
    408     if (uevent->ps_type[0] == '\0') {
    409         char *path;
    410         int ret;
    411 
    412         if (uevent->path[0] == '\0')
    413             return;
    414         ret = asprintf(&path, "/sys/%s/type", uevent->path);
    415         if (ret <= 0)
    416             return;
    417         ret = read_file(path, ps_type, sizeof(ps_type));
    418         free(path);
    419         if (ret < 0)
    420             return;
    421     } else {
    422         strlcpy(ps_type, uevent->ps_type, sizeof(ps_type));
    423     }
    424 
    425     if (!strncmp(ps_type, "Battery", 7))
    426         battery = true;
    427 
    428     online = atoi(uevent->ps_online);
    429     supply = find_supply(charger, uevent->ps_name);
    430     if (supply) {
    431         was_online = supply->online;
    432         supply->online = online;
    433     }
    434 
    435     if (!strcmp(uevent->action, "add")) {
    436         if (!supply) {
    437             supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path,
    438                                 online);
    439             if (!supply) {
    440                 LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name,
    441                      uevent->ps_type, online);
    442                 return;
    443             }
    444             /* only pick up the first battery for now */
    445             if (battery && !charger->battery)
    446                 charger->battery = supply;
    447         } else {
    448             LOGE("supply '%s' already exists..\n", uevent->ps_name);
    449         }
    450     } else if (!strcmp(uevent->action, "remove")) {
    451         if (supply) {
    452             if (charger->battery == supply)
    453                 charger->battery = NULL;
    454             remove_supply(charger, supply);
    455             supply = NULL;
    456         }
    457     } else if (!strcmp(uevent->action, "change")) {
    458         if (!supply) {
    459             LOGE("power supply '%s' not found ('%s' %d)\n",
    460                  uevent->ps_name, ps_type, online);
    461             return;
    462         }
    463     } else {
    464         return;
    465     }
    466 
    467     /* allow battery to be managed in the supply list but make it not
    468      * contribute to online power supplies. */
    469     if (!battery) {
    470         if (was_online && !online)
    471             charger->num_supplies_online--;
    472         else if (supply && !was_online && online)
    473             charger->num_supplies_online++;
    474     }
    475 
    476     LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n",
    477          uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline",
    478          uevent->action, charger->num_supplies_online, charger->num_supplies);
    479 }
    480 
    481 static void process_uevent(struct charger *charger, struct uevent *uevent)
    482 {
    483     if (!strcmp(uevent->subsystem, "power_supply"))
    484         process_ps_uevent(charger, uevent);
    485 }
    486 
    487 #define UEVENT_MSG_LEN  1024
    488 static int handle_uevent_fd(struct charger *charger, int fd)
    489 {
    490     char msg[UEVENT_MSG_LEN+2];
    491     int n;
    492 
    493     if (fd < 0)
    494         return -1;
    495 
    496     while (true) {
    497         struct uevent uevent;
    498 
    499         n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN);
    500         if (n <= 0)
    501             break;
    502         if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
    503             continue;
    504 
    505         msg[n] = '\0';
    506         msg[n+1] = '\0';
    507 
    508         parse_uevent(msg, &uevent);
    509         process_uevent(charger, &uevent);
    510     }
    511 
    512     return 0;
    513 }
    514 
    515 static int uevent_callback(int fd, short revents, void *data)
    516 {
    517     struct charger *charger = data;
    518 
    519     if (!(revents & POLLIN))
    520         return -1;
    521     return handle_uevent_fd(charger, fd);
    522 }
    523 
    524 /* force the kernel to regenerate the change events for the existing
    525  * devices, if valid */
    526 static void do_coldboot(struct charger *charger, DIR *d, const char *event,
    527                         bool follow_links, int max_depth)
    528 {
    529     struct dirent *de;
    530     int dfd, fd;
    531 
    532     dfd = dirfd(d);
    533 
    534     fd = openat(dfd, "uevent", O_WRONLY);
    535     if (fd >= 0) {
    536         write(fd, event, strlen(event));
    537         close(fd);
    538         handle_uevent_fd(charger, charger->uevent_fd);
    539     }
    540 
    541     while ((de = readdir(d)) && max_depth > 0) {
    542         DIR *d2;
    543 
    544         LOGV("looking at '%s'\n", de->d_name);
    545 
    546         if ((de->d_type != DT_DIR && !(de->d_type == DT_LNK && follow_links)) ||
    547            de->d_name[0] == '.') {
    548             LOGV("skipping '%s' type %d (depth=%d follow=%d)\n",
    549                  de->d_name, de->d_type, max_depth, follow_links);
    550             continue;
    551         }
    552         LOGV("can descend into '%s'\n", de->d_name);
    553 
    554         fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
    555         if (fd < 0) {
    556             LOGE("cannot openat %d '%s' (%d: %s)\n", dfd, de->d_name,
    557                  errno, strerror(errno));
    558             continue;
    559         }
    560 
    561         d2 = fdopendir(fd);
    562         if (d2 == 0)
    563             close(fd);
    564         else {
    565             LOGV("opened '%s'\n", de->d_name);
    566             do_coldboot(charger, d2, event, follow_links, max_depth - 1);
    567             closedir(d2);
    568         }
    569     }
    570 }
    571 
    572 static void coldboot(struct charger *charger, const char *path,
    573                      const char *event)
    574 {
    575     char str[256];
    576 
    577     LOGV("doing coldboot '%s' in '%s'\n", event, path);
    578     DIR *d = opendir(path);
    579     if (d) {
    580         snprintf(str, sizeof(str), "%s\n", event);
    581         do_coldboot(charger, d, str, true, 1);
    582         closedir(d);
    583     }
    584 }
    585 
    586 static int draw_text(const char *str, int x, int y)
    587 {
    588     int str_len_px = gr_measure(str);
    589 
    590     if (x < 0)
    591         x = (gr_fb_width() - str_len_px) / 2;
    592     if (y < 0)
    593         y = (gr_fb_height() - char_height) / 2;
    594     gr_text(x, y, str);
    595 
    596     return y + char_height;
    597 }
    598 
    599 static void android_green(void)
    600 {
    601     gr_color(0xa4, 0xc6, 0x39, 255);
    602 }
    603 
    604 /* returns the last y-offset of where the surface ends */
    605 static int draw_surface_centered(struct charger *charger, gr_surface surface)
    606 {
    607     int w;
    608     int h;
    609     int x;
    610     int y;
    611 
    612     w = gr_get_width(surface);
    613     h = gr_get_height(surface);
    614     x = (gr_fb_width() - w) / 2 ;
    615     y = (gr_fb_height() - h) / 2 ;
    616 
    617     LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
    618     gr_blit(surface, 0, 0, w, h, x, y);
    619     return y + h;
    620 }
    621 
    622 static void draw_unknown(struct charger *charger)
    623 {
    624     int y;
    625     if (charger->surf_unknown) {
    626         draw_surface_centered(charger, charger->surf_unknown);
    627     } else {
    628         android_green();
    629         y = draw_text("Charging!", -1, -1);
    630         draw_text("?\?/100", -1, y + 25);
    631     }
    632 }
    633 
    634 static void draw_battery(struct charger *charger)
    635 {
    636     struct animation *batt_anim = charger->batt_anim;
    637     struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
    638 
    639     if (batt_anim->num_frames != 0) {
    640         draw_surface_centered(charger, frame->surface);
    641         LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n",
    642              batt_anim->cur_frame, frame->name, frame->min_capacity,
    643              frame->disp_time);
    644     }
    645 }
    646 
    647 static void redraw_screen(struct charger *charger)
    648 {
    649     struct animation *batt_anim = charger->batt_anim;
    650 
    651     clear_screen();
    652 
    653     /* try to display *something* */
    654     if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
    655         draw_unknown(charger);
    656     else
    657         draw_battery(charger);
    658     gr_flip();
    659 }
    660 
    661 static void kick_animation(struct animation *anim)
    662 {
    663     anim->run = true;
    664 }
    665 
    666 static void reset_animation(struct animation *anim)
    667 {
    668     anim->cur_cycle = 0;
    669     anim->cur_frame = 0;
    670     anim->run = false;
    671 }
    672 
    673 static void update_screen_state(struct charger *charger, int64_t now)
    674 {
    675     struct animation *batt_anim = charger->batt_anim;
    676     int cur_frame;
    677     int disp_time;
    678 
    679     if (!batt_anim->run || now < charger->next_screen_transition)
    680         return;
    681 
    682     /* animation is over, blank screen and leave */
    683     if (batt_anim->cur_cycle == batt_anim->num_cycles) {
    684         reset_animation(batt_anim);
    685         charger->next_screen_transition = -1;
    686         gr_fb_blank(true);
    687         LOGV("[%lld] animation done\n", now);
    688         return;
    689     }
    690 
    691     disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
    692 
    693     /* animation starting, set up the animation */
    694     if (batt_anim->cur_frame == 0) {
    695         int batt_cap;
    696         int ret;
    697 
    698         LOGV("[%lld] animation starting\n", now);
    699         batt_cap = get_battery_capacity(charger);
    700         if (batt_cap >= 0 && batt_anim->num_frames != 0) {
    701             int i;
    702 
    703             /* find first frame given current capacity */
    704             for (i = 1; i < batt_anim->num_frames; i++) {
    705                 if (batt_cap < batt_anim->frames[i].min_capacity)
    706                     break;
    707             }
    708             batt_anim->cur_frame = i - 1;
    709 
    710             /* show the first frame for twice as long */
    711             disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
    712         }
    713 
    714         batt_anim->capacity = batt_cap;
    715     }
    716 
    717     /* unblank the screen  on first cycle */
    718     if (batt_anim->cur_cycle == 0)
    719         gr_fb_blank(false);
    720 
    721     /* draw the new frame (@ cur_frame) */
    722     redraw_screen(charger);
    723 
    724     /* if we don't have anim frames, we only have one image, so just bump
    725      * the cycle counter and exit
    726      */
    727     if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
    728         LOGV("[%lld] animation missing or unknown battery status\n", now);
    729         charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
    730         batt_anim->cur_cycle++;
    731         return;
    732     }
    733 
    734     /* schedule next screen transition */
    735     charger->next_screen_transition = now + disp_time;
    736 
    737     /* advance frame cntr to the next valid frame
    738      * if necessary, advance cycle cntr, and reset frame cntr
    739      */
    740     batt_anim->cur_frame++;
    741 
    742     /* if the frame is used for level-only, that is only show it when it's
    743      * the current level, skip it during the animation.
    744      */
    745     while (batt_anim->cur_frame < batt_anim->num_frames &&
    746            batt_anim->frames[batt_anim->cur_frame].level_only)
    747         batt_anim->cur_frame++;
    748     if (batt_anim->cur_frame >= batt_anim->num_frames) {
    749         batt_anim->cur_cycle++;
    750         batt_anim->cur_frame = 0;
    751 
    752         /* don't reset the cycle counter, since we use that as a signal
    753          * in a test above to check if animation is over
    754          */
    755     }
    756 }
    757 
    758 static int set_key_callback(int code, int value, void *data)
    759 {
    760     struct charger *charger = data;
    761     int64_t now = curr_time_ms();
    762     int down = !!value;
    763 
    764     if (code > KEY_MAX)
    765         return -1;
    766 
    767     /* ignore events that don't modify our state */
    768     if (charger->keys[code].down == down)
    769         return 0;
    770 
    771     /* only record the down even timestamp, as the amount
    772      * of time the key spent not being pressed is not useful */
    773     if (down)
    774         charger->keys[code].timestamp = now;
    775     charger->keys[code].down = down;
    776     charger->keys[code].pending = true;
    777     if (down) {
    778         LOGV("[%lld] key[%d] down\n", now, code);
    779     } else {
    780         int64_t duration = now - charger->keys[code].timestamp;
    781         int64_t secs = duration / 1000;
    782         int64_t msecs = duration - secs * 1000;
    783         LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
    784             code, secs, msecs);
    785     }
    786 
    787     return 0;
    788 }
    789 
    790 static void update_input_state(struct charger *charger,
    791                                struct input_event *ev)
    792 {
    793     if (ev->type != EV_KEY)
    794         return;
    795     set_key_callback(ev->code, ev->value, charger);
    796 }
    797 
    798 static void set_next_key_check(struct charger *charger,
    799                                struct key_state *key,
    800                                int64_t timeout)
    801 {
    802     int64_t then = key->timestamp + timeout;
    803 
    804     if (charger->next_key_check == -1 || then < charger->next_key_check)
    805         charger->next_key_check = then;
    806 }
    807 
    808 static void process_key(struct charger *charger, int code, int64_t now)
    809 {
    810     struct key_state *key = &charger->keys[code];
    811     int64_t next_key_check;
    812 
    813     if (code == KEY_POWER) {
    814         if (key->down) {
    815             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
    816             if (now >= reboot_timeout) {
    817                 LOGI("[%lld] rebooting\n", now);
    818                 android_reboot(ANDROID_RB_RESTART, 0, 0);
    819             } else {
    820                 /* if the key is pressed but timeout hasn't expired,
    821                  * make sure we wake up at the right-ish time to check
    822                  */
    823                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
    824             }
    825         } else {
    826             /* if the power key got released, force screen state cycle */
    827             if (key->pending)
    828                 kick_animation(charger->batt_anim);
    829         }
    830     }
    831 
    832     key->pending = false;
    833 }
    834 
    835 static void handle_input_state(struct charger *charger, int64_t now)
    836 {
    837     process_key(charger, KEY_POWER, now);
    838 
    839     if (charger->next_key_check != -1 && now > charger->next_key_check)
    840         charger->next_key_check = -1;
    841 }
    842 
    843 static void handle_power_supply_state(struct charger *charger, int64_t now)
    844 {
    845     if (charger->num_supplies_online == 0) {
    846         if (charger->next_pwr_check == -1) {
    847             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
    848             LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
    849                  now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
    850         } else if (now >= charger->next_pwr_check) {
    851             LOGI("[%lld] shutting down\n", now);
    852             android_reboot(ANDROID_RB_POWEROFF, 0, 0);
    853         } else {
    854             /* otherwise we already have a shutdown timer scheduled */
    855         }
    856     } else {
    857         /* online supply present, reset shutdown timer if set */
    858         if (charger->next_pwr_check != -1) {
    859             LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
    860             kick_animation(charger->batt_anim);
    861         }
    862         charger->next_pwr_check = -1;
    863     }
    864 }
    865 
    866 static void wait_next_event(struct charger *charger, int64_t now)
    867 {
    868     int64_t next_event = INT64_MAX;
    869     int64_t timeout;
    870     struct input_event ev;
    871     int ret;
    872 
    873     LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now,
    874          charger->next_screen_transition, charger->next_key_check,
    875          charger->next_pwr_check);
    876 
    877     if (charger->next_screen_transition != -1)
    878         next_event = charger->next_screen_transition;
    879     if (charger->next_key_check != -1 && charger->next_key_check < next_event)
    880         next_event = charger->next_key_check;
    881     if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
    882         next_event = charger->next_pwr_check;
    883 
    884     if (next_event != -1 && next_event != INT64_MAX)
    885         timeout = max(0, next_event - now);
    886     else
    887         timeout = -1;
    888     LOGV("[%lld] blocking (%lld)\n", now, timeout);
    889     ret = ev_wait((int)timeout);
    890     if (!ret)
    891         ev_dispatch();
    892 }
    893 
    894 static int input_callback(int fd, short revents, void *data)
    895 {
    896     struct charger *charger = data;
    897     struct input_event ev;
    898     int ret;
    899 
    900     ret = ev_get_input(fd, revents, &ev);
    901     if (ret)
    902         return -1;
    903     update_input_state(charger, &ev);
    904     return 0;
    905 }
    906 
    907 static void event_loop(struct charger *charger)
    908 {
    909     int ret;
    910 
    911     while (true) {
    912         int64_t now = curr_time_ms();
    913 
    914         LOGV("[%lld] event_loop()\n", now);
    915         handle_input_state(charger, now);
    916         handle_power_supply_state(charger, now);
    917 
    918         /* do screen update last in case any of the above want to start
    919          * screen transitions (animations, etc)
    920          */
    921         update_screen_state(charger, now);
    922 
    923         wait_next_event(charger, now);
    924     }
    925 }
    926 
    927 int main(int argc, char **argv)
    928 {
    929     int ret;
    930     struct charger *charger = &charger_state;
    931     int64_t now = curr_time_ms() - 1;
    932     int fd;
    933     int i;
    934 
    935     list_init(&charger->supplies);
    936 
    937     klog_init();
    938     klog_set_level(CHARGER_KLOG_LEVEL);
    939 
    940     dump_last_kmsg();
    941 
    942     LOGI("--------------- STARTING CHARGER MODE ---------------\n");
    943 
    944     gr_init();
    945     gr_font_size(&char_width, &char_height);
    946 
    947     ev_init(input_callback, charger);
    948 
    949     fd = uevent_open_socket(64*1024, true);
    950     if (fd >= 0) {
    951         fcntl(fd, F_SETFL, O_NONBLOCK);
    952         ev_add_fd(fd, uevent_callback, charger);
    953     }
    954     charger->uevent_fd = fd;
    955     coldboot(charger, "/sys/class/power_supply", "add");
    956 
    957     ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
    958     if (ret < 0) {
    959         LOGE("Cannot load image\n");
    960         charger->surf_unknown = NULL;
    961     }
    962 
    963     for (i = 0; i < charger->batt_anim->num_frames; i++) {
    964         struct frame *frame = &charger->batt_anim->frames[i];
    965 
    966         ret = res_create_surface(frame->name, &frame->surface);
    967         if (ret < 0) {
    968             LOGE("Cannot load image %s\n", frame->name);
    969             /* TODO: free the already allocated surfaces... */
    970             charger->batt_anim->num_frames = 0;
    971             charger->batt_anim->num_cycles = 1;
    972             break;
    973         }
    974     }
    975 
    976     ev_sync_key_state(set_key_callback, charger);
    977 
    978 #ifndef CHARGER_DISABLE_INIT_BLANK
    979     gr_fb_blank(true);
    980 #endif
    981 
    982     charger->next_screen_transition = now - 1;
    983     charger->next_key_check = -1;
    984     charger->next_pwr_check = -1;
    985     reset_animation(charger->batt_anim);
    986     kick_animation(charger->batt_anim);
    987 
    988     event_loop(charger);
    989 
    990     return 0;
    991 }
    992