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 <linux/netlink.h> 25 #include <stdbool.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <sys/poll.h> 30 #include <sys/socket.h> 31 #include <sys/stat.h> 32 #include <sys/types.h> 33 #include <sys/un.h> 34 #include <time.h> 35 #include <unistd.h> 36 37 #include <cutils/android_reboot.h> 38 #include <cutils/klog.h> 39 #include <cutils/list.h> 40 #include <cutils/misc.h> 41 #include <cutils/uevent.h> 42 43 #include "minui/minui.h" 44 45 #ifndef max 46 #define max(a,b) ((a) > (b) ? (a) : (b)) 47 #endif 48 49 #ifndef min 50 #define min(a,b) ((a) < (b) ? (a) : (b)) 51 #endif 52 53 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 54 55 #define MSEC_PER_SEC (1000LL) 56 #define NSEC_PER_MSEC (1000000LL) 57 58 #define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC) 59 #define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC) 60 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC) 61 62 #define BATTERY_FULL_THRESH 95 63 64 #define LAST_KMSG_PATH "/proc/last_kmsg" 65 #define LAST_KMSG_MAX_SZ (32 * 1024) 66 67 #define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0) 68 #define LOGI(x...) do { KLOG_INFO("charger", x); } while (0) 69 #define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0) 70 71 struct key_state { 72 bool pending; 73 bool down; 74 int64_t timestamp; 75 }; 76 77 struct power_supply { 78 struct listnode list; 79 char name[256]; 80 char type[32]; 81 bool online; 82 bool valid; 83 char cap_path[PATH_MAX]; 84 }; 85 86 struct frame { 87 const char *name; 88 int disp_time; 89 int min_capacity; 90 91 gr_surface surface; 92 }; 93 94 struct animation { 95 bool run; 96 97 struct frame *frames; 98 int cur_frame; 99 int num_frames; 100 101 int cur_cycle; 102 int num_cycles; 103 104 /* current capacity being animated */ 105 int capacity; 106 }; 107 108 struct charger { 109 int64_t next_screen_transition; 110 int64_t next_key_check; 111 int64_t next_pwr_check; 112 113 struct key_state keys[KEY_MAX + 1]; 114 int uevent_fd; 115 116 struct listnode supplies; 117 int num_supplies; 118 int num_supplies_online; 119 120 struct animation *batt_anim; 121 gr_surface surf_unknown; 122 123 struct power_supply *battery; 124 }; 125 126 struct uevent { 127 const char *action; 128 const char *path; 129 const char *subsystem; 130 const char *ps_name; 131 const char *ps_type; 132 const char *ps_online; 133 }; 134 135 static struct frame batt_anim_frames[] = { 136 { 137 .name = "charger/battery_0", 138 .disp_time = 750, 139 .min_capacity = 0, 140 }, 141 { 142 .name = "charger/battery_1", 143 .disp_time = 750, 144 .min_capacity = 20, 145 }, 146 { 147 .name = "charger/battery_2", 148 .disp_time = 750, 149 .min_capacity = 40, 150 }, 151 { 152 .name = "charger/battery_3", 153 .disp_time = 750, 154 .min_capacity = 60, 155 }, 156 { 157 .name = "charger/battery_4", 158 .disp_time = 750, 159 .min_capacity = 80, 160 }, 161 { 162 .name = "charger/battery_5", 163 .disp_time = 750, 164 .min_capacity = BATTERY_FULL_THRESH, 165 }, 166 }; 167 168 static struct animation battery_animation = { 169 .frames = batt_anim_frames, 170 .num_frames = ARRAY_SIZE(batt_anim_frames), 171 .num_cycles = 3, 172 }; 173 174 static struct charger charger_state = { 175 .batt_anim = &battery_animation, 176 }; 177 178 static int char_width; 179 static int char_height; 180 181 /* current time in milliseconds */ 182 static int64_t curr_time_ms(void) 183 { 184 struct timespec tm; 185 clock_gettime(CLOCK_MONOTONIC, &tm); 186 return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC); 187 } 188 189 static void clear_screen(void) 190 { 191 gr_color(0, 0, 0, 255); 192 gr_fill(0, 0, gr_fb_width(), gr_fb_height()); 193 }; 194 195 #define MAX_KLOG_WRITE_BUF_SZ 256 196 197 static void dump_last_kmsg(void) 198 { 199 char *buf; 200 char *ptr; 201 unsigned sz = 0; 202 int len; 203 204 LOGI("\n"); 205 LOGI("*************** LAST KMSG ***************\n"); 206 LOGI("\n"); 207 buf = load_file(LAST_KMSG_PATH, &sz); 208 if (!buf || !sz) { 209 LOGI("last_kmsg not found. Cold reset?\n"); 210 goto out; 211 } 212 213 len = min(sz, LAST_KMSG_MAX_SZ); 214 ptr = buf + (sz - len); 215 216 while (len > 0) { 217 int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ); 218 char yoink; 219 char *nl; 220 221 nl = memrchr(ptr, '\n', cnt - 1); 222 if (nl) 223 cnt = nl - ptr + 1; 224 225 yoink = ptr[cnt]; 226 ptr[cnt] = '\0'; 227 klog_write(6, "<6>%s", ptr); 228 ptr[cnt] = yoink; 229 230 len -= cnt; 231 ptr += cnt; 232 } 233 234 free(buf); 235 236 out: 237 LOGI("\n"); 238 LOGI("************* END LAST KMSG *************\n"); 239 LOGI("\n"); 240 } 241 242 static int read_file(const char *path, char *buf, size_t sz) 243 { 244 int fd; 245 size_t cnt; 246 247 fd = open(path, O_RDONLY, 0); 248 if (fd < 0) 249 goto err; 250 251 cnt = read(fd, buf, sz - 1); 252 if (cnt <= 0) 253 goto err; 254 buf[cnt] = '\0'; 255 if (buf[cnt - 1] == '\n') { 256 cnt--; 257 buf[cnt] = '\0'; 258 } 259 260 close(fd); 261 return cnt; 262 263 err: 264 if (fd >= 0) 265 close(fd); 266 return -1; 267 } 268 269 static int read_file_int(const char *path, int *val) 270 { 271 char buf[32]; 272 int ret; 273 int tmp; 274 char *end; 275 276 ret = read_file(path, buf, sizeof(buf)); 277 if (ret < 0) 278 return -1; 279 280 tmp = strtol(buf, &end, 0); 281 if (end == buf || 282 ((end < buf+sizeof(buf)) && (*end != '\n' && *end != '\0'))) 283 goto err; 284 285 *val = tmp; 286 return 0; 287 288 err: 289 return -1; 290 } 291 292 static int get_battery_capacity(struct charger *charger) 293 { 294 int ret; 295 int batt_cap = -1; 296 297 if (!charger->battery) 298 return -1; 299 300 ret = read_file_int(charger->battery->cap_path, &batt_cap); 301 if (ret < 0 || batt_cap > 100) { 302 batt_cap = -1; 303 } 304 305 return batt_cap; 306 } 307 308 static struct power_supply *find_supply(struct charger *charger, 309 const char *name) 310 { 311 struct listnode *node; 312 struct power_supply *supply; 313 314 list_for_each(node, &charger->supplies) { 315 supply = node_to_item(node, struct power_supply, list); 316 if (!strncmp(name, supply->name, sizeof(supply->name))) 317 return supply; 318 } 319 return NULL; 320 } 321 322 static struct power_supply *add_supply(struct charger *charger, 323 const char *name, const char *type, 324 const char *path, bool online) 325 { 326 struct power_supply *supply; 327 328 supply = calloc(1, sizeof(struct power_supply)); 329 if (!supply) 330 return NULL; 331 332 strlcpy(supply->name, name, sizeof(supply->name)); 333 strlcpy(supply->type, type, sizeof(supply->type)); 334 snprintf(supply->cap_path, sizeof(supply->cap_path), 335 "/sys/%s/capacity", path); 336 supply->online = online; 337 list_add_tail(&charger->supplies, &supply->list); 338 charger->num_supplies++; 339 LOGV("... added %s %s %d\n", supply->name, supply->type, online); 340 return supply; 341 } 342 343 static void remove_supply(struct charger *charger, struct power_supply *supply) 344 { 345 if (!supply) 346 return; 347 list_remove(&supply->list); 348 charger->num_supplies--; 349 free(supply); 350 } 351 352 static void parse_uevent(const char *msg, struct uevent *uevent) 353 { 354 uevent->action = ""; 355 uevent->path = ""; 356 uevent->subsystem = ""; 357 uevent->ps_name = ""; 358 uevent->ps_online = ""; 359 uevent->ps_type = ""; 360 361 /* currently ignoring SEQNUM */ 362 while (*msg) { 363 #ifdef DEBUG_UEVENTS 364 LOGV("uevent str: %s\n", msg); 365 #endif 366 if (!strncmp(msg, "ACTION=", 7)) { 367 msg += 7; 368 uevent->action = msg; 369 } else if (!strncmp(msg, "DEVPATH=", 8)) { 370 msg += 8; 371 uevent->path = msg; 372 } else if (!strncmp(msg, "SUBSYSTEM=", 10)) { 373 msg += 10; 374 uevent->subsystem = msg; 375 } else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) { 376 msg += 18; 377 uevent->ps_name = msg; 378 } else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) { 379 msg += 20; 380 uevent->ps_online = msg; 381 } else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) { 382 msg += 18; 383 uevent->ps_type = msg; 384 } 385 386 /* advance to after the next \0 */ 387 while (*msg++) 388 ; 389 } 390 391 LOGV("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n", 392 uevent->action, uevent->path, uevent->subsystem, 393 uevent->ps_name, uevent->ps_type, uevent->ps_online); 394 } 395 396 static void process_ps_uevent(struct charger *charger, struct uevent *uevent) 397 { 398 int online; 399 char ps_type[32]; 400 struct power_supply *supply = NULL; 401 int i; 402 bool was_online = false; 403 bool battery = false; 404 405 if (uevent->ps_type[0] == '\0') { 406 char *path; 407 int ret; 408 409 if (uevent->path[0] == '\0') 410 return; 411 ret = asprintf(&path, "/sys/%s/type", uevent->path); 412 if (ret <= 0) 413 return; 414 ret = read_file(path, ps_type, sizeof(ps_type)); 415 free(path); 416 if (ret < 0) 417 return; 418 } else { 419 strlcpy(ps_type, uevent->ps_type, sizeof(ps_type)); 420 } 421 422 if (!strncmp(ps_type, "Battery", 7)) 423 battery = true; 424 425 online = atoi(uevent->ps_online); 426 supply = find_supply(charger, uevent->ps_name); 427 if (supply) { 428 was_online = supply->online; 429 supply->online = online; 430 } 431 432 if (!strcmp(uevent->action, "add")) { 433 if (!supply) { 434 supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path, 435 online); 436 if (!supply) { 437 LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name, 438 uevent->ps_type, online); 439 return; 440 } 441 /* only pick up the first battery for now */ 442 if (battery && !charger->battery) 443 charger->battery = supply; 444 } else { 445 LOGE("supply '%s' already exists..\n", uevent->ps_name); 446 } 447 } else if (!strcmp(uevent->action, "remove")) { 448 if (supply) { 449 if (charger->battery == supply) 450 charger->battery = NULL; 451 remove_supply(charger, supply); 452 supply = NULL; 453 } 454 } else if (!strcmp(uevent->action, "change")) { 455 if (!supply) { 456 LOGE("power supply '%s' not found ('%s' %d)\n", 457 uevent->ps_name, ps_type, online); 458 return; 459 } 460 } else { 461 return; 462 } 463 464 /* allow battery to be managed in the supply list but make it not 465 * contribute to online power supplies. */ 466 if (!battery) { 467 if (was_online && !online) 468 charger->num_supplies_online--; 469 else if (supply && !was_online && online) 470 charger->num_supplies_online++; 471 } 472 473 LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n", 474 uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline", 475 uevent->action, charger->num_supplies_online, charger->num_supplies); 476 } 477 478 static void process_uevent(struct charger *charger, struct uevent *uevent) 479 { 480 if (!strcmp(uevent->subsystem, "power_supply")) 481 process_ps_uevent(charger, uevent); 482 } 483 484 #define UEVENT_MSG_LEN 1024 485 static int handle_uevent_fd(struct charger *charger, int fd) 486 { 487 char msg[UEVENT_MSG_LEN+2]; 488 int n; 489 490 if (fd < 0) 491 return -1; 492 493 while (true) { 494 struct uevent uevent; 495 496 n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN); 497 if (n <= 0) 498 break; 499 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ 500 continue; 501 502 msg[n] = '\0'; 503 msg[n+1] = '\0'; 504 505 parse_uevent(msg, &uevent); 506 process_uevent(charger, &uevent); 507 } 508 509 return 0; 510 } 511 512 static int uevent_callback(int fd, short revents, void *data) 513 { 514 struct charger *charger = data; 515 516 if (!(revents & POLLIN)) 517 return -1; 518 return handle_uevent_fd(charger, fd); 519 } 520 521 /* force the kernel to regenerate the change events for the existing 522 * devices, if valid */ 523 static void do_coldboot(struct charger *charger, DIR *d, const char *event, 524 bool follow_links, int max_depth) 525 { 526 struct dirent *de; 527 int dfd, fd; 528 529 dfd = dirfd(d); 530 531 fd = openat(dfd, "uevent", O_WRONLY); 532 if (fd >= 0) { 533 write(fd, event, strlen(event)); 534 close(fd); 535 handle_uevent_fd(charger, charger->uevent_fd); 536 } 537 538 while ((de = readdir(d)) && max_depth > 0) { 539 DIR *d2; 540 541 LOGV("looking at '%s'\n", de->d_name); 542 543 if ((de->d_type != DT_DIR && !(de->d_type == DT_LNK && follow_links)) || 544 de->d_name[0] == '.') { 545 LOGV("skipping '%s' type %d (depth=%d follow=%d)\n", 546 de->d_name, de->d_type, max_depth, follow_links); 547 continue; 548 } 549 LOGV("can descend into '%s'\n", de->d_name); 550 551 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); 552 if (fd < 0) { 553 LOGE("cannot openat %d '%s' (%d: %s)\n", dfd, de->d_name, 554 errno, strerror(errno)); 555 continue; 556 } 557 558 d2 = fdopendir(fd); 559 if (d2 == 0) 560 close(fd); 561 else { 562 LOGV("opened '%s'\n", de->d_name); 563 do_coldboot(charger, d2, event, follow_links, max_depth - 1); 564 closedir(d2); 565 } 566 } 567 } 568 569 static void coldboot(struct charger *charger, const char *path, 570 const char *event) 571 { 572 char str[256]; 573 574 LOGV("doing coldboot '%s' in '%s'\n", event, path); 575 DIR *d = opendir(path); 576 if (d) { 577 snprintf(str, sizeof(str), "%s\n", event); 578 do_coldboot(charger, d, str, true, 1); 579 closedir(d); 580 } 581 } 582 583 static int draw_text(const char *str, int x, int y) 584 { 585 int str_len_px = gr_measure(str); 586 587 if (x < 0) 588 x = (gr_fb_width() - str_len_px) / 2; 589 if (y < 0) 590 y = (gr_fb_height() - char_height) / 2; 591 gr_text(x, y, str); 592 593 return y + char_height; 594 } 595 596 static void android_green(void) 597 { 598 gr_color(0xa4, 0xc6, 0x39, 255); 599 } 600 601 /* returns the last y-offset of where the surface ends */ 602 static int draw_surface_centered(struct charger *charger, gr_surface surface) 603 { 604 int w; 605 int h; 606 int x; 607 int y; 608 609 w = gr_get_width(surface); 610 h = gr_get_height(surface); 611 x = (gr_fb_width() - w) / 2 ; 612 y = (gr_fb_height() - h) / 2 ; 613 614 LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y); 615 gr_blit(surface, 0, 0, w, h, x, y); 616 return y + h; 617 } 618 619 static void draw_unknown(struct charger *charger) 620 { 621 int y; 622 if (charger->surf_unknown) { 623 draw_surface_centered(charger, charger->surf_unknown); 624 } else { 625 android_green(); 626 y = draw_text("Charging!", -1, -1); 627 draw_text("?\?/100", -1, y + 25); 628 } 629 } 630 631 static void draw_battery(struct charger *charger) 632 { 633 struct animation *batt_anim = charger->batt_anim; 634 struct frame *frame = &batt_anim->frames[batt_anim->cur_frame]; 635 636 if (batt_anim->num_frames != 0) { 637 draw_surface_centered(charger, frame->surface); 638 LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n", 639 batt_anim->cur_frame, frame->name, frame->min_capacity, 640 frame->disp_time); 641 } 642 } 643 644 static void redraw_screen(struct charger *charger) 645 { 646 struct animation *batt_anim = charger->batt_anim; 647 648 clear_screen(); 649 650 /* try to display *something* */ 651 if (batt_anim->capacity < 0 || batt_anim->num_frames == 0) 652 draw_unknown(charger); 653 else 654 draw_battery(charger); 655 gr_flip(); 656 } 657 658 static void kick_animation(struct animation *anim) 659 { 660 anim->run = true; 661 } 662 663 static void reset_animation(struct animation *anim) 664 { 665 anim->cur_cycle = 0; 666 anim->cur_frame = 0; 667 anim->run = false; 668 } 669 670 static void update_screen_state(struct charger *charger, int64_t now) 671 { 672 struct animation *batt_anim = charger->batt_anim; 673 int cur_frame; 674 int disp_time; 675 676 if (!batt_anim->run || now < charger->next_screen_transition) 677 return; 678 679 /* animation is over, blank screen and leave */ 680 if (batt_anim->cur_cycle == batt_anim->num_cycles) { 681 reset_animation(batt_anim); 682 charger->next_screen_transition = -1; 683 gr_fb_blank(true); 684 LOGV("[%lld] animation done\n", now); 685 return; 686 } 687 688 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time; 689 690 /* animation starting, set up the animation */ 691 if (batt_anim->cur_frame == 0) { 692 int batt_cap; 693 int ret; 694 695 LOGV("[%lld] animation starting\n", now); 696 batt_cap = get_battery_capacity(charger); 697 if (batt_cap >= 0 && batt_anim->num_frames != 0) { 698 int i; 699 700 /* find first frame given current capacity */ 701 for (i = 1; i < batt_anim->num_frames; i++) { 702 if (batt_cap < batt_anim->frames[i].min_capacity) 703 break; 704 } 705 batt_anim->cur_frame = i - 1; 706 707 /* show the first frame for twice as long */ 708 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2; 709 } 710 711 batt_anim->capacity = batt_cap; 712 } 713 714 /* unblank the screen on first cycle */ 715 if (batt_anim->cur_cycle == 0) 716 gr_fb_blank(false); 717 718 /* draw the new frame (@ cur_frame) */ 719 redraw_screen(charger); 720 721 /* if we don't have anim frames, we only have one image, so just bump 722 * the cycle counter and exit 723 */ 724 if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) { 725 LOGV("[%lld] animation missing or unknown battery status\n", now); 726 charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME; 727 batt_anim->cur_cycle++; 728 return; 729 } 730 731 /* schedule next screen transition */ 732 charger->next_screen_transition = now + disp_time; 733 734 /* advance frame cntr to the next valid frame 735 * if necessary, advance cycle cntr, and reset frame cntr 736 */ 737 batt_anim->cur_frame++; 738 if (batt_anim->cur_frame == batt_anim->num_frames) { 739 batt_anim->cur_cycle++; 740 batt_anim->cur_frame = 0; 741 742 /* don't reset the cycle counter, since we use that as a signal 743 * in a test above to check if animation is over 744 */ 745 } 746 } 747 748 static int set_key_callback(int code, int value, void *data) 749 { 750 struct charger *charger = data; 751 int64_t now = curr_time_ms(); 752 int down = !!value; 753 754 if (code > KEY_MAX) 755 return -1; 756 757 /* ignore events that don't modify our state */ 758 if (charger->keys[code].down == down) 759 return 0; 760 761 /* only record the down even timestamp, as the amount 762 * of time the key spent not being pressed is not useful */ 763 if (down) 764 charger->keys[code].timestamp = now; 765 charger->keys[code].down = down; 766 charger->keys[code].pending = true; 767 if (down) { 768 LOGV("[%lld] key[%d] down\n", now, code); 769 } else { 770 int64_t duration = now - charger->keys[code].timestamp; 771 int64_t secs = duration / 1000; 772 int64_t msecs = duration - secs * 1000; 773 LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now, 774 code, secs, msecs); 775 } 776 777 return 0; 778 } 779 780 static void update_input_state(struct charger *charger, 781 struct input_event *ev) 782 { 783 if (ev->type != EV_KEY) 784 return; 785 set_key_callback(ev->code, ev->value, charger); 786 } 787 788 static void set_next_key_check(struct charger *charger, 789 struct key_state *key, 790 int64_t timeout) 791 { 792 int64_t then = key->timestamp + timeout; 793 794 if (charger->next_key_check == -1 || then < charger->next_key_check) 795 charger->next_key_check = then; 796 } 797 798 static void process_key(struct charger *charger, int code, int64_t now) 799 { 800 struct key_state *key = &charger->keys[code]; 801 int64_t next_key_check; 802 803 if (code == KEY_POWER) { 804 if (key->down) { 805 int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME; 806 if (now >= reboot_timeout) { 807 LOGI("[%lld] rebooting\n", now); 808 android_reboot(ANDROID_RB_RESTART, 0, 0); 809 } else { 810 /* if the key is pressed but timeout hasn't expired, 811 * make sure we wake up at the right-ish time to check 812 */ 813 set_next_key_check(charger, key, POWER_ON_KEY_TIME); 814 } 815 } else { 816 /* if the power key got released, force screen state cycle */ 817 if (key->pending) 818 kick_animation(charger->batt_anim); 819 } 820 } 821 822 key->pending = false; 823 } 824 825 static void handle_input_state(struct charger *charger, int64_t now) 826 { 827 process_key(charger, KEY_POWER, now); 828 829 if (charger->next_key_check != -1 && now > charger->next_key_check) 830 charger->next_key_check = -1; 831 } 832 833 static void handle_power_supply_state(struct charger *charger, int64_t now) 834 { 835 if (charger->num_supplies_online == 0) { 836 if (charger->next_pwr_check == -1) { 837 charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME; 838 LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n", 839 now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check); 840 } else if (now >= charger->next_pwr_check) { 841 LOGI("[%lld] shutting down\n", now); 842 android_reboot(ANDROID_RB_POWEROFF, 0, 0); 843 } else { 844 /* otherwise we already have a shutdown timer scheduled */ 845 } 846 } else { 847 /* online supply present, reset shutdown timer if set */ 848 if (charger->next_pwr_check != -1) { 849 LOGI("[%lld] device plugged in: shutdown cancelled\n", now); 850 kick_animation(charger->batt_anim); 851 } 852 charger->next_pwr_check = -1; 853 } 854 } 855 856 static void wait_next_event(struct charger *charger, int64_t now) 857 { 858 int64_t next_event = INT64_MAX; 859 int64_t timeout; 860 struct input_event ev; 861 int ret; 862 863 LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now, 864 charger->next_screen_transition, charger->next_key_check, 865 charger->next_pwr_check); 866 867 if (charger->next_screen_transition != -1) 868 next_event = charger->next_screen_transition; 869 if (charger->next_key_check != -1 && charger->next_key_check < next_event) 870 next_event = charger->next_key_check; 871 if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event) 872 next_event = charger->next_pwr_check; 873 874 if (next_event != -1 && next_event != INT64_MAX) 875 timeout = max(0, next_event - now); 876 else 877 timeout = -1; 878 LOGV("[%lld] blocking (%lld)\n", now, timeout); 879 ret = ev_wait((int)timeout); 880 if (!ret) 881 ev_dispatch(); 882 } 883 884 static int input_callback(int fd, short revents, void *data) 885 { 886 struct charger *charger = data; 887 struct input_event ev; 888 int ret; 889 890 ret = ev_get_input(fd, revents, &ev); 891 if (ret) 892 return -1; 893 update_input_state(charger, &ev); 894 return 0; 895 } 896 897 static void event_loop(struct charger *charger) 898 { 899 int ret; 900 901 while (true) { 902 int64_t now = curr_time_ms(); 903 904 LOGV("[%lld] event_loop()\n", now); 905 handle_input_state(charger, now); 906 handle_power_supply_state(charger, now); 907 908 /* do screen update last in case any of the above want to start 909 * screen transitions (animations, etc) 910 */ 911 update_screen_state(charger, now); 912 913 wait_next_event(charger, now); 914 } 915 } 916 917 int main(int argc, char **argv) 918 { 919 int ret; 920 struct charger *charger = &charger_state; 921 int64_t now = curr_time_ms() - 1; 922 int fd; 923 int i; 924 925 list_init(&charger->supplies); 926 927 klog_init(); 928 klog_set_level(CHARGER_KLOG_LEVEL); 929 930 dump_last_kmsg(); 931 932 LOGI("--------------- STARTING CHARGER MODE ---------------\n"); 933 934 gr_init(); 935 gr_font_size(&char_width, &char_height); 936 937 ev_init(input_callback, charger); 938 939 fd = uevent_open_socket(64*1024, true); 940 if (fd >= 0) { 941 fcntl(fd, F_SETFL, O_NONBLOCK); 942 ev_add_fd(fd, uevent_callback, charger); 943 } 944 charger->uevent_fd = fd; 945 coldboot(charger, "/sys/class/power_supply", "add"); 946 947 ret = res_create_surface("charger/battery_fail", &charger->surf_unknown); 948 if (ret < 0) { 949 LOGE("Cannot load image\n"); 950 charger->surf_unknown = NULL; 951 } 952 953 for (i = 0; i < charger->batt_anim->num_frames; i++) { 954 struct frame *frame = &charger->batt_anim->frames[i]; 955 956 ret = res_create_surface(frame->name, &frame->surface); 957 if (ret < 0) { 958 LOGE("Cannot load image %s\n", frame->name); 959 /* TODO: free the already allocated surfaces... */ 960 charger->batt_anim->num_frames = 0; 961 charger->batt_anim->num_cycles = 1; 962 break; 963 } 964 } 965 966 ev_sync_key_state(set_key_callback, charger); 967 968 gr_fb_blank(true); 969 970 charger->next_screen_transition = now - 1; 971 charger->next_key_check = -1; 972 charger->next_pwr_check = -1; 973 reset_animation(charger->batt_anim); 974 kick_animation(charger->batt_anim); 975 976 event_loop(charger); 977 978 return 0; 979 } 980