Merge "Revert "AlarmManagerService: remove legacy /dev/alarm support"" am: 6fb921a61b am: 359a4d9569
am: f11d0fe8c5
* commit 'f11d0fe8c5a0906a7b6295adea9da1d544a3a22d':
Revert "AlarmManagerService: remove legacy /dev/alarm support"
Change-Id: I59c0d3b1e08ed98fa8d2e4e1c3ff4992d3088814
This commit is contained in:
@@ -37,28 +37,13 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <linux/ioctl.h>
|
#include <linux/ioctl.h>
|
||||||
|
#include <linux/android_alarm.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace android {
|
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 size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
|
||||||
static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
|
static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
|
||||||
CLOCK_REALTIME_ALARM,
|
CLOCK_REALTIME_ALARM,
|
||||||
@@ -68,39 +53,98 @@ static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
|
|||||||
CLOCK_MONOTONIC,
|
CLOCK_MONOTONIC,
|
||||||
CLOCK_REALTIME,
|
CLOCK_REALTIME,
|
||||||
};
|
};
|
||||||
|
/* to match the legacy alarm driver implementation, we need an extra
|
||||||
typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
|
CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */
|
||||||
|
|
||||||
class AlarmImpl
|
class AlarmImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) :
|
AlarmImpl(int *fds, size_t n_fds);
|
||||||
fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { }
|
virtual ~AlarmImpl();
|
||||||
~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 set(int type, struct timespec *ts);
|
||||||
int setTime(struct timeval *tv);
|
int setTime(struct timeval *tv);
|
||||||
int waitForAlarm();
|
int waitForAlarm();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const TimerFds fds;
|
int epollfd;
|
||||||
const int epollfd;
|
int rtc_id;
|
||||||
const 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()
|
AlarmImpl::~AlarmImpl()
|
||||||
{
|
{
|
||||||
for (auto fd : fds) {
|
for (size_t i = 0; i < n_fds; i++) {
|
||||||
epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr);
|
close(fds[i]);
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
|
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);
|
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;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -118,7 +162,7 @@ int AlarmImpl::set(int type, struct timespec *ts)
|
|||||||
return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
|
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 rtc_time rtc;
|
||||||
struct tm tm, *gmtime_res;
|
struct tm tm, *gmtime_res;
|
||||||
@@ -169,7 +213,7 @@ done:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AlarmImpl::waitForAlarm()
|
int AlarmImplTimerFd::waitForAlarm()
|
||||||
{
|
{
|
||||||
epoll_event events[N_ANDROID_TIMERFDS];
|
epoll_event events[N_ANDROID_TIMERFDS];
|
||||||
|
|
||||||
@@ -239,12 +283,25 @@ static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobjec
|
|||||||
return 0;
|
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 const char rtc_sysfs[] = "/sys/class/rtc";
|
||||||
|
|
||||||
static bool rtc_is_hctosys(unsigned int rtc_id)
|
static bool rtc_is_hctosys(unsigned int rtc_id)
|
||||||
{
|
{
|
||||||
android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
|
android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
|
||||||
rtc_sysfs, rtc_id);
|
rtc_sysfs, rtc_id);
|
||||||
|
|
||||||
FILE *file = fopen(hctosys_path.string(), "re");
|
FILE *file = fopen(hctosys_path.string(), "re");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
|
ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
|
||||||
@@ -298,22 +355,22 @@ static int wall_clock_rtc()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
|
static jlong init_timerfd()
|
||||||
{
|
{
|
||||||
int epollfd;
|
int epollfd;
|
||||||
TimerFds fds;
|
int fds[N_ANDROID_TIMERFDS];
|
||||||
|
|
||||||
epollfd = epoll_create(fds.size());
|
epollfd = epoll_create(N_ANDROID_TIMERFDS);
|
||||||
if (epollfd < 0) {
|
if (epollfd < 0) {
|
||||||
ALOGE("epoll_create(%zu) failed: %s", fds.size(),
|
ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return 0;
|
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);
|
fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
|
||||||
if (fds[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));
|
strerror(errno));
|
||||||
close(epollfd);
|
close(epollfd);
|
||||||
for (size_t j = 0; j < i; j++) {
|
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;
|
epoll_event event;
|
||||||
event.events = EPOLLIN | EPOLLWAKEUP;
|
event.events = EPOLLIN | EPOLLWAKEUP;
|
||||||
event.data.u32 = i;
|
event.data.u32 = i;
|
||||||
|
|
||||||
int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
|
int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
|
||||||
if (err < 0) {
|
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;
|
delete ret;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -346,7 +403,7 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
|
|||||||
int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
|
int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
|
||||||
TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
|
TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
ALOGE("timerfd_settime() failed: %s", strerror(errno));
|
ALOGV("timerfd_settime() failed: %s", strerror(errno));
|
||||||
delete ret;
|
delete ret;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -354,6 +411,16 @@ static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
|
|||||||
return reinterpret_cast<jlong>(ret);
|
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)
|
static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
|
||||||
{
|
{
|
||||||
AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
|
AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
|
||||||
|
|||||||
Reference in New Issue
Block a user