blob: 5cbb277a2f12642bc5275ca0daec974d0b110cf8 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
Elliott Hughesdd66bcb2011-04-12 11:28:59 -07005** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008**
Elliott Hughesdd66bcb2011-04-12 11:28:59 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010**
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070011** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
18#define LOG_TAG "AlarmManagerService"
19
20#include "JNIHelp.h"
21#include "jni.h"
Mathias Agopian25ba5b62009-05-18 15:08:03 -070022#include <utils/Log.h>
23#include <utils/misc.h>
Greg Hackmann0eb58262014-02-26 12:22:13 -080024#include <utils/String8.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
Greg Hackmann0eb58262014-02-26 12:22:13 -080026#include <dirent.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027#include <fcntl.h>
28#include <stdio.h>
29#include <string.h>
Greg Hackmanna1d6f922013-12-09 16:56:53 -080030#include <sys/epoll.h>
31#include <sys/timerfd.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032#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>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039#include <linux/ioctl.h>
40#include <linux/android_alarm.h>
Greg Hackmann38bf5142014-02-19 16:39:36 -080041#include <linux/rtc.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043namespace android {
44
Greg Hackmanna1d6f922013-12-09 16:56:53 -080045static 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;
Greg Hackmann38bf5142014-02-19 16:39:36 -080064 virtual int setTime(struct timeval *tv) = 0;
Greg Hackmanna1d6f922013-12-09 16:56:53 -080065 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);
Greg Hackmann38bf5142014-02-19 16:39:36 -080078 int setTime(struct timeval *tv);
Greg Hackmanna1d6f922013-12-09 16:56:53 -080079 int waitForAlarm();
80};
81
82class AlarmImplTimerFd : public AlarmImpl
83{
84public:
Greg Hackmann0eb58262014-02-26 12:22:13 -080085 AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) :
86 AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { }
Greg Hackmanna1d6f922013-12-09 16:56:53 -080087 ~AlarmImplTimerFd();
88
89 int set(int type, struct timespec *ts);
Greg Hackmann38bf5142014-02-19 16:39:36 -080090 int setTime(struct timeval *tv);
Greg Hackmanna1d6f922013-12-09 16:56:53 -080091 int waitForAlarm();
92
93private:
94 int epollfd;
Greg Hackmann0eb58262014-02-26 12:22:13 -080095 int rtc_id;
Greg Hackmanna1d6f922013-12-09 16:56:53 -080096};
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
Greg Hackmann38bf5142014-02-19 16:39:36 -0800117int 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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800130int 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
Greg Hackmann38bf5142014-02-19 16:39:36 -0800163int AlarmImplTimerFd::setTime(struct timeval *tv)
164{
165 struct rtc_time rtc;
166 struct tm tm, *gmtime_res;
167 int fd;
168 int res;
169
Greg Hackmann38bf5142014-02-19 16:39:36 -0800170 res = settimeofday(tv, NULL);
171 if (res < 0) {
172 ALOGV("settimeofday() failed: %s\n", strerror(errno));
Greg Hackmannc9244722014-01-27 16:30:09 -0800173 return -1;
174 }
175
Greg Hackmann0eb58262014-02-26 12:22:13 -0800176 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);
Greg Hackmannc9244722014-01-27 16:30:09 -0800184 if (fd < 0) {
Greg Hackmann0eb58262014-02-26 12:22:13 -0800185 ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
Greg Hackmannc9244722014-01-27 16:30:09 -0800186 return res;
Greg Hackmann38bf5142014-02-19 16:39:36 -0800187 }
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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800214int 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
Greg Hackmann38bf5142014-02-19 16:39:36 -0800242static 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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800266static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 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) {
Steve Block3762c312012-01-06 19:20:56 +0000275 ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 return -1;
277 } else {
Steve Block5baa3a62011-12-20 16:23:08 +0000278 ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 }
280
281 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282}
283
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800284static jlong init_alarm_driver()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800286 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294}
295
Greg Hackmann0eb58262014-02-26 12:22:13 -0800296static 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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800356static jlong init_timerfd()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800358 int epollfd;
359 int fds[N_ANDROID_TIMERFDS];
360
361 epollfd = epoll_create(N_ANDROID_TIMERFDS);
362 if (epollfd < 0) {
Bernhard Rosenkränzer46c82b42014-11-30 11:04:10 +0100363 ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS,
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800364 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
Greg Hackmann0eb58262014-02-26 12:22:13 -0800381 AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc());
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800382
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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410}
411
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800412static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800414 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 struct timespec ts;
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700432 ts.tv_sec = seconds;
433 ts.tv_nsec = nanoseconds;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700434
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800435 int result = impl->set(type, &ts);
Greg Hackmann32b4c072013-12-06 10:52:09 -0800436 if (result < 0)
437 {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000438 ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
439 static_cast<long long>(seconds),
440 static_cast<long long>(nanoseconds), strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442}
443
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800444static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800446 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
Greg Hackmann32b4c072013-12-06 10:52:09 -0800447 int result = 0;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700448
Greg Hackmann32b4c072013-12-06 10:52:09 -0800449 do
450 {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800451 result = impl->waitForAlarm();
Greg Hackmann32b4c072013-12-06 10:52:09 -0800452 } while (result < 0 && errno == EINTR);
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700453
Greg Hackmann32b4c072013-12-06 10:52:09 -0800454 if (result < 0)
455 {
Steve Block3762c312012-01-06 19:20:56 +0000456 ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 return 0;
458 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461}
462
Daniel Micay76f6a862015-09-19 17:31:01 -0400463static const JNINativeMethod sMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 /* name, signature, funcPtr */
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800465 {"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},
Greg Hackmann38bf5142014-02-19 16:39:36 -0800469 {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800470 {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471};
472
473int register_android_server_AlarmManagerService(JNIEnv* env)
474{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
476 sMethods, NELEM(sMethods));
477}
478
479} /* namespace android */