* commit '060ae1db7bba39cb8171f4267b5de9538f1ab440': Add timerfd backend to AlarmManagerService
This commit is contained in:
@@ -99,7 +99,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
|
||||
private Object mLock = new Object();
|
||||
|
||||
private int mDescriptor;
|
||||
private long mNativeData;
|
||||
private long mNextWakeup;
|
||||
private long mNextNonWakeup;
|
||||
private int mBroadcastRefCount = 0;
|
||||
@@ -464,7 +464,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
|
||||
public AlarmManagerService(Context context) {
|
||||
mContext = context;
|
||||
mDescriptor = init();
|
||||
mNativeData = init();
|
||||
mNextWakeup = mNextNonWakeup = 0;
|
||||
|
||||
// We have to set current TimeZone info to kernel
|
||||
@@ -493,7 +493,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
mClockReceiver.scheduleDateChangedEvent();
|
||||
mUninstallReceiver = new UninstallReceiver();
|
||||
|
||||
if (mDescriptor != -1) {
|
||||
if (mNativeData != 0) {
|
||||
mWaitThread.start();
|
||||
} else {
|
||||
Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
|
||||
@@ -502,7 +502,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
close(mDescriptor);
|
||||
close(mNativeData);
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
@@ -702,7 +702,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
// Update the kernel timezone information
|
||||
// Kernel tracks time offsets as 'minutes west of GMT'
|
||||
int gmtOffset = zone.getOffset(System.currentTimeMillis());
|
||||
setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
|
||||
setKernelTimezone(mNativeData, -(gmtOffset / 60000));
|
||||
}
|
||||
|
||||
TimeZone.setDefault(null);
|
||||
@@ -796,7 +796,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
|
||||
private void setLocked(int type, long when)
|
||||
{
|
||||
if (mDescriptor != -1)
|
||||
if (mNativeData != 0)
|
||||
{
|
||||
// The kernel never triggers alarms with negative wakeup times
|
||||
// so we ensure they are positive.
|
||||
@@ -809,7 +809,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
alarmNanoseconds = (when % 1000) * 1000 * 1000;
|
||||
}
|
||||
|
||||
set(mDescriptor, type, alarmSeconds, alarmNanoseconds);
|
||||
set(mNativeData, type, alarmSeconds, alarmNanoseconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1014,11 +1014,11 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private native int init();
|
||||
private native void close(int fd);
|
||||
private native void set(int fd, int type, long seconds, long nanoseconds);
|
||||
private native int waitForAlarm(int fd);
|
||||
private native int setKernelTimezone(int fd, int minuteswest);
|
||||
private native long init();
|
||||
private native void close(long nativeData);
|
||||
private native void set(long nativeData, int type, long seconds, long nanoseconds);
|
||||
private native int waitForAlarm(long nativeData);
|
||||
private native int setKernelTimezone(long nativeData, int minuteswest);
|
||||
|
||||
private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
|
||||
// batches are temporally sorted, so we need only pull from the
|
||||
@@ -1158,7 +1158,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
|
||||
while (true)
|
||||
{
|
||||
int result = waitForAlarm(mDescriptor);
|
||||
int result = waitForAlarm(mNativeData);
|
||||
|
||||
triggerList.clear();
|
||||
|
||||
@@ -1340,7 +1340,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
|
||||
// daylight savings information.
|
||||
TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
|
||||
int gmtOffset = zone.getOffset(System.currentTimeMillis());
|
||||
setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
|
||||
setKernelTimezone(mNativeData, -(gmtOffset / 60000));
|
||||
scheduleDateChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -37,7 +39,136 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jint, jint minswest)
|
||||
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,
|
||||
CLOCK_REALTIME,
|
||||
CLOCK_BOOTTIME_ALARM,
|
||||
CLOCK_BOOTTIME,
|
||||
CLOCK_MONOTONIC,
|
||||
CLOCK_REALTIME,
|
||||
};
|
||||
/* 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(int *fds, size_t n_fds);
|
||||
virtual ~AlarmImpl();
|
||||
|
||||
virtual int set(int type, struct timespec *ts) = 0;
|
||||
virtual int waitForAlarm() = 0;
|
||||
|
||||
protected:
|
||||
int *fds;
|
||||
size_t n_fds;
|
||||
};
|
||||
|
||||
class AlarmImplAlarmDriver : public AlarmImpl
|
||||
{
|
||||
public:
|
||||
AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }
|
||||
|
||||
int set(int type, struct timespec *ts);
|
||||
int waitForAlarm();
|
||||
};
|
||||
|
||||
class AlarmImplTimerFd : public AlarmImpl
|
||||
{
|
||||
public:
|
||||
AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd) :
|
||||
AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd) { }
|
||||
~AlarmImplTimerFd();
|
||||
|
||||
int set(int type, struct timespec *ts);
|
||||
int waitForAlarm();
|
||||
|
||||
private:
|
||||
int epollfd;
|
||||
};
|
||||
|
||||
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 (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::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 AlarmImplTimerFd::set(int type, struct timespec *ts)
|
||||
{
|
||||
if (type > ANDROID_ALARM_TYPE_COUNT) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ts->tv_nsec && !ts->tv_sec) {
|
||||
ts->tv_nsec = 1;
|
||||
}
|
||||
/* timerfd interprets 0 = disarm, so replace with a practically
|
||||
equivalent deadline of 1 ns */
|
||||
|
||||
struct itimerspec spec;
|
||||
memset(&spec, 0, sizeof(spec));
|
||||
memcpy(&spec.it_value, ts, sizeof(spec.it_value));
|
||||
|
||||
return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
|
||||
}
|
||||
|
||||
int AlarmImplTimerFd::waitForAlarm()
|
||||
{
|
||||
epoll_event events[N_ANDROID_TIMERFDS];
|
||||
|
||||
int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);
|
||||
if (nevents < 0) {
|
||||
return nevents;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < nevents; i++) {
|
||||
uint32_t alarm_idx = events[i].data.u32;
|
||||
uint64_t unused;
|
||||
ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
|
||||
if (err < 0) {
|
||||
if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
|
||||
result |= ANDROID_ALARM_TIME_CHANGE_MASK;
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
result |= (1 << alarm_idx);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
|
||||
{
|
||||
struct timezone tz;
|
||||
|
||||
@@ -55,36 +186,112 @@ static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobjec
|
||||
return 0;
|
||||
}
|
||||
|
||||
static jint android_server_AlarmManagerService_init(JNIEnv*, jobject)
|
||||
static jlong init_alarm_driver()
|
||||
{
|
||||
return open("/dev/alarm", O_RDWR);
|
||||
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 void android_server_AlarmManagerService_close(JNIEnv*, jobject, jint fd)
|
||||
static jlong init_timerfd()
|
||||
{
|
||||
close(fd);
|
||||
int epollfd;
|
||||
int fds[N_ANDROID_TIMERFDS];
|
||||
|
||||
epollfd = epoll_create(N_ANDROID_TIMERFDS);
|
||||
if (epollfd < 0) {
|
||||
ALOGV("epoll_create(%u) failed: %s", N_ANDROID_TIMERFDS,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
|
||||
fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
|
||||
if (fds[i] < 0) {
|
||||
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]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd);
|
||||
|
||||
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) {
|
||||
ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
|
||||
delete ret;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct itimerspec spec;
|
||||
memset(&spec, 0, sizeof(spec));
|
||||
/* 0 = disarmed; the timerfd doesn't need to be armed to get
|
||||
RTC change notifications, just set up as cancelable */
|
||||
|
||||
int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
|
||||
TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
|
||||
if (err < 0) {
|
||||
ALOGV("timerfd_settime() failed: %s", strerror(errno));
|
||||
delete ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return reinterpret_cast<jlong>(ret);
|
||||
}
|
||||
|
||||
static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jint fd, jint type, jlong seconds, jlong nanoseconds)
|
||||
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);
|
||||
delete impl;
|
||||
}
|
||||
|
||||
static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
|
||||
{
|
||||
AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
|
||||
struct timespec ts;
|
||||
ts.tv_sec = seconds;
|
||||
ts.tv_nsec = nanoseconds;
|
||||
|
||||
int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
|
||||
int result = impl->set(type, &ts);
|
||||
if (result < 0)
|
||||
{
|
||||
ALOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jint fd)
|
||||
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
|
||||
{
|
||||
AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
|
||||
int result = 0;
|
||||
|
||||
do
|
||||
{
|
||||
result = ioctl(fd, ANDROID_ALARM_WAIT);
|
||||
result = impl->waitForAlarm();
|
||||
} while (result < 0 && errno == EINTR);
|
||||
|
||||
if (result < 0)
|
||||
@@ -98,11 +305,11 @@ static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, ji
|
||||
|
||||
static JNINativeMethod sMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"init", "()I", (void*)android_server_AlarmManagerService_init},
|
||||
{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
|
||||
{"set", "(IIJJ)V", (void*)android_server_AlarmManagerService_set},
|
||||
{"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
|
||||
{"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
|
||||
{"init", "()J", (void*)android_server_AlarmManagerService_init},
|
||||
{"close", "(J)V", (void*)android_server_AlarmManagerService_close},
|
||||
{"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
|
||||
{"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
|
||||
{"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
|
||||
};
|
||||
|
||||
int register_android_server_AlarmManagerService(JNIEnv* env)
|
||||
|
||||
Reference in New Issue
Block a user