blob: 246ab0d259f4e64027eb83b4be8805802bcdc226 [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
Mykola Kondratenkoe45abfa2016-01-18 12:43:30 +010043#include <memory>
44
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045namespace android {
46
Greg Hackmanna1d6f922013-12-09 16:56:53 -080047static 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;
Greg Hackmann38bf5142014-02-19 16:39:36 -080066 virtual int setTime(struct timeval *tv) = 0;
Greg Hackmanna1d6f922013-12-09 16:56:53 -080067 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);
Greg Hackmann38bf5142014-02-19 16:39:36 -080080 int setTime(struct timeval *tv);
Greg Hackmanna1d6f922013-12-09 16:56:53 -080081 int waitForAlarm();
82};
83
84class AlarmImplTimerFd : public AlarmImpl
85{
86public:
Greg Hackmann0eb58262014-02-26 12:22:13 -080087 AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) :
88 AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { }
Greg Hackmanna1d6f922013-12-09 16:56:53 -080089 ~AlarmImplTimerFd();
90
91 int set(int type, struct timespec *ts);
Greg Hackmann38bf5142014-02-19 16:39:36 -080092 int setTime(struct timeval *tv);
Greg Hackmanna1d6f922013-12-09 16:56:53 -080093 int waitForAlarm();
94
95private:
96 int epollfd;
Greg Hackmann0eb58262014-02-26 12:22:13 -080097 int rtc_id;
Greg Hackmanna1d6f922013-12-09 16:56:53 -080098};
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
Greg Hackmann38bf5142014-02-19 16:39:36 -0800119int 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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800132int 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
Greg Hackmann38bf5142014-02-19 16:39:36 -0800165int AlarmImplTimerFd::setTime(struct timeval *tv)
166{
167 struct rtc_time rtc;
168 struct tm tm, *gmtime_res;
169 int fd;
170 int res;
171
Greg Hackmann38bf5142014-02-19 16:39:36 -0800172 res = settimeofday(tv, NULL);
173 if (res < 0) {
174 ALOGV("settimeofday() failed: %s\n", strerror(errno));
Greg Hackmannc9244722014-01-27 16:30:09 -0800175 return -1;
176 }
177
Greg Hackmann0eb58262014-02-26 12:22:13 -0800178 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);
Greg Hackmannc9244722014-01-27 16:30:09 -0800186 if (fd < 0) {
Greg Hackmann0eb58262014-02-26 12:22:13 -0800187 ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
Greg Hackmannc9244722014-01-27 16:30:09 -0800188 return res;
Greg Hackmann38bf5142014-02-19 16:39:36 -0800189 }
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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800216int 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
Greg Hackmann38bf5142014-02-19 16:39:36 -0800244static 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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800268static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 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) {
Steve Block3762c312012-01-06 19:20:56 +0000277 ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 return -1;
279 } else {
Steve Block5baa3a62011-12-20 16:23:08 +0000280 ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 }
282
283 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284}
285
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800286static jlong init_alarm_driver()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800288 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296}
297
Greg Hackmann0eb58262014-02-26 12:22:13 -0800298static 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{
Mykola Kondratenkoe45abfa2016-01-18 12:43:30 +0100328 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(rtc_sysfs), closedir);
329 if (!dir.get()) {
Greg Hackmann0eb58262014-02-26 12:22:13 -0800330 ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
331 return -1;
332 }
333
334 struct dirent *dirent;
Mykola Kondratenkoe45abfa2016-01-18 12:43:30 +0100335 while (errno = 0, dirent = readdir(dir.get())) {
Greg Hackmann0eb58262014-02-26 12:22:13 -0800336 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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800358static jlong init_timerfd()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800360 int epollfd;
361 int fds[N_ANDROID_TIMERFDS];
362
363 epollfd = epoll_create(N_ANDROID_TIMERFDS);
364 if (epollfd < 0) {
Bernhard Rosenkränzer46c82b42014-11-30 11:04:10 +0100365 ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS,
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800366 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
Greg Hackmann0eb58262014-02-26 12:22:13 -0800383 AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc());
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800384
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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412}
413
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800414static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800416 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 struct timespec ts;
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700434 ts.tv_sec = seconds;
435 ts.tv_nsec = nanoseconds;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700436
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800437 int result = impl->set(type, &ts);
Greg Hackmann32b4c072013-12-06 10:52:09 -0800438 if (result < 0)
439 {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000440 ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
441 static_cast<long long>(seconds),
442 static_cast<long long>(nanoseconds), strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444}
445
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800446static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800448 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
Greg Hackmann32b4c072013-12-06 10:52:09 -0800449 int result = 0;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700450
Greg Hackmann32b4c072013-12-06 10:52:09 -0800451 do
452 {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800453 result = impl->waitForAlarm();
Greg Hackmann32b4c072013-12-06 10:52:09 -0800454 } while (result < 0 && errno == EINTR);
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700455
Greg Hackmann32b4c072013-12-06 10:52:09 -0800456 if (result < 0)
457 {
Steve Block3762c312012-01-06 19:20:56 +0000458 ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 return 0;
460 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463}
464
Daniel Micay76f6a862015-09-19 17:31:01 -0400465static const JNINativeMethod sMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 /* name, signature, funcPtr */
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800467 {"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},
Greg Hackmann38bf5142014-02-19 16:39:36 -0800471 {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800472 {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473};
474
475int register_android_server_AlarmManagerService(JNIEnv* env)
476{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
478 sMethods, NELEM(sMethods));
479}
480
481} /* namespace android */