diff options
| -rw-r--r-- | services/core/jni/com_android_server_AlarmManagerService.cpp | 149 |
1 files changed, 108 insertions, 41 deletions
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp index 36105bd12b1d..407c0726e521 100644 --- a/services/core/jni/com_android_server_AlarmManagerService.cpp +++ b/services/core/jni/com_android_server_AlarmManagerService.cpp @@ -37,28 +37,13 @@ #include <errno.h> #include <unistd.h> #include <linux/ioctl.h> +#include <linux/android_alarm.h> #include <linux/rtc.h> -#include <array> #include <memory> namespace android { -static constexpr int ANDROID_ALARM_TIME_CHANGE_MASK = 1 << 16; - -/** - * The AlarmManager alarm constants: - * - * RTC_WAKEUP - * RTC - * REALTIME_WAKEUP - * REALTIME - * SYSTEMTIME (only defined in old alarm driver header, possibly unused?) - * - * We also need an extra CLOCK_REALTIME fd which exists specifically to be - * canceled on RTC changes. - */ -static const size_t ANDROID_ALARM_TYPE_COUNT = 5; static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1; static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = { CLOCK_REALTIME_ALARM, @@ -68,39 +53,98 @@ static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = { CLOCK_MONOTONIC, CLOCK_REALTIME, }; - -typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds; +/* to match the legacy alarm driver implementation, we need an extra + CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */ class AlarmImpl { public: - AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) : - fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { } - ~AlarmImpl(); + AlarmImpl(int *fds, size_t n_fds); + virtual ~AlarmImpl(); + + virtual int set(int type, struct timespec *ts) = 0; + virtual int setTime(struct timeval *tv) = 0; + virtual int waitForAlarm() = 0; + +protected: + int *fds; + size_t n_fds; +}; + +class AlarmImplAlarmDriver : public AlarmImpl +{ +public: + explicit AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { } + + int set(int type, struct timespec *ts); + int setTime(struct timeval *tv); + int waitForAlarm(); +}; + +class AlarmImplTimerFd : public AlarmImpl +{ +public: + 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); int setTime(struct timeval *tv); int waitForAlarm(); private: - const TimerFds fds; - const int epollfd; - const int rtc_id; + int epollfd; + int rtc_id; }; +AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]), + n_fds(n_fds) +{ + memcpy(fds, fds_, n_fds * sizeof(fds[0])); +} + AlarmImpl::~AlarmImpl() { - for (auto fd : fds) { - epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr); - close(fd); + for (size_t i = 0; i < n_fds; i++) { + close(fds[i]); } + delete [] fds; +} + +int AlarmImplAlarmDriver::set(int type, struct timespec *ts) +{ + return ioctl(fds[0], ANDROID_ALARM_SET(type), ts); +} + +int AlarmImplAlarmDriver::setTime(struct timeval *tv) +{ + struct timespec ts; + int res; + ts.tv_sec = tv->tv_sec; + ts.tv_nsec = tv->tv_usec * 1000; + res = ioctl(fds[0], ANDROID_ALARM_SET_RTC, &ts); + if (res < 0) + ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno)); + return res; +} + +int AlarmImplAlarmDriver::waitForAlarm() +{ + return ioctl(fds[0], ANDROID_ALARM_WAIT); +} + +AlarmImplTimerFd::~AlarmImplTimerFd() +{ + for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { + epoll_ctl(epollfd, EPOLL_CTL_DEL, fds[i], NULL); + } close(epollfd); } -int AlarmImpl::set(int type, struct timespec *ts) +int AlarmImplTimerFd::set(int type, struct timespec *ts) { - if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) { + if (type > ANDROID_ALARM_TYPE_COUNT) { errno = EINVAL; return -1; } @@ -118,7 +162,7 @@ int AlarmImpl::set(int type, struct timespec *ts) return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL); } -int AlarmImpl::setTime(struct timeval *tv) +int AlarmImplTimerFd::setTime(struct timeval *tv) { struct rtc_time rtc; struct tm tm, *gmtime_res; @@ -169,7 +213,7 @@ done: return res; } -int AlarmImpl::waitForAlarm() +int AlarmImplTimerFd::waitForAlarm() { epoll_event events[N_ANDROID_TIMERFDS]; @@ -239,12 +283,25 @@ static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobjec return 0; } +static jlong init_alarm_driver() +{ + int fd = open("/dev/alarm", O_RDWR); + if (fd < 0) { + ALOGV("opening alarm driver failed: %s", strerror(errno)); + return 0; + } + + AlarmImpl *ret = new AlarmImplAlarmDriver(fd); + 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)); @@ -298,22 +355,22 @@ static int wall_clock_rtc() return -1; } -static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) +static jlong init_timerfd() { int epollfd; - TimerFds fds; + int fds[N_ANDROID_TIMERFDS]; - epollfd = epoll_create(fds.size()); + epollfd = epoll_create(N_ANDROID_TIMERFDS); if (epollfd < 0) { - ALOGE("epoll_create(%zu) failed: %s", fds.size(), + ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS, strerror(errno)); return 0; } - for (size_t i = 0; i < fds.size(); i++) { + for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { fds[i] = timerfd_create(android_alarm_to_clockid[i], 0); if (fds[i] < 0) { - ALOGE("timerfd_create(%u) failed: %s", android_alarm_to_clockid[i], + ALOGV("timerfd_create(%u) failed: %s", android_alarm_to_clockid[i], strerror(errno)); close(epollfd); for (size_t j = 0; j < i; j++) { @@ -323,16 +380,16 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) } } - AlarmImpl *ret = new AlarmImpl(fds, epollfd, wall_clock_rtc()); + AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc()); - for (size_t i = 0; i < fds.size(); i++) { + for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { epoll_event event; event.events = EPOLLIN | EPOLLWAKEUP; event.data.u32 = i; int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event); if (err < 0) { - ALOGE("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno)); + ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno)); delete ret; return 0; } @@ -346,7 +403,7 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT], TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL); if (err < 0) { - ALOGE("timerfd_settime() failed: %s", strerror(errno)); + ALOGV("timerfd_settime() failed: %s", strerror(errno)); delete ret; return 0; } @@ -354,6 +411,16 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) return reinterpret_cast<jlong>(ret); } +static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) +{ + jlong ret = init_alarm_driver(); + if (ret) { + return ret; + } + + return init_timerfd(); +} + static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData) { AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); |