com_android_server_AlarmManagerService.cpp revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
1/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "AlarmManagerService"
19
20#include "JNIHelp.h"
21#include "jni.h"
22#include <utils/Log.h>
23#include <utils/misc.h>
24
25#include <fcntl.h>
26#include <stdio.h>
27#include <string.h>
28#include <sys/epoll.h>
29#include <sys/timerfd.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <arpa/inet.h>
33#include <netinet/in.h>
34#include <stdlib.h>
35#include <errno.h>
36#include <unistd.h>
37#include <linux/ioctl.h>
38#include <linux/android_alarm.h>
39
40namespace android {
41
42static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
43static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
44    CLOCK_REALTIME_ALARM,
45    CLOCK_REALTIME,
46    CLOCK_BOOTTIME_ALARM,
47    CLOCK_BOOTTIME,
48    CLOCK_MONOTONIC,
49    CLOCK_REALTIME,
50};
51/* to match the legacy alarm driver implementation, we need an extra
52   CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */
53
54class AlarmImpl
55{
56public:
57    AlarmImpl(int *fds, size_t n_fds);
58    virtual ~AlarmImpl();
59
60    virtual int set(int type, struct timespec *ts) = 0;
61    virtual int waitForAlarm() = 0;
62
63protected:
64    int *fds;
65    size_t n_fds;
66};
67
68class AlarmImplAlarmDriver : public AlarmImpl
69{
70public:
71    AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }
72
73    int set(int type, struct timespec *ts);
74    int waitForAlarm();
75};
76
77class AlarmImplTimerFd : public AlarmImpl
78{
79public:
80    AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd) :
81        AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd) { }
82    ~AlarmImplTimerFd();
83
84    int set(int type, struct timespec *ts);
85    int waitForAlarm();
86
87private:
88    int epollfd;
89};
90
91AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]),
92        n_fds(n_fds)
93{
94    memcpy(fds, fds_, n_fds * sizeof(fds[0]));
95}
96
97AlarmImpl::~AlarmImpl()
98{
99    for (size_t i = 0; i < n_fds; i++) {
100        close(fds[i]);
101    }
102    delete [] fds;
103}
104
105int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
106{
107    return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
108}
109
110int AlarmImplAlarmDriver::waitForAlarm()
111{
112    return ioctl(fds[0], ANDROID_ALARM_WAIT);
113}
114
115AlarmImplTimerFd::~AlarmImplTimerFd()
116{
117    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
118        epoll_ctl(epollfd, EPOLL_CTL_DEL, fds[i], NULL);
119    }
120    close(epollfd);
121}
122
123int AlarmImplTimerFd::set(int type, struct timespec *ts)
124{
125    if (type > ANDROID_ALARM_TYPE_COUNT) {
126        errno = EINVAL;
127        return -1;
128    }
129
130    if (!ts->tv_nsec && !ts->tv_sec) {
131        ts->tv_nsec = 1;
132    }
133    /* timerfd interprets 0 = disarm, so replace with a practically
134       equivalent deadline of 1 ns */
135
136    struct itimerspec spec;
137    memset(&spec, 0, sizeof(spec));
138    memcpy(&spec.it_value, ts, sizeof(spec.it_value));
139
140    return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
141}
142
143int AlarmImplTimerFd::waitForAlarm()
144{
145    epoll_event events[N_ANDROID_TIMERFDS];
146
147    int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);
148    if (nevents < 0) {
149        return nevents;
150    }
151
152    int result = 0;
153    for (int i = 0; i < nevents; i++) {
154        uint32_t alarm_idx = events[i].data.u32;
155        uint64_t unused;
156        ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
157        if (err < 0) {
158            if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
159                result |= ANDROID_ALARM_TIME_CHANGE_MASK;
160            } else {
161                return err;
162            }
163        } else {
164            result |= (1 << alarm_idx);
165        }
166    }
167
168    return result;
169}
170
171static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
172{
173    struct timezone tz;
174
175    tz.tz_minuteswest = minswest;
176    tz.tz_dsttime = 0;
177
178    int result = settimeofday(NULL, &tz);
179    if (result < 0) {
180        ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
181        return -1;
182    } else {
183        ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
184    }
185
186    return 0;
187}
188
189static jlong init_alarm_driver()
190{
191    int fd = open("/dev/alarm", O_RDWR);
192    if (fd < 0) {
193        ALOGV("opening alarm driver failed: %s", strerror(errno));
194        return 0;
195    }
196
197    AlarmImpl *ret = new AlarmImplAlarmDriver(fd);
198    return reinterpret_cast<jlong>(ret);
199}
200
201static jlong init_timerfd()
202{
203    int epollfd;
204    int fds[N_ANDROID_TIMERFDS];
205
206    epollfd = epoll_create(N_ANDROID_TIMERFDS);
207    if (epollfd < 0) {
208        ALOGV("epoll_create(%u) failed: %s", N_ANDROID_TIMERFDS,
209                strerror(errno));
210        return 0;
211    }
212
213    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
214        fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
215        if (fds[i] < 0) {
216            ALOGV("timerfd_create(%u) failed: %s",  android_alarm_to_clockid[i],
217                    strerror(errno));
218            close(epollfd);
219            for (size_t j = 0; j < i; j++) {
220                close(fds[j]);
221            }
222            return 0;
223        }
224    }
225
226    AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd);
227
228    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
229        epoll_event event;
230        event.events = EPOLLIN | EPOLLWAKEUP;
231        event.data.u32 = i;
232
233        int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
234        if (err < 0) {
235            ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
236            delete ret;
237            return 0;
238        }
239    }
240
241    struct itimerspec spec;
242    memset(&spec, 0, sizeof(spec));
243    /* 0 = disarmed; the timerfd doesn't need to be armed to get
244       RTC change notifications, just set up as cancelable */
245
246    int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
247            TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
248    if (err < 0) {
249        ALOGV("timerfd_settime() failed: %s", strerror(errno));
250        delete ret;
251        return 0;
252    }
253
254    return reinterpret_cast<jlong>(ret);
255}
256
257static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
258{
259    jlong ret = init_alarm_driver();
260    if (ret) {
261        return ret;
262    }
263
264    return init_timerfd();
265}
266
267static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
268{
269    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
270    delete impl;
271}
272
273static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
274{
275    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
276    struct timespec ts;
277    ts.tv_sec = seconds;
278    ts.tv_nsec = nanoseconds;
279
280    int result = impl->set(type, &ts);
281    if (result < 0)
282    {
283        ALOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
284    }
285}
286
287static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
288{
289    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
290    int result = 0;
291
292    do
293    {
294        result = impl->waitForAlarm();
295    } while (result < 0 && errno == EINTR);
296
297    if (result < 0)
298    {
299        ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
300        return 0;
301    }
302
303    return result;
304}
305
306static JNINativeMethod sMethods[] = {
307     /* name, signature, funcPtr */
308    {"init", "()J", (void*)android_server_AlarmManagerService_init},
309    {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
310    {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
311    {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
312    {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
313};
314
315int register_android_server_AlarmManagerService(JNIEnv* env)
316{
317    return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
318                                    sMethods, NELEM(sMethods));
319}
320
321} /* namespace android */
322