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 <stdbool.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/epoll.h> 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 #include <sys/un.h> 29 #include <time.h> 30 #include <unistd.h> 31 32 #include <functional> 33 34 #include <android-base/file.h> 35 #include <android-base/macros.h> 36 37 #include <linux/netlink.h> 38 #include <sys/socket.h> 39 40 #include <cutils/klog.h> 41 #include <cutils/misc.h> 42 #include <cutils/properties.h> 43 #include <cutils/uevent.h> 44 #include <sys/reboot.h> 45 46 #ifdef CHARGER_ENABLE_SUSPEND 47 #include <suspend/autosuspend.h> 48 #endif 49 50 #include "AnimationParser.h" 51 #include "healthd_draw.h" 52 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 */ 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 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 253 static int request_suspend(bool enable) { 254 if (enable) 255 return autosuspend_enable(); 256 else 257 return autosuspend_disable(); 258 } 259 #else 260 static int request_suspend(bool /*enable*/) { 261 return 0; 262 } 263 #endif 264 265 static void kick_animation(animation* anim) { 266 anim->run = true; 267 } 268 269 static void reset_animation(animation* anim) { 270 anim->cur_cycle = 0; 271 anim->cur_frame = 0; 272 anim->run = false; 273 } 274 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 /* animation starting, set up the animation */ 312 if (batt_anim->cur_frame == 0) { 313 LOGV("[%" PRId64 "] animation starting\n", now); 314 if (batt_prop) { 315 batt_anim->cur_level = batt_prop->batteryLevel; 316 batt_anim->cur_status = batt_prop->batteryStatus; 317 if (batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) { 318 /* find first frame given current battery level */ 319 for (int i = 0; i < batt_anim->num_frames; i++) { 320 if (batt_anim->cur_level >= batt_anim->frames[i].min_level && 321 batt_anim->cur_level <= batt_anim->frames[i].max_level) { 322 batt_anim->cur_frame = i; 323 break; 324 } 325 } 326 327 // repeat the first frame first_frame_repeats times 328 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 329 batt_anim->first_frame_repeats; 330 } 331 } 332 } 333 334 /* unblank the screen on first cycle */ 335 if (batt_anim->cur_cycle == 0) healthd_draw->blank_screen(false); 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 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 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 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 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 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 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 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 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 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 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 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 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 615 void healthd_mode_charger_init(struct healthd_config* config) { 616 int ret; 617 charger* charger = &charger_state; 618 int i; 619 int epollfd; 620 621 dump_last_kmsg(); 622 623 LOGW("--------------- STARTING CHARGER MODE ---------------\n"); 624 625 ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1, std::placeholders::_2)); 626 if (!ret) { 627 epollfd = ev_get_epollfd(); 628 healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD); 629 } 630 631 animation* anim = init_animation(); 632 charger->batt_anim = anim; 633 634 ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown); 635 if (ret < 0) { 636 LOGE("Cannot load custom battery_fail image. Reverting to built in.\n"); 637 ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown); 638 if (ret < 0) { 639 LOGE("Cannot load built in battery_fail image\n"); 640 charger->surf_unknown = NULL; 641 } 642 } 643 644 GRSurface** scale_frames; 645 int scale_count; 646 int scale_fps; // Not in use (charger/battery_scale doesn't have FPS text 647 // chunk). We are using hard-coded frame.disp_time instead. 648 ret = res_create_multi_display_surface(anim->animation_file.c_str(), &scale_count, &scale_fps, 649 &scale_frames); 650 if (ret < 0) { 651 LOGE("Cannot load battery_scale image\n"); 652 anim->num_frames = 0; 653 anim->num_cycles = 1; 654 } else if (scale_count != anim->num_frames) { 655 LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", scale_count, 656 anim->num_frames); 657 anim->num_frames = 0; 658 anim->num_cycles = 1; 659 } else { 660 for (i = 0; i < anim->num_frames; i++) { 661 anim->frames[i].surface = scale_frames[i]; 662 } 663 } 664 ev_sync_key_state( 665 std::bind(&set_key_callback, charger, std::placeholders::_1, std::placeholders::_2)); 666 667 charger->next_screen_transition = -1; 668 charger->next_key_check = -1; 669 charger->next_pwr_check = -1; 670 healthd_config = config; 671 charger->boot_min_cap = config->boot_min_cap; 672 } 673