Skip to content

Commit

Permalink
Find wall clock RTC through sysfs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
greghackmann authored and Chairshot215 committed Jan 16, 2015
1 parent b291365 commit 9d2f144
Showing 1 changed file with 75 additions and 5 deletions.
80 changes: 75 additions & 5 deletions services/core/jni/com_android_server_AlarmManagerService.cpp
Expand Up @@ -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>
Expand Down Expand Up @@ -80,8 +82,8 @@ class AlarmImplAlarmDriver : public AlarmImpl
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);
Expand All @@ -90,6 +92,7 @@ class AlarmImplTimerFd : public AlarmImpl

private:
int epollfd;
int rtc_id;
};

AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]),
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down

0 comments on commit 9d2f144

Please sign in to comment.