diff --git a/charger/healthd_board_lineage.cpp b/charger/healthd_board_lineage.cpp index ea0212a3..dcfbc4a6 100644 --- a/charger/healthd_board_lineage.cpp +++ b/charger/healthd_board_lineage.cpp @@ -33,9 +33,10 @@ #include #include -#include -#include #include +#include +#include +#include #include "healthd/healthd.h" #include "minui/minui.h" @@ -106,12 +107,6 @@ enum alarm_time_type { RTC_TIME, }; -/* - * shouldn't be changed after - * reading from alarm register - */ -static time_t alm_secs; - static int alarm_get_time(enum alarm_time_type time_type, time_t *secs) { @@ -160,104 +155,88 @@ err: return -1; } -#define ERR_SECS 2 -static int alarm_is_alm_expired() +static void alarm_reboot(void) { - int rc; - time_t rtc_secs; - - rc = alarm_get_time(RTC_TIME, &rtc_secs); - if (rc < 0) - return 0; - - return (alm_secs >= rtc_secs - ERR_SECS && - alm_secs <= rtc_secs + ERR_SECS) ? 1 : 0; -} - -static int timerfd_set_reboot_time_and_wait(time_t secs) -{ - int fd; - int ret = -1; - fd = timerfd_create(CLOCK_REALTIME_ALARM, 0); - if (fd < 0) { - LOGE("Can't open timerfd alarm node\n"); - goto err_return; - } - - struct itimerspec spec; - memset(&spec, 0, sizeof(spec)); - spec.it_value.tv_sec = secs; - - if (timerfd_settime(fd, 0 /* relative */, &spec, NULL)) { - LOGE("Can't set timerfd alarm\n"); - goto err_close; - } - - uint64_t unused; - if (read(fd, &unused, sizeof(unused)) < 0) { - LOGE("Wait alarm error\n"); - goto err_close; - } - - ret = 0; -err_close: - close(fd); -err_return: - return ret; + LOGI("alarm time is up, reboot the phone!\n"); + syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, "rtc"); } static int alarm_set_reboot_time_and_wait(time_t secs) { - int rc, fd; + int rc, epollfd, nevents; + int fd = 0; struct timespec ts; + epoll_event event, events[1]; + struct itimerspec itval; - fd = open("/dev/alarm", O_RDWR); + epollfd = epoll_create(1); + if (epollfd < 0) { + LOGE("epoll_create failed\n"); + goto err; + } + + fd = timerfd_create(CLOCK_REALTIME_ALARM, 0); if (fd < 0) { - LOGE("Can't open alarm devfs node, trying timerfd\n"); - return timerfd_set_reboot_time_and_wait(secs); - } - - /* get the elapsed realtime from boot time to now */ - rc = ioctl(fd, ANDROID_ALARM_GET_TIME( - ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP), &ts); - if (rc < 0) { - LOGE("Unable to get elapsed realtime\n"); + LOGE("timerfd_create failed\n"); goto err; } - /* calculate the elapsed time from boot time to reboot time */ - ts.tv_sec += secs; - ts.tv_nsec = 0; - - rc = ioctl(fd, ANDROID_ALARM_SET( - ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP), &ts); + event.events = EPOLLIN | EPOLLWAKEUP; + event.data.ptr = (void *)alarm_reboot; + rc = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event); if (rc < 0) { - LOGE("Unable to set reboot time to %ld\n", secs); + LOGE("epoll_ctl(EPOLL_CTL_ADD) failed \n"); goto err; } - do { - rc = ioctl(fd, ANDROID_ALARM_WAIT); - } while ((rc < 0 && errno == EINTR) || !alarm_is_alm_expired()); + itval.it_value.tv_sec = secs; + itval.it_value.tv_nsec = 0; - if (rc <= 0) { + itval.it_interval.tv_sec = 0; + itval.it_interval.tv_nsec = 0; + + rc = timerfd_settime(fd, TFD_TIMER_ABSTIME, &itval, NULL); + if (rc < 0) { + LOGE("timerfd_settime failed %d\n",rc); + goto err; + } + + nevents = epoll_wait(epollfd, events, 1, -1); + + if (nevents <= 0) { LOGE("Unable to wait on alarm\n"); goto err; + } else { + (*(void (*)())events[0].data.ptr)(); } + close(epollfd); close(fd); return 0; err: + if (epollfd > 0) + close(epollfd); + if (fd >= 0) close(fd); return -1; } +/* + * 10s the estimated time from timestamp of alarm thread start + * to timestamp of android boot completed. + */ +#define TIME_DELTA 10 + +/* seconds of 1 minute*/ +#define ONE_MINUTE 60 static void *alarm_thread(void *) { - time_t rtc_secs, rb_secs; + time_t rtc_secs, alarm_secs; int rc; + timespec ts; /* * to support power off alarm, the time @@ -266,31 +245,39 @@ static void *alarm_thread(void *) * earlier than the actual alarm time * set by user */ - rc = alarm_get_time(ALARM_TIME, &alm_secs); - LOGI("RTC Alarm %ld\n", alm_secs); - if (rc < 0 || !alm_secs) + rc = alarm_get_time(ALARM_TIME, &alarm_secs); + if (rc < 0 || !alarm_secs) goto err; rc = alarm_get_time(RTC_TIME, &rtc_secs); - LOGI("RTC Clock %ld\n", rtc_secs); + if (rc < 0 || !rtc_secs) + goto err; + LOGI("alarm time in rtc is %ld, rtc time is %ld\n", alarm_secs, rtc_secs); + + if (alarm_secs <= rtc_secs) { + clock_gettime(CLOCK_BOOTTIME, &ts); + + /* + * It is possible that last power off alarm time is up at this point. + * (alarm_secs + ONE_MINUTE) is the final alarm time to fire. + * (rtc_secs + ts.tv_sec + TIME_DELTA) is the estimated time of next + * boot completed to fire alarm. + * If the final alarm time is less than the estimated time of next boot + * completed to fire, that means it is not able to fire the last power + * off alarm at the right time, so just miss it. + */ + if (alarm_secs + ONE_MINUTE < rtc_secs + ts.tv_sec + TIME_DELTA) { + LOGE("alarm is missed\n"); + goto err; + } + + alarm_reboot(); + } + + rc = alarm_set_reboot_time_and_wait(alarm_secs); if (rc < 0) goto err; - /* - * calculate the reboot time after which - * the phone will reboot - */ - rb_secs = alm_secs - rtc_secs; - if (rb_secs <= 0) - goto err; - - rc = alarm_set_reboot_time_and_wait(rb_secs); - if (rc < 0) - goto err; - - LOGI("Exit from power off charging, reboot the phone!\n"); - android_reboot(ANDROID_RB_RESTART, 0, 0); - err: LOGE("Exit from alarm thread\n"); return NULL;