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