• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
curr_time_ms(void)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 
clear_screen(void)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 
dump_last_kmsg(void)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 
read_file(const char * path,char * buf,size_t sz)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 
read_file_int(const char * path,int * val)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 
get_battery_capacity(struct charger * charger)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 
find_supply(struct charger * charger,const char * name)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 
add_supply(struct charger * charger,const char * name,const char * type,const char * path,bool online)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 
remove_supply(struct charger * charger,struct power_supply * supply)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
request_suspend(bool enable)360 static int request_suspend(bool enable)
361 {
362     if (enable)
363         return autosuspend_enable();
364     else
365         return autosuspend_disable();
366 }
367 #else
request_suspend(bool enable)368 static int request_suspend(bool enable)
369 {
370     return 0;
371 }
372 #endif
373 
parse_uevent(const char * msg,struct uevent * uevent)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 
process_ps_uevent(struct charger * charger,struct uevent * uevent)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 
process_uevent(struct charger * charger,struct uevent * uevent)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
handle_uevent_fd(struct charger * charger,int fd)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 
uevent_callback(int fd,short revents,void * data)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 */
do_coldboot(struct charger * charger,DIR * d,const char * event,bool follow_links,int max_depth)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 
coldboot(struct charger * charger,const char * path,const char * event)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 
draw_text(const char * str,int x,int y)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);
614 
615     return y + char_height;
616 }
617 
android_green(void)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 */
draw_surface_centered(struct charger * charger,gr_surface surface)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 
draw_unknown(struct charger * charger)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 
draw_battery(struct charger * charger)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 
redraw_screen(struct charger * charger)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 
kick_animation(struct animation * anim)680 static void kick_animation(struct animation *anim)
681 {
682     anim->run = true;
683 }
684 
reset_animation(struct animation * anim)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 
update_screen_state(struct charger * charger,int64_t now)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 
set_key_callback(int code,int value,void * data)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 
update_input_state(struct charger * charger,struct input_event * ev)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 
set_next_key_check(struct charger * charger,struct key_state * key,int64_t timeout)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 
process_key(struct charger * charger,int code,int64_t now)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 
handle_input_state(struct charger * charger,int64_t now)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 
handle_power_supply_state(struct charger * charger,int64_t now)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 
wait_next_event(struct charger * charger,int64_t now)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 
input_callback(int fd,short revents,void * data)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 
event_loop(struct charger * charger)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 
main(int argc,char ** argv)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