• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011-2017 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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/epoll.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/un.h>
28 #include <time.h>
29 #include <unistd.h>
30 
31 #include <functional>
32 
33 #include <android-base/file.h>
34 #include <android-base/macros.h>
35 
36 #include <linux/netlink.h>
37 #include <sys/socket.h>
38 
39 #include <cutils/klog.h>
40 #include <cutils/misc.h>
41 #include <cutils/properties.h>
42 #include <cutils/uevent.h>
43 #include <sys/reboot.h>
44 
45 #ifdef CHARGER_ENABLE_SUSPEND
46 #include <suspend/autosuspend.h>
47 #endif
48 
49 #include "AnimationParser.h"
50 #include "healthd_draw.h"
51 
52 #include <health2/Health.h>
53 #include <healthd/healthd.h>
54 
55 using namespace android;
56 
57 char* locale;
58 
59 #ifndef max
60 #define max(a, b) ((a) > (b) ? (a) : (b))
61 #endif
62 
63 #ifndef min
64 #define min(a, b) ((a) < (b) ? (a) : (b))
65 #endif
66 
67 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
68 
69 #define MSEC_PER_SEC (1000LL)
70 #define NSEC_PER_MSEC (1000000LL)
71 
72 #define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
73 #define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
74 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
75 
76 #define LAST_KMSG_MAX_SZ (32 * 1024)
77 
78 #define LOGE(x...) KLOG_ERROR("charger", x);
79 #define LOGW(x...) KLOG_WARNING("charger", x);
80 #define LOGV(x...) KLOG_DEBUG("charger", x);
81 
82 static constexpr const char* animation_desc_path =
83     "/res/values/charger/animation.txt";
84 
85 struct key_state {
86     bool pending;
87     bool down;
88     int64_t timestamp;
89 };
90 
91 struct charger {
92     bool have_battery_state;
93     bool charger_connected;
94     int64_t next_screen_transition;
95     int64_t next_key_check;
96     int64_t next_pwr_check;
97 
98     key_state keys[KEY_MAX + 1];
99 
100     animation* batt_anim;
101     GRSurface* surf_unknown;
102     int boot_min_cap;
103 };
104 
105 static const animation BASE_ANIMATION = {
106     .text_clock =
107         {
108             .pos_x = 0,
109             .pos_y = 0,
110 
111             .color_r = 255,
112             .color_g = 255,
113             .color_b = 255,
114             .color_a = 255,
115 
116             .font = nullptr,
117         },
118     .text_percent =
119         {
120             .pos_x = 0,
121             .pos_y = 0,
122 
123             .color_r = 255,
124             .color_g = 255,
125             .color_b = 255,
126             .color_a = 255,
127         },
128 
129     .run = false,
130 
131     .frames = nullptr,
132     .cur_frame = 0,
133     .num_frames = 0,
134     .first_frame_repeats = 2,
135 
136     .cur_cycle = 0,
137     .num_cycles = 3,
138 
139     .cur_level = 0,
140     .cur_status = BATTERY_STATUS_UNKNOWN,
141 };
142 
143 static animation::frame default_animation_frames[] = {
144     {
145         .disp_time = 750,
146         .min_level = 0,
147         .max_level = 19,
148         .surface = NULL,
149     },
150     {
151         .disp_time = 750,
152         .min_level = 0,
153         .max_level = 39,
154         .surface = NULL,
155     },
156     {
157         .disp_time = 750,
158         .min_level = 0,
159         .max_level = 59,
160         .surface = NULL,
161     },
162     {
163         .disp_time = 750,
164         .min_level = 0,
165         .max_level = 79,
166         .surface = NULL,
167     },
168     {
169         .disp_time = 750,
170         .min_level = 80,
171         .max_level = 95,
172         .surface = NULL,
173     },
174     {
175         .disp_time = 750,
176         .min_level = 0,
177         .max_level = 100,
178         .surface = NULL,
179     },
180 };
181 
182 static animation battery_animation = BASE_ANIMATION;
183 
184 static charger charger_state;
185 static healthd_config* healthd_config;
186 static android::BatteryProperties* batt_prop;
187 static std::unique_ptr<HealthdDraw> healthd_draw;
188 
189 /* current time in milliseconds */
curr_time_ms()190 static int64_t curr_time_ms() {
191     timespec tm;
192     clock_gettime(CLOCK_MONOTONIC, &tm);
193     return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
194 }
195 
196 #define MAX_KLOG_WRITE_BUF_SZ 256
197 
dump_last_kmsg(void)198 static void dump_last_kmsg(void) {
199     char* buf;
200     char* ptr;
201     unsigned sz = 0;
202     int len;
203 
204     LOGW("\n");
205     LOGW("*************** LAST KMSG ***************\n");
206     LOGW("\n");
207     const char* kmsg[] = {
208         // clang-format off
209         "/sys/fs/pstore/console-ramoops-0",
210         "/sys/fs/pstore/console-ramoops",
211         "/proc/last_kmsg",
212         // clang-format on
213     };
214     for (size_t i = 0; i < arraysize(kmsg); ++i) {
215         buf = (char*)load_file(kmsg[i], &sz);
216         if (buf && sz) break;
217     }
218 
219     if (!buf || !sz) {
220         LOGW("last_kmsg not found. Cold reset?\n");
221         goto out;
222     }
223 
224     len = min(sz, LAST_KMSG_MAX_SZ);
225     ptr = buf + (sz - len);
226 
227     while (len > 0) {
228         int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
229         char yoink;
230         char* nl;
231 
232         nl = (char*)memrchr(ptr, '\n', cnt - 1);
233         if (nl) cnt = nl - ptr + 1;
234 
235         yoink = ptr[cnt];
236         ptr[cnt] = '\0';
237         klog_write(6, "<4>%s", ptr);
238         ptr[cnt] = yoink;
239 
240         len -= cnt;
241         ptr += cnt;
242     }
243 
244     free(buf);
245 
246 out:
247     LOGW("\n");
248     LOGW("************* END LAST KMSG *************\n");
249     LOGW("\n");
250 }
251 
252 #ifdef CHARGER_ENABLE_SUSPEND
request_suspend(bool enable)253 static int request_suspend(bool enable) {
254     if (enable)
255         return autosuspend_enable();
256     else
257         return autosuspend_disable();
258 }
259 #else
request_suspend(bool)260 static int request_suspend(bool /*enable*/) {
261     return 0;
262 }
263 #endif
264 
kick_animation(animation * anim)265 static void kick_animation(animation* anim) {
266     anim->run = true;
267 }
268 
reset_animation(animation * anim)269 static void reset_animation(animation* anim) {
270     anim->cur_cycle = 0;
271     anim->cur_frame = 0;
272     anim->run = false;
273 }
274 
update_screen_state(charger * charger,int64_t now)275 static void update_screen_state(charger* charger, int64_t now) {
276     animation* batt_anim = charger->batt_anim;
277     int disp_time;
278 
279     if (!batt_anim->run || now < charger->next_screen_transition) return;
280 
281     if (healthd_draw == nullptr) {
282         if (healthd_config && healthd_config->screen_on) {
283             if (!healthd_config->screen_on(batt_prop)) {
284                 LOGV("[%" PRId64 "] leave screen off\n", now);
285                 batt_anim->run = false;
286                 charger->next_screen_transition = -1;
287                 if (charger->charger_connected) request_suspend(true);
288                 return;
289             }
290         }
291 
292         healthd_draw.reset(new HealthdDraw(batt_anim));
293 
294 #ifndef CHARGER_DISABLE_INIT_BLANK
295         healthd_draw->blank_screen(true);
296 #endif
297     }
298 
299     /* animation is over, blank screen and leave */
300     if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
301         reset_animation(batt_anim);
302         charger->next_screen_transition = -1;
303         healthd_draw->blank_screen(true);
304         LOGV("[%" PRId64 "] animation done\n", now);
305         if (charger->charger_connected) request_suspend(true);
306         return;
307     }
308 
309     disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
310 
311     /* unblank the screen on first cycle and first frame */
312     if (batt_anim->cur_cycle == 0 && batt_anim->cur_frame == 0) healthd_draw->blank_screen(false);
313 
314     /* animation starting, set up the animation */
315     if (batt_anim->cur_frame == 0) {
316         LOGV("[%" PRId64 "] animation starting\n", now);
317         if (batt_prop) {
318             batt_anim->cur_level = batt_prop->batteryLevel;
319             batt_anim->cur_status = batt_prop->batteryStatus;
320             if (batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
321                 /* find first frame given current battery level */
322                 for (int i = 0; i < batt_anim->num_frames; i++) {
323                     if (batt_anim->cur_level >= batt_anim->frames[i].min_level &&
324                         batt_anim->cur_level <= batt_anim->frames[i].max_level) {
325                         batt_anim->cur_frame = i;
326                         break;
327                     }
328                 }
329 
330                 // repeat the first frame first_frame_repeats times
331                 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
332                             batt_anim->first_frame_repeats;
333             }
334         }
335     }
336 
337     /* draw the new frame (@ cur_frame) */
338     healthd_draw->redraw_screen(charger->batt_anim, charger->surf_unknown);
339 
340     /* if we don't have anim frames, we only have one image, so just bump
341      * the cycle counter and exit
342      */
343     if (batt_anim->num_frames == 0 || batt_anim->cur_level < 0) {
344         LOGW("[%" PRId64 "] animation missing or unknown battery status\n", now);
345         charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
346         batt_anim->cur_cycle++;
347         return;
348     }
349 
350     /* schedule next screen transition */
351     charger->next_screen_transition = now + disp_time;
352 
353     /* advance frame cntr to the next valid frame only if we are charging
354      * if necessary, advance cycle cntr, and reset frame cntr
355      */
356     if (charger->charger_connected) {
357         batt_anim->cur_frame++;
358 
359         while (batt_anim->cur_frame < batt_anim->num_frames &&
360                (batt_anim->cur_level < batt_anim->frames[batt_anim->cur_frame].min_level ||
361                 batt_anim->cur_level > batt_anim->frames[batt_anim->cur_frame].max_level)) {
362             batt_anim->cur_frame++;
363         }
364         if (batt_anim->cur_frame >= batt_anim->num_frames) {
365             batt_anim->cur_cycle++;
366             batt_anim->cur_frame = 0;
367 
368             /* don't reset the cycle counter, since we use that as a signal
369              * in a test above to check if animation is over
370              */
371         }
372     } else {
373         /* Stop animating if we're not charging.
374          * If we stop it immediately instead of going through this loop, then
375          * the animation would stop somewhere in the middle.
376          */
377         batt_anim->cur_frame = 0;
378         batt_anim->cur_cycle++;
379     }
380 }
381 
set_key_callback(charger * charger,int code,int value)382 static int set_key_callback(charger* charger, int code, int value) {
383     int64_t now = curr_time_ms();
384     int down = !!value;
385 
386     if (code > KEY_MAX) return -1;
387 
388     /* ignore events that don't modify our state */
389     if (charger->keys[code].down == down) return 0;
390 
391     /* only record the down even timestamp, as the amount
392      * of time the key spent not being pressed is not useful */
393     if (down) charger->keys[code].timestamp = now;
394     charger->keys[code].down = down;
395     charger->keys[code].pending = true;
396     if (down) {
397         LOGV("[%" PRId64 "] key[%d] down\n", now, code);
398     } else {
399         int64_t duration = now - charger->keys[code].timestamp;
400         int64_t secs = duration / 1000;
401         int64_t msecs = duration - secs * 1000;
402         LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n", now, code,
403              secs, msecs);
404     }
405 
406     return 0;
407 }
408 
update_input_state(charger * charger,input_event * ev)409 static void update_input_state(charger* charger, input_event* ev) {
410     if (ev->type != EV_KEY) return;
411     set_key_callback(charger, ev->code, ev->value);
412 }
413 
set_next_key_check(charger * charger,key_state * key,int64_t timeout)414 static void set_next_key_check(charger* charger, key_state* key, int64_t timeout) {
415     int64_t then = key->timestamp + timeout;
416 
417     if (charger->next_key_check == -1 || then < charger->next_key_check)
418         charger->next_key_check = then;
419 }
420 
process_key(charger * charger,int code,int64_t now)421 static void process_key(charger* charger, int code, int64_t now) {
422     key_state* key = &charger->keys[code];
423 
424     if (code == KEY_POWER) {
425         if (key->down) {
426             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
427             if (now >= reboot_timeout) {
428                 /* We do not currently support booting from charger mode on
429                    all devices. Check the property and continue booting or reboot
430                    accordingly. */
431                 if (property_get_bool("ro.enable_boot_charger_mode", false)) {
432                     LOGW("[%" PRId64 "] booting from charger mode\n", now);
433                     property_set("sys.boot_from_charger_mode", "1");
434                 } else {
435                     if (charger->batt_anim->cur_level >= charger->boot_min_cap) {
436                         LOGW("[%" PRId64 "] rebooting\n", now);
437                         reboot(RB_AUTOBOOT);
438                     } else {
439                         LOGV("[%" PRId64
440                              "] ignore power-button press, battery level "
441                              "less than minimum\n",
442                              now);
443                     }
444                 }
445             } else {
446                 /* if the key is pressed but timeout hasn't expired,
447                  * make sure we wake up at the right-ish time to check
448                  */
449                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
450 
451                 /* Turn on the display and kick animation on power-key press
452                  * rather than on key release
453                  */
454                 kick_animation(charger->batt_anim);
455                 request_suspend(false);
456             }
457         } else {
458             /* if the power key got released, force screen state cycle */
459             if (key->pending) {
460                 kick_animation(charger->batt_anim);
461             }
462         }
463     }
464 
465     key->pending = false;
466 }
467 
handle_input_state(charger * charger,int64_t now)468 static void handle_input_state(charger* charger, int64_t now) {
469     process_key(charger, KEY_POWER, now);
470 
471     if (charger->next_key_check != -1 && now > charger->next_key_check)
472         charger->next_key_check = -1;
473 }
474 
handle_power_supply_state(charger * charger,int64_t now)475 static void handle_power_supply_state(charger* charger, int64_t now) {
476     if (!charger->have_battery_state) return;
477 
478     if (!charger->charger_connected) {
479         /* Last cycle would have stopped at the extreme top of battery-icon
480          * Need to show the correct level corresponding to capacity.
481          */
482         kick_animation(charger->batt_anim);
483         request_suspend(false);
484         if (charger->next_pwr_check == -1) {
485             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
486             LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
487                  now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
488         } else if (now >= charger->next_pwr_check) {
489             LOGW("[%" PRId64 "] shutting down\n", now);
490             reboot(RB_POWER_OFF);
491         } else {
492             /* otherwise we already have a shutdown timer scheduled */
493         }
494     } else {
495         /* online supply present, reset shutdown timer if set */
496         if (charger->next_pwr_check != -1) {
497             LOGW("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
498             kick_animation(charger->batt_anim);
499         }
500         charger->next_pwr_check = -1;
501     }
502 }
503 
healthd_mode_charger_heartbeat()504 void healthd_mode_charger_heartbeat() {
505     charger* charger = &charger_state;
506     int64_t now = curr_time_ms();
507 
508     handle_input_state(charger, now);
509     handle_power_supply_state(charger, now);
510 
511     /* do screen update last in case any of the above want to start
512      * screen transitions (animations, etc)
513      */
514     update_screen_state(charger, now);
515 }
516 
healthd_mode_charger_battery_update(android::BatteryProperties * props)517 void healthd_mode_charger_battery_update(android::BatteryProperties* props) {
518     charger* charger = &charger_state;
519 
520     charger->charger_connected =
521         props->chargerAcOnline || props->chargerUsbOnline || props->chargerWirelessOnline;
522 
523     if (!charger->have_battery_state) {
524         charger->have_battery_state = true;
525         charger->next_screen_transition = curr_time_ms() - 1;
526         reset_animation(charger->batt_anim);
527         kick_animation(charger->batt_anim);
528     }
529     batt_prop = props;
530 }
531 
healthd_mode_charger_preparetowait(void)532 int healthd_mode_charger_preparetowait(void) {
533     charger* charger = &charger_state;
534     int64_t now = curr_time_ms();
535     int64_t next_event = INT64_MAX;
536     int64_t timeout;
537 
538     LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n",
539          now, charger->next_screen_transition, charger->next_key_check, charger->next_pwr_check);
540 
541     if (charger->next_screen_transition != -1) next_event = charger->next_screen_transition;
542     if (charger->next_key_check != -1 && charger->next_key_check < next_event)
543         next_event = charger->next_key_check;
544     if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
545         next_event = charger->next_pwr_check;
546 
547     if (next_event != -1 && next_event != INT64_MAX)
548         timeout = max(0, next_event - now);
549     else
550         timeout = -1;
551 
552     return (int)timeout;
553 }
554 
input_callback(charger * charger,int fd,unsigned int epevents)555 static int input_callback(charger* charger, int fd, unsigned int epevents) {
556     input_event ev;
557     int ret;
558 
559     ret = ev_get_input(fd, epevents, &ev);
560     if (ret) return -1;
561     update_input_state(charger, &ev);
562     return 0;
563 }
564 
charger_event_handler(uint32_t)565 static void charger_event_handler(uint32_t /*epevents*/) {
566     int ret;
567 
568     ret = ev_wait(-1);
569     if (!ret) ev_dispatch();
570 }
571 
init_animation()572 animation* init_animation() {
573     bool parse_success;
574 
575     std::string content;
576     if (base::ReadFileToString(animation_desc_path, &content)) {
577         parse_success = parse_animation_desc(content, &battery_animation);
578     } else {
579         LOGW("Could not open animation description at %s\n", animation_desc_path);
580         parse_success = false;
581     }
582 
583     if (!parse_success) {
584         LOGW("Could not parse animation description. Using default animation.\n");
585         battery_animation = BASE_ANIMATION;
586         battery_animation.animation_file.assign("charger/battery_scale");
587         battery_animation.frames = default_animation_frames;
588         battery_animation.num_frames = ARRAY_SIZE(default_animation_frames);
589     }
590     if (battery_animation.fail_file.empty()) {
591         battery_animation.fail_file.assign("charger/battery_fail");
592     }
593 
594     LOGV("Animation Description:\n");
595     LOGV("  animation: %d %d '%s' (%d)\n", battery_animation.num_cycles,
596          battery_animation.first_frame_repeats, battery_animation.animation_file.c_str(),
597          battery_animation.num_frames);
598     LOGV("  fail_file: '%s'\n", battery_animation.fail_file.c_str());
599     LOGV("  clock: %d %d %d %d %d %d '%s'\n", battery_animation.text_clock.pos_x,
600          battery_animation.text_clock.pos_y, battery_animation.text_clock.color_r,
601          battery_animation.text_clock.color_g, battery_animation.text_clock.color_b,
602          battery_animation.text_clock.color_a, battery_animation.text_clock.font_file.c_str());
603     LOGV("  percent: %d %d %d %d %d %d '%s'\n", battery_animation.text_percent.pos_x,
604          battery_animation.text_percent.pos_y, battery_animation.text_percent.color_r,
605          battery_animation.text_percent.color_g, battery_animation.text_percent.color_b,
606          battery_animation.text_percent.color_a, battery_animation.text_percent.font_file.c_str());
607     for (int i = 0; i < battery_animation.num_frames; i++) {
608         LOGV("  frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
609              battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
610     }
611 
612     return &battery_animation;
613 }
614 
healthd_mode_charger_init(struct healthd_config * config)615 void healthd_mode_charger_init(struct healthd_config* config) {
616     using android::hardware::health::V2_0::implementation::Health;
617 
618     int ret;
619     charger* charger = &charger_state;
620     int i;
621     int epollfd;
622 
623     dump_last_kmsg();
624 
625     LOGW("--------------- STARTING CHARGER MODE ---------------\n");
626 
627     ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1, std::placeholders::_2));
628     if (!ret) {
629         epollfd = ev_get_epollfd();
630         healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
631     }
632 
633     animation* anim = init_animation();
634     charger->batt_anim = anim;
635 
636     ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
637     if (ret < 0) {
638         LOGE("Cannot load custom battery_fail image. Reverting to built in: %d\n", ret);
639         ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
640         if (ret < 0) {
641             LOGE("Cannot load built in battery_fail image\n");
642             charger->surf_unknown = NULL;
643         }
644     }
645 
646     GRSurface** scale_frames;
647     int scale_count;
648     int scale_fps;  // Not in use (charger/battery_scale doesn't have FPS text
649                     // chunk). We are using hard-coded frame.disp_time instead.
650     ret = res_create_multi_display_surface(anim->animation_file.c_str(), &scale_count, &scale_fps,
651                                            &scale_frames);
652     if (ret < 0) {
653         LOGE("Cannot load battery_scale image\n");
654         anim->num_frames = 0;
655         anim->num_cycles = 1;
656     } else if (scale_count != anim->num_frames) {
657         LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", scale_count,
658              anim->num_frames);
659         anim->num_frames = 0;
660         anim->num_cycles = 1;
661     } else {
662         for (i = 0; i < anim->num_frames; i++) {
663             anim->frames[i].surface = scale_frames[i];
664         }
665     }
666     ev_sync_key_state(
667         std::bind(&set_key_callback, charger, std::placeholders::_1, std::placeholders::_2));
668 
669     charger->next_screen_transition = -1;
670     charger->next_key_check = -1;
671     charger->next_pwr_check = -1;
672 
673     // Initialize Health implementation (which initializes the internal BatteryMonitor).
674     Health::initInstance(config);
675 
676     healthd_config = config;
677     charger->boot_min_cap = config->boot_min_cap;
678 }
679