From 0eb5826830592695f4a5b4d1dba18e0ca991163e Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Wed, 26 Feb 2014 12:22:13 -0800 Subject: [PATCH] Find wall clock RTC through sysfs Devices may have multiple RTCs. By default the kernel uses rtc0 to store the system time, but devices may override this (or even specify that none of them should be used for system time). Userspace can indirectly find the designated RTC through sysfs. During AlarmManagerService initialization, enumerate through all rtc class devices to locate the device with attribute hctosys=1. This is only done on devices without /dev/alarm, which has its own in-kernel mechanism to pick the RTC. Change-Id: Ife2b342c3590133ed316ddaf1799cbc1bfa6e6d9 Signed-off-by: Greg Hackmann --- .../jni/com_android_server_AlarmManagerService.cpp | 80 ++++++++++++++++++++-- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp index 3d981abf5ff0..3fd0f84f5957 100644 --- a/services/core/jni/com_android_server_AlarmManagerService.cpp +++ b/services/core/jni/com_android_server_AlarmManagerService.cpp @@ -21,7 +21,9 @@ #include "jni.h" #include #include +#include +#include #include #include #include @@ -80,8 +82,8 @@ public: class AlarmImplTimerFd : public AlarmImpl { public: - AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd) : - AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd) { } + AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) : + AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { } ~AlarmImplTimerFd(); int set(int type, struct timespec *ts); @@ -90,6 +92,7 @@ public: private: int epollfd; + int rtc_id; }; AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]), @@ -170,9 +173,16 @@ int AlarmImplTimerFd::setTime(struct timeval *tv) return -1; } - fd = open("/dev/rtc0", O_RDWR); + if (rtc_id < 0) { + ALOGV("Not setting RTC because wall clock RTC was not found"); + errno = ENODEV; + return -1; + } + + android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id); + fd = open(rtc_dev.string(), O_RDWR); if (fd < 0) { - ALOGV("Unable to open RTC driver: %s\n", strerror(errno)); + ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno)); return res; } @@ -283,6 +293,66 @@ static jlong init_alarm_driver() return reinterpret_cast(ret); } +static const char rtc_sysfs[] = "/sys/class/rtc"; + +static bool rtc_is_hctosys(unsigned int rtc_id) +{ + android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys", + rtc_sysfs, rtc_id); + + FILE *file = fopen(hctosys_path.string(), "re"); + if (!file) { + ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno)); + return false; + } + + unsigned int hctosys; + bool ret = false; + int err = fscanf(file, "%u", &hctosys); + if (err == EOF) + ALOGE("failed to read from %s: %s", hctosys_path.string(), + strerror(errno)); + else if (err == 0) + ALOGE("%s did not have expected contents", hctosys_path.string()); + else + ret = hctosys; + + fclose(file); + return ret; +} + +static int wall_clock_rtc() +{ + DIR *dir = opendir(rtc_sysfs); + if (!dir) { + ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno)); + return -1; + } + + struct dirent *dirent; + while (errno = 0, dirent = readdir(dir)) { + unsigned int rtc_id; + int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id); + + if (matched < 0) + break; + else if (matched != 1) + continue; + + if (rtc_is_hctosys(rtc_id)) { + ALOGV("found wall clock RTC %u", rtc_id); + return rtc_id; + } + } + + if (errno == 0) + ALOGW("no wall clock RTC found"); + else + ALOGE("failed to enumerate RTCs: %s", strerror(errno)); + + return -1; +} + static jlong init_timerfd() { int epollfd; @@ -308,7 +378,7 @@ static jlong init_timerfd() } } - AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd); + AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc()); for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { epoll_event event; -- 2.11.0