• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011-2013 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 #include <dirent.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <inttypes.h>
21 #include <linux/input.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/epoll.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30 #include <time.h>
31 #include <unistd.h>
32 
33 #include <functional>
34 
35 #include <android-base/file.h>
36 #include <android-base/stringprintf.h>
37 
38 #include <sys/socket.h>
39 #include <linux/netlink.h>
40 
41 #include <batteryservice/BatteryService.h>
42 #include <cutils/klog.h>
43 #include <cutils/misc.h>
44 #include <cutils/uevent.h>
45 #include <cutils/properties.h>
46 #include <minui/minui.h>
47 #include <sys/reboot.h>
48 
49 #ifdef CHARGER_ENABLE_SUSPEND
50 #include <suspend/autosuspend.h>
51 #endif
52 
53 #include "animation.h"
54 #include "AnimationParser.h"
55 
56 #include <healthd/healthd.h>
57 
58 using namespace android;
59 
60 char *locale;
61 
62 #ifndef max
63 #define max(a,b) ((a) > (b) ? (a) : (b))
64 #endif
65 
66 #ifndef min
67 #define min(a,b) ((a) < (b) ? (a) : (b))
68 #endif
69 
70 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof((x)[0]))
71 
72 #define MSEC_PER_SEC            (1000LL)
73 #define NSEC_PER_MSEC           (1000000LL)
74 
75 #define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
76 #define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
77 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
78 
79 #define LAST_KMSG_PATH          "/proc/last_kmsg"
80 #define LAST_KMSG_PSTORE_PATH   "/sys/fs/pstore/console-ramoops"
81 #define LAST_KMSG_MAX_SZ        (32 * 1024)
82 
83 #define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
84 #define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
85 #define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
86 
87 static constexpr const char* animation_desc_path = "/res/values/charger/animation.txt";
88 
89 struct key_state {
90     bool pending;
91     bool down;
92     int64_t timestamp;
93 };
94 
95 struct charger {
96     bool have_battery_state;
97     bool charger_connected;
98     int64_t next_screen_transition;
99     int64_t next_key_check;
100     int64_t next_pwr_check;
101 
102     struct key_state keys[KEY_MAX + 1];
103 
104     struct animation *batt_anim;
105     GRSurface* surf_unknown;
106     int boot_min_cap;
107 };
108 
109 static const struct animation BASE_ANIMATION = {
110     .text_clock = {
111         .pos_x = 0,
112         .pos_y = 0,
113 
114         .color_r = 255,
115         .color_g = 255,
116         .color_b = 255,
117         .color_a = 255,
118 
119         .font = nullptr,
120     },
121     .text_percent = {
122         .pos_x = 0,
123         .pos_y = 0,
124 
125         .color_r = 255,
126         .color_g = 255,
127         .color_b = 255,
128         .color_a = 255,
129     },
130 
131     .run = false,
132 
133     .frames = nullptr,
134     .cur_frame = 0,
135     .num_frames = 0,
136     .first_frame_repeats = 2,
137 
138     .cur_cycle = 0,
139     .num_cycles = 3,
140 
141     .cur_level = 0,
142     .cur_status = BATTERY_STATUS_UNKNOWN,
143 };
144 
145 
146 static struct animation::frame default_animation_frames[] = {
147     {
148         .disp_time = 750,
149         .min_level = 0,
150         .max_level = 19,
151         .surface = NULL,
152     },
153     {
154         .disp_time = 750,
155         .min_level = 0,
156         .max_level = 39,
157         .surface = NULL,
158     },
159     {
160         .disp_time = 750,
161         .min_level = 0,
162         .max_level = 59,
163         .surface = NULL,
164     },
165     {
166         .disp_time = 750,
167         .min_level = 0,
168         .max_level = 79,
169         .surface = NULL,
170     },
171     {
172         .disp_time = 750,
173         .min_level = 80,
174         .max_level = 95,
175         .surface = NULL,
176     },
177     {
178         .disp_time = 750,
179         .min_level = 0,
180         .max_level = 100,
181         .surface = NULL,
182     },
183 };
184 
185 static struct animation battery_animation = BASE_ANIMATION;
186 
187 static struct charger charger_state;
188 static struct healthd_config *healthd_config;
189 static struct android::BatteryProperties *batt_prop;
190 static int char_width;
191 static int char_height;
192 static bool minui_inited;
193 
194 /* current time in milliseconds */
curr_time_ms(void)195 static int64_t curr_time_ms(void)
196 {
197     struct timespec tm;
198     clock_gettime(CLOCK_MONOTONIC, &tm);
199     return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
200 }
201 
clear_screen(void)202 static void clear_screen(void)
203 {
204     gr_color(0, 0, 0, 255);
205     gr_clear();
206 }
207 
208 #define MAX_KLOG_WRITE_BUF_SZ 256
209 
dump_last_kmsg(void)210 static void dump_last_kmsg(void)
211 {
212     char *buf;
213     char *ptr;
214     unsigned sz = 0;
215     int len;
216 
217     LOGW("\n");
218     LOGW("*************** LAST KMSG ***************\n");
219     LOGW("\n");
220     buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
221 
222     if (!buf || !sz) {
223         buf = (char *)load_file(LAST_KMSG_PATH, &sz);
224         if (!buf || !sz) {
225             LOGW("last_kmsg not found. Cold reset?\n");
226             goto out;
227         }
228     }
229 
230     len = min(sz, LAST_KMSG_MAX_SZ);
231     ptr = buf + (sz - len);
232 
233     while (len > 0) {
234         int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
235         char yoink;
236         char *nl;
237 
238         nl = (char *)memrchr(ptr, '\n', cnt - 1);
239         if (nl)
240             cnt = nl - ptr + 1;
241 
242         yoink = ptr[cnt];
243         ptr[cnt] = '\0';
244         klog_write(6, "<4>%s", ptr);
245         ptr[cnt] = yoink;
246 
247         len -= cnt;
248         ptr += cnt;
249     }
250 
251     free(buf);
252 
253 out:
254     LOGW("\n");
255     LOGW("************* END LAST KMSG *************\n");
256     LOGW("\n");
257 }
258 
259 #ifdef CHARGER_ENABLE_SUSPEND
request_suspend(bool enable)260 static int request_suspend(bool enable)
261 {
262     if (enable)
263         return autosuspend_enable();
264     else
265         return autosuspend_disable();
266 }
267 #else
request_suspend(bool)268 static int request_suspend(bool /*enable*/)
269 {
270     return 0;
271 }
272 #endif
273 
draw_text(const char * str,int x,int y)274 static int draw_text(const char *str, int x, int y)
275 {
276     int str_len_px = gr_measure(gr_sys_font(), str);
277 
278     if (x < 0)
279         x = (gr_fb_width() - str_len_px) / 2;
280     if (y < 0)
281         y = (gr_fb_height() - char_height) / 2;
282     gr_text(gr_sys_font(), x, y, str, 0);
283 
284     return y + char_height;
285 }
286 
android_green(void)287 static void android_green(void)
288 {
289     gr_color(0xa4, 0xc6, 0x39, 255);
290 }
291 
292 // Negative x or y coordinates position the text away from the opposite edge that positive ones do.
determine_xy(const animation::text_field & field,const int length,int * x,int * y)293 void determine_xy(const animation::text_field& field, const int length, int* x, int* y)
294 {
295     *x = field.pos_x;
296     *y = field.pos_y;
297 
298     int str_len_px = length * field.font->char_width;
299     if (field.pos_x == CENTER_VAL) {
300         *x = (gr_fb_width() - str_len_px) / 2;
301     } else if (field.pos_x >= 0) {
302         *x = field.pos_x;
303     } else {  // position from max edge
304         *x = gr_fb_width() + field.pos_x - str_len_px;
305     }
306 
307     if (field.pos_y == CENTER_VAL) {
308         *y = (gr_fb_height() - field.font->char_height) / 2;
309     } else if (field.pos_y >= 0) {
310         *y = field.pos_y;
311     } else {  // position from max edge
312         *y = gr_fb_height() + field.pos_y - field.font->char_height;
313     }
314 }
315 
draw_clock(const animation & anim)316 static void draw_clock(const animation& anim)
317 {
318     static constexpr char CLOCK_FORMAT[] = "%H:%M";
319     static constexpr int CLOCK_LENGTH = 6;
320 
321     const animation::text_field& field = anim.text_clock;
322 
323     if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) return;
324 
325     time_t rawtime;
326     time(&rawtime);
327     struct tm* time_info = localtime(&rawtime);
328 
329     char clock_str[CLOCK_LENGTH];
330     size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
331     if (length != CLOCK_LENGTH - 1) {
332         LOGE("Could not format time\n");
333         return;
334     }
335 
336     int x, y;
337     determine_xy(field, length, &x, &y);
338 
339     LOGV("drawing clock %s %d %d\n", clock_str, x, y);
340     gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
341     gr_text(field.font, x, y, clock_str, false);
342 }
343 
draw_percent(const animation & anim)344 static void draw_percent(const animation& anim)
345 {
346     int cur_level = anim.cur_level;
347     if (anim.cur_status == BATTERY_STATUS_FULL) {
348         cur_level = 100;
349     }
350 
351     if (cur_level <= 0) return;
352 
353     const animation::text_field& field = anim.text_percent;
354     if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
355         return;
356     }
357 
358     std::string str = base::StringPrintf("%d%%", cur_level);
359 
360     int x, y;
361     determine_xy(field, str.size(), &x, &y);
362 
363     LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
364     gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
365     gr_text(field.font, x, y, str.c_str(), false);
366 }
367 
368 /* returns the last y-offset of where the surface ends */
draw_surface_centered(GRSurface * surface)369 static int draw_surface_centered(GRSurface* surface)
370 {
371     int w;
372     int h;
373     int x;
374     int y;
375 
376     w = gr_get_width(surface);
377     h = gr_get_height(surface);
378     x = (gr_fb_width() - w) / 2 ;
379     y = (gr_fb_height() - h) / 2 ;
380 
381     LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
382     gr_blit(surface, 0, 0, w, h, x, y);
383     return y + h;
384 }
385 
draw_unknown(struct charger * charger)386 static void draw_unknown(struct charger *charger)
387 {
388     int y;
389     if (charger->surf_unknown) {
390         draw_surface_centered(charger->surf_unknown);
391     } else {
392         android_green();
393         y = draw_text("Charging!", -1, -1);
394         draw_text("?\?/100", -1, y + 25);
395     }
396 }
397 
draw_battery(const struct charger * charger)398 static void draw_battery(const struct charger* charger)
399 {
400     const struct animation& anim = *charger->batt_anim;
401     const struct animation::frame& frame = anim.frames[anim.cur_frame];
402 
403     if (anim.num_frames != 0) {
404         draw_surface_centered(frame.surface);
405         LOGV("drawing frame #%d min_cap=%d time=%d\n",
406              anim.cur_frame, frame.min_level,
407              frame.disp_time);
408     }
409     draw_clock(anim);
410     draw_percent(anim);
411 }
412 
redraw_screen(struct charger * charger)413 static void redraw_screen(struct charger *charger)
414 {
415     struct animation *batt_anim = charger->batt_anim;
416 
417     clear_screen();
418 
419     /* try to display *something* */
420     if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
421         draw_unknown(charger);
422     else
423         draw_battery(charger);
424     gr_flip();
425 }
426 
kick_animation(struct animation * anim)427 static void kick_animation(struct animation *anim)
428 {
429     anim->run = true;
430 }
431 
reset_animation(struct animation * anim)432 static void reset_animation(struct animation *anim)
433 {
434     anim->cur_cycle = 0;
435     anim->cur_frame = 0;
436     anim->run = false;
437 }
438 
init_status_display(struct animation * anim)439 static void init_status_display(struct animation* anim)
440 {
441     int res;
442 
443     if (!anim->text_clock.font_file.empty()) {
444         if ((res =
445                 gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) {
446             LOGE("Could not load time font (%d)\n", res);
447         }
448     }
449 
450     if (!anim->text_percent.font_file.empty()) {
451         if ((res =
452                 gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) {
453             LOGE("Could not load percent font (%d)\n", res);
454         }
455     }
456 }
457 
update_screen_state(struct charger * charger,int64_t now)458 static void update_screen_state(struct charger *charger, int64_t now)
459 {
460     struct animation *batt_anim = charger->batt_anim;
461     int disp_time;
462 
463     if (!batt_anim->run || now < charger->next_screen_transition) return;
464 
465     if (!minui_inited) {
466         if (healthd_config && healthd_config->screen_on) {
467             if (!healthd_config->screen_on(batt_prop)) {
468                 LOGV("[%" PRId64 "] leave screen off\n", now);
469                 batt_anim->run = false;
470                 charger->next_screen_transition = -1;
471                 if (charger->charger_connected)
472                     request_suspend(true);
473                 return;
474             }
475         }
476 
477         gr_init();
478         gr_font_size(gr_sys_font(), &char_width, &char_height);
479         init_status_display(batt_anim);
480 
481 #ifndef CHARGER_DISABLE_INIT_BLANK
482         gr_fb_blank(true);
483 #endif
484         minui_inited = true;
485     }
486 
487     /* animation is over, blank screen and leave */
488     if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
489         reset_animation(batt_anim);
490         charger->next_screen_transition = -1;
491         gr_fb_blank(true);
492         LOGV("[%" PRId64 "] animation done\n", now);
493         if (charger->charger_connected)
494             request_suspend(true);
495         return;
496     }
497 
498     disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
499 
500     /* animation starting, set up the animation */
501     if (batt_anim->cur_frame == 0) {
502 
503         LOGV("[%" PRId64 "] animation starting\n", now);
504         if (batt_prop) {
505             batt_anim->cur_level = batt_prop->batteryLevel;
506             batt_anim->cur_status = batt_prop->batteryStatus;
507             if (batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
508                 /* find first frame given current battery level */
509                 for (int i = 0; i < batt_anim->num_frames; i++) {
510                     if (batt_anim->cur_level >= batt_anim->frames[i].min_level &&
511                         batt_anim->cur_level <= batt_anim->frames[i].max_level) {
512                         batt_anim->cur_frame = i;
513                         break;
514                     }
515                 }
516 
517                 // repeat the first frame first_frame_repeats times
518                 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
519                     batt_anim->first_frame_repeats;
520             }
521         }
522     }
523 
524     /* unblank the screen  on first cycle */
525     if (batt_anim->cur_cycle == 0)
526         gr_fb_blank(false);
527 
528     /* draw the new frame (@ cur_frame) */
529     redraw_screen(charger);
530 
531     /* if we don't have anim frames, we only have one image, so just bump
532      * the cycle counter and exit
533      */
534     if (batt_anim->num_frames == 0 || batt_anim->cur_level < 0) {
535         LOGW("[%" PRId64 "] animation missing or unknown battery status\n", now);
536         charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
537         batt_anim->cur_cycle++;
538         return;
539     }
540 
541     /* schedule next screen transition */
542     charger->next_screen_transition = now + disp_time;
543 
544     /* advance frame cntr to the next valid frame only if we are charging
545      * if necessary, advance cycle cntr, and reset frame cntr
546      */
547     if (charger->charger_connected) {
548         batt_anim->cur_frame++;
549 
550         while (batt_anim->cur_frame < batt_anim->num_frames &&
551                (batt_anim->cur_level < batt_anim->frames[batt_anim->cur_frame].min_level ||
552                 batt_anim->cur_level > batt_anim->frames[batt_anim->cur_frame].max_level)) {
553             batt_anim->cur_frame++;
554         }
555         if (batt_anim->cur_frame >= batt_anim->num_frames) {
556             batt_anim->cur_cycle++;
557             batt_anim->cur_frame = 0;
558 
559             /* don't reset the cycle counter, since we use that as a signal
560              * in a test above to check if animation is over
561              */
562         }
563     } else {
564         /* Stop animating if we're not charging.
565          * If we stop it immediately instead of going through this loop, then
566          * the animation would stop somewhere in the middle.
567          */
568         batt_anim->cur_frame = 0;
569         batt_anim->cur_cycle++;
570     }
571 }
572 
set_key_callback(struct charger * charger,int code,int value)573 static int set_key_callback(struct charger *charger, int code, int value)
574 {
575     int64_t now = curr_time_ms();
576     int down = !!value;
577 
578     if (code > KEY_MAX)
579         return -1;
580 
581     /* ignore events that don't modify our state */
582     if (charger->keys[code].down == down)
583         return 0;
584 
585     /* only record the down even timestamp, as the amount
586      * of time the key spent not being pressed is not useful */
587     if (down)
588         charger->keys[code].timestamp = now;
589     charger->keys[code].down = down;
590     charger->keys[code].pending = true;
591     if (down) {
592         LOGV("[%" PRId64 "] key[%d] down\n", now, code);
593     } else {
594         int64_t duration = now - charger->keys[code].timestamp;
595         int64_t secs = duration / 1000;
596         int64_t msecs = duration - secs * 1000;
597         LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
598              now, code, secs, msecs);
599     }
600 
601     return 0;
602 }
603 
update_input_state(struct charger * charger,struct input_event * ev)604 static void update_input_state(struct charger *charger,
605                                struct input_event *ev)
606 {
607     if (ev->type != EV_KEY)
608         return;
609     set_key_callback(charger, ev->code, ev->value);
610 }
611 
set_next_key_check(struct charger * charger,struct key_state * key,int64_t timeout)612 static void set_next_key_check(struct charger *charger,
613                                struct key_state *key,
614                                int64_t timeout)
615 {
616     int64_t then = key->timestamp + timeout;
617 
618     if (charger->next_key_check == -1 || then < charger->next_key_check)
619         charger->next_key_check = then;
620 }
621 
process_key(struct charger * charger,int code,int64_t now)622 static void process_key(struct charger *charger, int code, int64_t now)
623 {
624     struct key_state *key = &charger->keys[code];
625 
626     if (code == KEY_POWER) {
627         if (key->down) {
628             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
629             if (now >= reboot_timeout) {
630                 /* We do not currently support booting from charger mode on
631                    all devices. Check the property and continue booting or reboot
632                    accordingly. */
633                 if (property_get_bool("ro.enable_boot_charger_mode", false)) {
634                     LOGW("[%" PRId64 "] booting from charger mode\n", now);
635                     property_set("sys.boot_from_charger_mode", "1");
636                 } else {
637                     if (charger->batt_anim->cur_level >= charger->boot_min_cap) {
638                         LOGW("[%" PRId64 "] rebooting\n", now);
639                         reboot(RB_AUTOBOOT);
640                     } else {
641                         LOGV("[%" PRId64 "] ignore power-button press, battery level "
642                             "less than minimum\n", now);
643                     }
644                 }
645             } else {
646                 /* if the key is pressed but timeout hasn't expired,
647                  * make sure we wake up at the right-ish time to check
648                  */
649                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
650 
651                /* Turn on the display and kick animation on power-key press
652                 * rather than on key release
653                 */
654                 kick_animation(charger->batt_anim);
655                 request_suspend(false);
656             }
657         } else {
658             /* if the power key got released, force screen state cycle */
659             if (key->pending) {
660                 kick_animation(charger->batt_anim);
661             }
662         }
663     }
664 
665     key->pending = false;
666 }
667 
handle_input_state(struct charger * charger,int64_t now)668 static void handle_input_state(struct charger *charger, int64_t now)
669 {
670     process_key(charger, KEY_POWER, now);
671 
672     if (charger->next_key_check != -1 && now > charger->next_key_check)
673         charger->next_key_check = -1;
674 }
675 
handle_power_supply_state(struct charger * charger,int64_t now)676 static void handle_power_supply_state(struct charger *charger, int64_t now)
677 {
678     if (!charger->have_battery_state)
679         return;
680 
681     if (!charger->charger_connected) {
682 
683         /* Last cycle would have stopped at the extreme top of battery-icon
684          * Need to show the correct level corresponding to capacity.
685          */
686         kick_animation(charger->batt_anim);
687         request_suspend(false);
688         if (charger->next_pwr_check == -1) {
689             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
690             LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
691                  now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
692         } else if (now >= charger->next_pwr_check) {
693             LOGW("[%" PRId64 "] shutting down\n", now);
694             reboot(RB_POWER_OFF);
695         } else {
696             /* otherwise we already have a shutdown timer scheduled */
697         }
698     } else {
699         /* online supply present, reset shutdown timer if set */
700         if (charger->next_pwr_check != -1) {
701             LOGW("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
702             kick_animation(charger->batt_anim);
703         }
704         charger->next_pwr_check = -1;
705     }
706 }
707 
healthd_mode_charger_heartbeat()708 void healthd_mode_charger_heartbeat()
709 {
710     struct charger *charger = &charger_state;
711     int64_t now = curr_time_ms();
712 
713     handle_input_state(charger, now);
714     handle_power_supply_state(charger, now);
715 
716     /* do screen update last in case any of the above want to start
717      * screen transitions (animations, etc)
718      */
719     update_screen_state(charger, now);
720 }
721 
healthd_mode_charger_battery_update(struct android::BatteryProperties * props)722 void healthd_mode_charger_battery_update(
723     struct android::BatteryProperties *props)
724 {
725     struct charger *charger = &charger_state;
726 
727     charger->charger_connected =
728         props->chargerAcOnline || props->chargerUsbOnline ||
729         props->chargerWirelessOnline;
730 
731     if (!charger->have_battery_state) {
732         charger->have_battery_state = true;
733         charger->next_screen_transition = curr_time_ms() - 1;
734         reset_animation(charger->batt_anim);
735         kick_animation(charger->batt_anim);
736     }
737     batt_prop = props;
738 }
739 
healthd_mode_charger_preparetowait(void)740 int healthd_mode_charger_preparetowait(void)
741 {
742     struct charger *charger = &charger_state;
743     int64_t now = curr_time_ms();
744     int64_t next_event = INT64_MAX;
745     int64_t timeout;
746 
747     LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
748          charger->next_screen_transition, charger->next_key_check,
749          charger->next_pwr_check);
750 
751     if (charger->next_screen_transition != -1)
752         next_event = charger->next_screen_transition;
753     if (charger->next_key_check != -1 && charger->next_key_check < next_event)
754         next_event = charger->next_key_check;
755     if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
756         next_event = charger->next_pwr_check;
757 
758     if (next_event != -1 && next_event != INT64_MAX)
759         timeout = max(0, next_event - now);
760     else
761         timeout = -1;
762 
763    return (int)timeout;
764 }
765 
input_callback(struct charger * charger,int fd,unsigned int epevents)766 static int input_callback(struct charger *charger, int fd, unsigned int epevents)
767 {
768     struct input_event ev;
769     int ret;
770 
771     ret = ev_get_input(fd, epevents, &ev);
772     if (ret)
773         return -1;
774     update_input_state(charger, &ev);
775     return 0;
776 }
777 
charger_event_handler(uint32_t)778 static void charger_event_handler(uint32_t /*epevents*/)
779 {
780     int ret;
781 
782     ret = ev_wait(-1);
783     if (!ret)
784         ev_dispatch();
785 }
786 
init_animation()787 animation* init_animation()
788 {
789     bool parse_success;
790 
791     std::string content;
792     if (base::ReadFileToString(animation_desc_path, &content)) {
793         parse_success = parse_animation_desc(content, &battery_animation);
794     } else {
795         LOGW("Could not open animation description at %s\n", animation_desc_path);
796         parse_success = false;
797     }
798 
799     if (!parse_success) {
800         LOGW("Could not parse animation description. Using default animation.\n");
801         battery_animation = BASE_ANIMATION;
802         battery_animation.animation_file.assign("charger/battery_scale");
803         battery_animation.frames = default_animation_frames;
804         battery_animation.num_frames = ARRAY_SIZE(default_animation_frames);
805     }
806     if (battery_animation.fail_file.empty()) {
807         battery_animation.fail_file.assign("charger/battery_fail");
808     }
809 
810     LOGV("Animation Description:\n");
811     LOGV("  animation: %d %d '%s' (%d)\n",
812         battery_animation.num_cycles, battery_animation.first_frame_repeats,
813         battery_animation.animation_file.c_str(), battery_animation.num_frames);
814     LOGV("  fail_file: '%s'\n", battery_animation.fail_file.c_str());
815     LOGV("  clock: %d %d %d %d %d %d '%s'\n",
816         battery_animation.text_clock.pos_x, battery_animation.text_clock.pos_y,
817         battery_animation.text_clock.color_r, battery_animation.text_clock.color_g,
818         battery_animation.text_clock.color_b, battery_animation.text_clock.color_a,
819         battery_animation.text_clock.font_file.c_str());
820     LOGV("  percent: %d %d %d %d %d %d '%s'\n",
821         battery_animation.text_percent.pos_x, battery_animation.text_percent.pos_y,
822         battery_animation.text_percent.color_r, battery_animation.text_percent.color_g,
823         battery_animation.text_percent.color_b, battery_animation.text_percent.color_a,
824         battery_animation.text_percent.font_file.c_str());
825     for (int i = 0; i < battery_animation.num_frames; i++) {
826         LOGV("  frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
827             battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
828     }
829 
830     return &battery_animation;
831 }
832 
healthd_mode_charger_init(struct healthd_config * config)833 void healthd_mode_charger_init(struct healthd_config* config)
834 {
835     int ret;
836     struct charger *charger = &charger_state;
837     int i;
838     int epollfd;
839 
840     dump_last_kmsg();
841 
842     LOGW("--------------- STARTING CHARGER MODE ---------------\n");
843 
844     ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1,
845                             std::placeholders::_2));
846     if (!ret) {
847         epollfd = ev_get_epollfd();
848         healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
849     }
850 
851     struct animation* anim = init_animation();
852     charger->batt_anim = anim;
853 
854     ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
855     if (ret < 0) {
856         LOGE("Cannot load custom battery_fail image. Reverting to built in.\n");
857         ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
858         if (ret < 0) {
859             LOGE("Cannot load built in battery_fail image\n");
860             charger->surf_unknown = NULL;
861         }
862     }
863 
864     GRSurface** scale_frames;
865     int scale_count;
866     int scale_fps;  // Not in use (charger/battery_scale doesn't have FPS text
867                     // chunk). We are using hard-coded frame.disp_time instead.
868     ret = res_create_multi_display_surface(anim->animation_file.c_str(),
869         &scale_count, &scale_fps, &scale_frames);
870     if (ret < 0) {
871         LOGE("Cannot load battery_scale image\n");
872         anim->num_frames = 0;
873         anim->num_cycles = 1;
874     } else if (scale_count != anim->num_frames) {
875         LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
876              scale_count, anim->num_frames);
877         anim->num_frames = 0;
878         anim->num_cycles = 1;
879     } else {
880         for (i = 0; i < anim->num_frames; i++) {
881             anim->frames[i].surface = scale_frames[i];
882         }
883     }
884     ev_sync_key_state(std::bind(&set_key_callback, charger, std::placeholders::_1,
885                                 std::placeholders::_2));
886 
887     charger->next_screen_transition = -1;
888     charger->next_key_check = -1;
889     charger->next_pwr_check = -1;
890     healthd_config = config;
891     charger->boot_min_cap = config->boot_min_cap;
892 }
893