summaryrefslogtreecommitdiffstats
path: root/services/core/jni
diff options
context:
space:
mode:
authorGreg Hackmann <ghackmann@google.com>2014-02-26 12:22:13 -0800
committerGreg Hackmann <ghackmann@google.com>2015-01-13 12:16:56 -0800
commit0eb5826830592695f4a5b4d1dba18e0ca991163e (patch)
treee99cf4f2ed5efd25c966384acc6495e2d586e547 /services/core/jni
parent66b4d48469c74f7dd889f3f685b436fcb957bf16 (diff)
downloadframeworks_base-0eb5826830592695f4a5b4d1dba18e0ca991163e.zip
frameworks_base-0eb5826830592695f4a5b4d1dba18e0ca991163e.tar.gz
frameworks_base-0eb5826830592695f4a5b4d1dba18e0ca991163e.tar.bz2
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 <ghackmann@google.com>
Diffstat (limited to 'services/core/jni')
-rw-r--r--services/core/jni/com_android_server_AlarmManagerService.cpp80
1 files 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 3d981ab..3fd0f84 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 <utils/Log.h>
#include <utils/misc.h>
+#include <utils/String8.h>
+#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
@@ -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<jlong>(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;