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
76struct key_state {
77    bool pending;
78    bool down;
79    int64_t timestamp;
80};
81
82struct 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
91struct frame {
92    const char *name;
93    int disp_time;
94    int min_capacity;
95    bool level_only;
96
97    gr_surface surface;
98};
99
100struct 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
114struct 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
132struct 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
141static 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
175static struct animation battery_animation = {
176    .frames = batt_anim_frames,
177    .num_frames = ARRAY_SIZE(batt_anim_frames),
178    .num_cycles = 3,
179};
180
181static struct charger charger_state = {
182    .batt_anim = &battery_animation,
183};
184
185static int char_width;
186static int char_height;
187
188/* current time in milliseconds */
189static 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
196static 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
204static 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
243out:
244    LOGI("\n");
245    LOGI("************* END LAST KMSG *************\n");
246    LOGI("\n");
247}
248
249static 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
270err:
271    if (fd >= 0)
272        close(fd);
273    return -1;
274}
275
276static 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
295err:
296    return -1;
297}
298
299static 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
315static 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
329static 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
350static 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
360static int request_suspend(bool enable)
361{
362    if (enable)
363        return autosuspend_enable();
364    else
365        return autosuspend_disable();
366}
367#else
368static int request_suspend(bool enable)
369{
370    return 0;
371}
372#endif
373
374static 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
418static 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
500static 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
507static 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
534static 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 */
545static 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
591static 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
605static 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
618static 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 */
624static 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
641static 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
653static 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
666static 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
680static void kick_animation(struct animation *anim)
681{
682    anim->run = true;
683}
684
685static void reset_animation(struct animation *anim)
686{
687    anim->cur_cycle = 0;
688    anim->cur_frame = 0;
689    anim->run = false;
690}
691
692static 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
779static 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
811static 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
819static 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
829static 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
858static 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
866static 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
890static 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
918static 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
931static 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
951int 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