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