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