com_android_server_AlarmManagerService.cpp revision 76f6a86de25e1bf74717e047e55fd44b089673f3
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#include <utils/String8.h>
25
26#include <dirent.h>
27#include <fcntl.h>
28#include <stdio.h>
29#include <string.h>
30#include <sys/epoll.h>
31#include <sys/timerfd.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <arpa/inet.h>
35#include <netinet/in.h>
36#include <stdlib.h>
37#include <errno.h>
38#include <unistd.h>
39#include <linux/ioctl.h>
40#include <linux/android_alarm.h>
41#include <linux/rtc.h>
42
43namespace android {
44
45static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
46static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
47    CLOCK_REALTIME_ALARM,
48    CLOCK_REALTIME,
49    CLOCK_BOOTTIME_ALARM,
50    CLOCK_BOOTTIME,
51    CLOCK_MONOTONIC,
52    CLOCK_REALTIME,
53};
54/* to match the legacy alarm driver implementation, we need an extra
55   CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */
56
57class AlarmImpl
58{
59public:
60    AlarmImpl(int *fds, size_t n_fds);
61    virtual ~AlarmImpl();
62
63    virtual int set(int type, struct timespec *ts) = 0;
64    virtual int setTime(struct timeval *tv) = 0;
65    virtual int waitForAlarm() = 0;
66
67protected:
68    int *fds;
69    size_t n_fds;
70};
71
72class AlarmImplAlarmDriver : public AlarmImpl
73{
74public:
75    AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }
76
77    int set(int type, struct timespec *ts);
78    int setTime(struct timeval *tv);
79    int waitForAlarm();
80};
81
82class AlarmImplTimerFd : public AlarmImpl
83{
84public:
85    AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) :
86        AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { }
87    ~AlarmImplTimerFd();
88
89    int set(int type, struct timespec *ts);
90    int setTime(struct timeval *tv);
91    int waitForAlarm();
92
93private:
94    int epollfd;
95    int rtc_id;
96};
97
98AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]),
99        n_fds(n_fds)
100{
101    memcpy(fds, fds_, n_fds * sizeof(fds[0]));
102}
103
104AlarmImpl::~AlarmImpl()
105{
106    for (size_t i = 0; i < n_fds; i++) {
107        close(fds[i]);
108    }
109    delete [] fds;
110}
111
112int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
113{
114    return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
115}
116
117int AlarmImplAlarmDriver::setTime(struct timeval *tv)
118{
119    struct timespec ts;
120    int res;
121
122    ts.tv_sec = tv->tv_sec;
123    ts.tv_nsec = tv->tv_usec * 1000;
124    res = ioctl(fds[0], ANDROID_ALARM_SET_RTC, &ts);
125    if (res < 0)
126        ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno));
127    return res;
128}
129
130int AlarmImplAlarmDriver::waitForAlarm()
131{
132    return ioctl(fds[0], ANDROID_ALARM_WAIT);
133}
134
135AlarmImplTimerFd::~AlarmImplTimerFd()
136{
137    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
138        epoll_ctl(epollfd, EPOLL_CTL_DEL, fds[i], NULL);
139    }
140    close(epollfd);
141}
142
143int AlarmImplTimerFd::set(int type, struct timespec *ts)
144{
145    if (type > ANDROID_ALARM_TYPE_COUNT) {
146        errno = EINVAL;
147        return -1;
148    }
149
150    if (!ts->tv_nsec && !ts->tv_sec) {
151        ts->tv_nsec = 1;
152    }
153    /* timerfd interprets 0 = disarm, so replace with a practically
154       equivalent deadline of 1 ns */
155
156    struct itimerspec spec;
157    memset(&spec, 0, sizeof(spec));
158    memcpy(&spec.it_value, ts, sizeof(spec.it_value));
159
160    return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
161}
162
163int AlarmImplTimerFd::setTime(struct timeval *tv)
164{
165    struct rtc_time rtc;
166    struct tm tm, *gmtime_res;
167    int fd;
168    int res;
169
170    res = settimeofday(tv, NULL);
171    if (res < 0) {
172        ALOGV("settimeofday() failed: %s\n", strerror(errno));
173        return -1;
174    }
175
176    if (rtc_id < 0) {
177        ALOGV("Not setting RTC because wall clock RTC was not found");
178        errno = ENODEV;
179        return -1;
180    }
181
182    android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
183    fd = open(rtc_dev.string(), O_RDWR);
184    if (fd < 0) {
185        ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
186        return res;
187    }
188
189    gmtime_res = gmtime_r(&tv->tv_sec, &tm);
190    if (!gmtime_res) {
191        ALOGV("gmtime_r() failed: %s\n", strerror(errno));
192        res = -1;
193        goto done;
194    }
195
196    memset(&rtc, 0, sizeof(rtc));
197    rtc.tm_sec = tm.tm_sec;
198    rtc.tm_min = tm.tm_min;
199    rtc.tm_hour = tm.tm_hour;
200    rtc.tm_mday = tm.tm_mday;
201    rtc.tm_mon = tm.tm_mon;
202    rtc.tm_year = tm.tm_year;
203    rtc.tm_wday = tm.tm_wday;
204    rtc.tm_yday = tm.tm_yday;
205    rtc.tm_isdst = tm.tm_isdst;
206    res = ioctl(fd, RTC_SET_TIME, &rtc);
207    if (res < 0)
208        ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
209done:
210    close(fd);
211    return res;
212}
213
214int AlarmImplTimerFd::waitForAlarm()
215{
216    epoll_event events[N_ANDROID_TIMERFDS];
217
218    int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);
219    if (nevents < 0) {
220        return nevents;
221    }
222
223    int result = 0;
224    for (int i = 0; i < nevents; i++) {
225        uint32_t alarm_idx = events[i].data.u32;
226        uint64_t unused;
227        ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
228        if (err < 0) {
229            if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
230                result |= ANDROID_ALARM_TIME_CHANGE_MASK;
231            } else {
232                return err;
233            }
234        } else {
235            result |= (1 << alarm_idx);
236        }
237    }
238
239    return result;
240}
241
242static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
243{
244    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
245    struct timeval tv;
246    int ret;
247
248    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
249        return -1;
250    }
251
252    tv.tv_sec = (time_t) (millis / 1000LL);
253    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
254
255    ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
256
257    ret = impl->setTime(&tv);
258
259    if(ret < 0) {
260        ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
261        ret = -1;
262    }
263    return ret;
264}
265
266static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
267{
268    struct timezone tz;
269
270    tz.tz_minuteswest = minswest;
271    tz.tz_dsttime = 0;
272
273    int result = settimeofday(NULL, &tz);
274    if (result < 0) {
275        ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
276        return -1;
277    } else {
278        ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
279    }
280
281    return 0;
282}
283
284static jlong init_alarm_driver()
285{
286    int fd = open("/dev/alarm", O_RDWR);
287    if (fd < 0) {
288        ALOGV("opening alarm driver failed: %s", strerror(errno));
289        return 0;
290    }
291
292    AlarmImpl *ret = new AlarmImplAlarmDriver(fd);
293    return reinterpret_cast<jlong>(ret);
294}
295
296static const char rtc_sysfs[] = "/sys/class/rtc";
297
298static bool rtc_is_hctosys(unsigned int rtc_id)
299{
300    android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
301            rtc_sysfs, rtc_id);
302
303    FILE *file = fopen(hctosys_path.string(), "re");
304    if (!file) {
305        ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
306        return false;
307    }
308
309    unsigned int hctosys;
310    bool ret = false;
311    int err = fscanf(file, "%u", &hctosys);
312    if (err == EOF)
313        ALOGE("failed to read from %s: %s", hctosys_path.string(),
314                strerror(errno));
315    else if (err == 0)
316        ALOGE("%s did not have expected contents", hctosys_path.string());
317    else
318        ret = hctosys;
319
320    fclose(file);
321    return ret;
322}
323
324static int wall_clock_rtc()
325{
326    DIR *dir = opendir(rtc_sysfs);
327    if (!dir) {
328        ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
329        return -1;
330    }
331
332    struct dirent *dirent;
333    while (errno = 0, dirent = readdir(dir)) {
334        unsigned int rtc_id;
335        int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id);
336
337        if (matched < 0)
338            break;
339        else if (matched != 1)
340            continue;
341
342        if (rtc_is_hctosys(rtc_id)) {
343            ALOGV("found wall clock RTC %u", rtc_id);
344            return rtc_id;
345        }
346    }
347
348    if (errno == 0)
349        ALOGW("no wall clock RTC found");
350    else
351        ALOGE("failed to enumerate RTCs: %s", strerror(errno));
352
353    return -1;
354}
355
356static jlong init_timerfd()
357{
358    int epollfd;
359    int fds[N_ANDROID_TIMERFDS];
360
361    epollfd = epoll_create(N_ANDROID_TIMERFDS);
362    if (epollfd < 0) {
363        ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS,
364                strerror(errno));
365        return 0;
366    }
367
368    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
369        fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
370        if (fds[i] < 0) {
371            ALOGV("timerfd_create(%u) failed: %s",  android_alarm_to_clockid[i],
372                    strerror(errno));
373            close(epollfd);
374            for (size_t j = 0; j < i; j++) {
375                close(fds[j]);
376            }
377            return 0;
378        }
379    }
380
381    AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc());
382
383    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
384        epoll_event event;
385        event.events = EPOLLIN | EPOLLWAKEUP;
386        event.data.u32 = i;
387
388        int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
389        if (err < 0) {
390            ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
391            delete ret;
392            return 0;
393        }
394    }
395
396    struct itimerspec spec;
397    memset(&spec, 0, sizeof(spec));
398    /* 0 = disarmed; the timerfd doesn't need to be armed to get
399       RTC change notifications, just set up as cancelable */
400
401    int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
402            TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
403    if (err < 0) {
404        ALOGV("timerfd_settime() failed: %s", strerror(errno));
405        delete ret;
406        return 0;
407    }
408
409    return reinterpret_cast<jlong>(ret);
410}
411
412static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
413{
414    jlong ret = init_alarm_driver();
415    if (ret) {
416        return ret;
417    }
418
419    return init_timerfd();
420}
421
422static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
423{
424    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
425    delete impl;
426}
427
428static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
429{
430    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
431    struct timespec ts;
432    ts.tv_sec = seconds;
433    ts.tv_nsec = nanoseconds;
434
435    int result = impl->set(type, &ts);
436    if (result < 0)
437    {
438        ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
439              static_cast<long long>(seconds),
440              static_cast<long long>(nanoseconds), strerror(errno));
441    }
442}
443
444static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
445{
446    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
447    int result = 0;
448
449    do
450    {
451        result = impl->waitForAlarm();
452    } while (result < 0 && errno == EINTR);
453
454    if (result < 0)
455    {
456        ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
457        return 0;
458    }
459
460    return result;
461}
462
463static const JNINativeMethod sMethods[] = {
464     /* name, signature, funcPtr */
465    {"init", "()J", (void*)android_server_AlarmManagerService_init},
466    {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
467    {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
468    {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
469    {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
470    {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
471};
472
473int register_android_server_AlarmManagerService(JNIEnv* env)
474{
475    return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
476                                    sMethods, NELEM(sMethods));
477}
478
479} /* namespace android */
480