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 */ 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 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 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 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 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 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 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 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 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 360 static int request_suspend(bool enable) 361 { 362 if (enable) 363 return autosuspend_enable(); 364 else 365 return autosuspend_disable(); 366 } 367 #else 368 static int request_suspend(bool enable) 369 { 370 return 0; 371 } 372 #endif 373 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 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 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 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 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 */ 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 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 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, 0); 614 615 return y + char_height; 616 } 617 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 */ 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 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 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 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 680 static void kick_animation(struct animation *anim) 681 { 682 anim->run = true; 683 } 684 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 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 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 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 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 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 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 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 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 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 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 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