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