336 lines
11 KiB
Diff
336 lines
11 KiB
Diff
From 1d63e15119ada24bc78c5b06b051f9313497a813 Mon Sep 17 00:00:00 2001
|
|
From: Moyster <oysterized@gmail.com>
|
|
Date: Wed, 14 Feb 2018 14:25:40 +0100
|
|
Subject: [PATCH] mtk: bring back legacy /dev/alarm support
|
|
|
|
Revert "AlarmManagerService: explain some timerfd_create() failures"
|
|
This reverts commit a0126e0857481866dab5060384d611c83ca53d0e.
|
|
|
|
Revert "AlarmManagerService: remove legacy /dev/alarm support"
|
|
This reverts commit d7151c06f11c05ad3dcab175a6e4b4ea694dab96.
|
|
---
|
|
.../jni/com_android_server_AlarmManagerService.cpp | 204 ++++++++++++++-------
|
|
1 file changed, 137 insertions(+), 67 deletions(-)
|
|
|
|
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
|
|
index bcb0b4fcbe0..ab446b44f20 100644
|
|
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
|
|
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
|
|
@@ -39,26 +39,39 @@
|
|
#include <linux/ioctl.h>
|
|
#include <linux/rtc.h>
|
|
|
|
-#include <array>
|
|
#include <memory>
|
|
|
|
+//--------------------------------------------------------------------------
|
|
+// The android_alarm.h header has been deleted from the kernel headers.
|
|
+// Add only the parts still needed, this should be deleted in the future.
|
|
+#include <linux/ioctl.h>
|
|
+
|
|
+enum android_alarm_type {
|
|
+ ANDROID_ALARM_RTC_WAKEUP,
|
|
+ ANDROID_ALARM_RTC,
|
|
+ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
|
|
+ ANDROID_ALARM_ELAPSED_REALTIME,
|
|
+ ANDROID_ALARM_SYSTEMTIME,
|
|
+ ANDROID_ALARM_TYPE_COUNT,
|
|
+};
|
|
+
|
|
+enum android_alarm_return_flags {
|
|
+ ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
|
|
+ ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
|
|
+ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK = 1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
|
|
+ ANDROID_ALARM_ELAPSED_REALTIME_MASK = 1U << ANDROID_ALARM_ELAPSED_REALTIME,
|
|
+ ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
|
|
+ ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
|
|
+};
|
|
+
|
|
+#define ALARM_IOW(c,type,size) _IOW('a', (c) | ((type) << 4), size)
|
|
+#define ANDROID_ALARM_WAIT _IO('a', 1)
|
|
+#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
|
|
+#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
|
|
+//--------------------------------------------------------------------------
|
|
+
|
|
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 +81,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 +190,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 +241,7 @@ done:
|
|
return res;
|
|
}
|
|
|
|
-int AlarmImpl::waitForAlarm()
|
|
+int AlarmImplTimerFd::waitForAlarm()
|
|
{
|
|
epoll_event events[N_ANDROID_TIMERFDS];
|
|
|
|
@@ -239,12 +311,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,48 +383,23 @@ static int wall_clock_rtc()
|
|
return -1;
|
|
}
|
|
|
|
-static void log_timerfd_create_error(clockid_t id)
|
|
-{
|
|
- if (errno == EINVAL) {
|
|
- switch (id) {
|
|
- case CLOCK_REALTIME_ALARM:
|
|
- case CLOCK_BOOTTIME_ALARM:
|
|
- ALOGE("kernel missing required commits:");
|
|
- ALOGE("https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6cffe00f7d4e24679eae6b7aae4caaf915288256");
|
|
- ALOGE("https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=11ffa9d6065f344a9bd769a2452f26f2f671e5f8");
|
|
- LOG_ALWAYS_FATAL("kernel does not support timerfd_create() with alarm timers");
|
|
- break;
|
|
-
|
|
- case CLOCK_BOOTTIME:
|
|
- ALOGE("kernel missing required commit:");
|
|
- ALOGE("https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=4a2378a943f09907fb1ae35c15de917f60289c14");
|
|
- LOG_ALWAYS_FATAL("kernel does not support timerfd_create(CLOCK_BOOTTIME)");
|
|
- break;
|
|
-
|
|
- default:
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- ALOGE("timerfd_create(%u) failed: %s", id, strerror(errno));
|
|
-}
|
|
-
|
|
-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) {
|
|
- log_timerfd_create_error(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++) {
|
|
close(fds[j]);
|
|
@@ -348,16 +408,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;
|
|
}
|
|
@@ -371,7 +431,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;
|
|
}
|
|
@@ -379,6 +439,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);
|
|
--
|
|
2.14.1
|
|
|