summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorGreg Hackmann <ghackmann@google.com>2013-12-17 20:09:09 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2013-12-17 20:09:09 +0000
commit10df052c6a6cf74ef08ed5f28a45aade07b9796d (patch)
treeaaf3a863a22b75a15fc1837875947f25d724d2ac /services
parentbd6877f968a83435e1f59013eb1689e1a3b54a4e (diff)
parentf1bdbdd1bea9662f6731b7a366de1f602f43e5a9 (diff)
downloadframeworks_base-10df052c6a6cf74ef08ed5f28a45aade07b9796d.zip
frameworks_base-10df052c6a6cf74ef08ed5f28a45aade07b9796d.tar.gz
frameworks_base-10df052c6a6cf74ef08ed5f28a45aade07b9796d.tar.bz2
am f1bdbdd1: resolved conflicts for merge of 08579921 to klp-modular-dev
* commit 'f1bdbdd1bea9662f6731b7a366de1f602f43e5a9': Add timerfd backend to AlarmManagerService
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/AlarmManagerService.java28
-rw-r--r--services/jni/com_android_server_AlarmManagerService.cpp235
2 files changed, 235 insertions, 28 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 1fb164d..3cdf170 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -98,7 +98,7 @@ class AlarmManagerService extends SystemService {
final Object mLock = new Object();
- int mDescriptor;
+ long mNativeData;
private long mNextWakeup;
private long mNextNonWakeup;
int mBroadcastRefCount = 0;
@@ -462,7 +462,7 @@ class AlarmManagerService extends SystemService {
@Override
public void onStart() {
- mDescriptor = init();
+ mNativeData = init();
mNextWakeup = mNextNonWakeup = 0;
// We have to set current TimeZone info to kernel
@@ -488,7 +488,7 @@ class AlarmManagerService extends SystemService {
mClockReceiver.scheduleDateChangedEvent();
mUninstallReceiver = new UninstallReceiver();
- if (mDescriptor != -1) {
+ if (mNativeData != 0) {
AlarmThread waitThread = new AlarmThread();
waitThread.start();
} else {
@@ -501,7 +501,7 @@ class AlarmManagerService extends SystemService {
@Override
protected void finalize() throws Throwable {
try {
- close(mDescriptor);
+ close(mNativeData);
} finally {
super.finalize();
}
@@ -529,7 +529,7 @@ class AlarmManagerService extends SystemService {
// 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);
@@ -975,7 +975,7 @@ class AlarmManagerService extends SystemService {
}
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.
long alarmSeconds, alarmNanoseconds;
@@ -987,7 +987,7 @@ class AlarmManagerService extends SystemService {
alarmNanoseconds = (when % 1000) * 1000 * 1000;
}
- set(mDescriptor, type, alarmSeconds, alarmNanoseconds);
+ set(mNativeData, type, alarmSeconds, alarmNanoseconds);
} else {
Message msg = Message.obtain();
msg.what = ALARM_EVENT;
@@ -1031,11 +1031,11 @@ class AlarmManagerService extends SystemService {
}
}
- 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);
void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
// batches are temporally sorted, so we need only pull from the
@@ -1175,7 +1175,7 @@ class AlarmManagerService extends SystemService {
while (true)
{
- int result = waitForAlarm(mDescriptor);
+ int result = waitForAlarm(mNativeData);
triggerList.clear();
@@ -1357,7 +1357,7 @@ class AlarmManagerService extends SystemService {
// 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();
}
}
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index 8da143d..342515b 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -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()
+{
+ 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 jlong init_timerfd()
{
- return open("/dev/alarm", O_RDWR);
+ 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 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, jint fd)
+static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
{
- close(fd);
+ AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
+ delete impl;
}
-static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jint fd, jint type, jlong seconds, jlong nanoseconds)
+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)