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