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