blob: 3a0273d8c3c8cc53c4cc2393d550f78ab5e6a130 [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>
Greg Hackmann38bf5142014-02-19 16:39:36 -080040#include <linux/rtc.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
Greg Hackmannd7151c02016-04-25 13:30:34 -070042#include <array>
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 Hackmannd7151c02016-04-25 13:30:34 -070047static 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;
Greg Hackmanna1d6f922013-12-09 16:56:53 -080062static 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};
Greg Hackmannd7151c02016-04-25 13:30:34 -070071
72typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
Greg Hackmanna1d6f922013-12-09 16:56:53 -080073
74class AlarmImpl
75{
76public:
Greg Hackmannd7151c02016-04-25 13:30:34 -070077 AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) :
78 fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { }
79 ~AlarmImpl();
Greg Hackmanna1d6f922013-12-09 16:56:53 -080080
81 int set(int type, struct timespec *ts);
Greg Hackmann38bf5142014-02-19 16:39:36 -080082 int setTime(struct timeval *tv);
Greg Hackmanna1d6f922013-12-09 16:56:53 -080083 int waitForAlarm();
84
85private:
Greg Hackmannd7151c02016-04-25 13:30:34 -070086 const TimerFds fds;
87 const int epollfd;
88 const int rtc_id;
Greg Hackmanna1d6f922013-12-09 16:56:53 -080089};
90
Greg Hackmanna1d6f922013-12-09 16:56:53 -080091AlarmImpl::~AlarmImpl()
92{
Greg Hackmannd7151c02016-04-25 13:30:34 -070093 for (auto fd : fds) {
94 epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr);
95 close(fd);
Greg Hackmanna1d6f922013-12-09 16:56:53 -080096 }
Greg Hackmanna1d6f922013-12-09 16:56:53 -080097
Greg Hackmanna1d6f922013-12-09 16:56:53 -080098 close(epollfd);
99}
100
Greg Hackmannd7151c02016-04-25 13:30:34 -0700101int AlarmImpl::set(int type, struct timespec *ts)
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800102{
Greg Hackmannd7151c02016-04-25 13:30:34 -0700103 if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800104 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
Greg Hackmannd7151c02016-04-25 13:30:34 -0700121int AlarmImpl::setTime(struct timeval *tv)
Greg Hackmann38bf5142014-02-19 16:39:36 -0800122{
123 struct rtc_time rtc;
124 struct tm tm, *gmtime_res;
125 int fd;
126 int res;
127
Greg Hackmann38bf5142014-02-19 16:39:36 -0800128 res = settimeofday(tv, NULL);
129 if (res < 0) {
130 ALOGV("settimeofday() failed: %s\n", strerror(errno));
Greg Hackmannc9244722014-01-27 16:30:09 -0800131 return -1;
132 }
133
Greg Hackmann0eb58262014-02-26 12:22:13 -0800134 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);
Greg Hackmannc9244722014-01-27 16:30:09 -0800142 if (fd < 0) {
Greg Hackmann0eb58262014-02-26 12:22:13 -0800143 ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
Greg Hackmannc9244722014-01-27 16:30:09 -0800144 return res;
Greg Hackmann38bf5142014-02-19 16:39:36 -0800145 }
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
Greg Hackmannd7151c02016-04-25 13:30:34 -0700172int AlarmImpl::waitForAlarm()
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800173{
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
Greg Hackmann38bf5142014-02-19 16:39:36 -0800200static 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
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800224static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 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) {
Steve Block3762c312012-01-06 19:20:56 +0000233 ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 return -1;
235 } else {
Steve Block5baa3a62011-12-20 16:23:08 +0000236 ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 }
238
239 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240}
241
Greg Hackmann0eb58262014-02-26 12:22:13 -0800242static 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);
Greg Hackmann0eb58262014-02-26 12:22:13 -0800248 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{
Mykola Kondratenkoe45abfa2016-01-18 12:43:30 +0100271 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(rtc_sysfs), closedir);
272 if (!dir.get()) {
Greg Hackmann0eb58262014-02-26 12:22:13 -0800273 ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
274 return -1;
275 }
276
277 struct dirent *dirent;
Mykola Kondratenkoe45abfa2016-01-18 12:43:30 +0100278 while (errno = 0, dirent = readdir(dir.get())) {
Greg Hackmann0eb58262014-02-26 12:22:13 -0800279 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
Greg Hackmanna0126e02016-05-02 13:22:51 -0700301static 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
Greg Hackmannd7151c02016-04-25 13:30:34 -0700327static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800329 int epollfd;
Greg Hackmannd7151c02016-04-25 13:30:34 -0700330 TimerFds fds;
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800331
Greg Hackmannd7151c02016-04-25 13:30:34 -0700332 epollfd = epoll_create(fds.size());
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800333 if (epollfd < 0) {
Greg Hackmannd7151c02016-04-25 13:30:34 -0700334 ALOGE("epoll_create(%zu) failed: %s", fds.size(),
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800335 strerror(errno));
336 return 0;
337 }
338
Greg Hackmannd7151c02016-04-25 13:30:34 -0700339 for (size_t i = 0; i < fds.size(); i++) {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800340 fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
341 if (fds[i] < 0) {
Greg Hackmanna0126e02016-05-02 13:22:51 -0700342 log_timerfd_create_error(android_alarm_to_clockid[i]);
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800343 close(epollfd);
344 for (size_t j = 0; j < i; j++) {
345 close(fds[j]);
346 }
347 return 0;
348 }
349 }
350
Greg Hackmannd7151c02016-04-25 13:30:34 -0700351 AlarmImpl *ret = new AlarmImpl(fds, epollfd, wall_clock_rtc());
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800352
Greg Hackmannd7151c02016-04-25 13:30:34 -0700353 for (size_t i = 0; i < fds.size(); i++) {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800354 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) {
Greg Hackmannd7151c02016-04-25 13:30:34 -0700360 ALOGE("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800361 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) {
Greg Hackmannd7151c02016-04-25 13:30:34 -0700374 ALOGE("timerfd_settime() failed: %s", strerror(errno));
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800375 delete ret;
376 return 0;
377 }
378
379 return reinterpret_cast<jlong>(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380}
381
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800382static 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 struct timespec ts;
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700392 ts.tv_sec = seconds;
393 ts.tv_nsec = nanoseconds;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700394
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800395 int result = impl->set(type, &ts);
Greg Hackmann32b4c072013-12-06 10:52:09 -0800396 if (result < 0)
397 {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000398 ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
399 static_cast<long long>(seconds),
400 static_cast<long long>(nanoseconds), strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402}
403
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800404static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405{
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800406 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
Greg Hackmann32b4c072013-12-06 10:52:09 -0800407 int result = 0;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700408
Greg Hackmann32b4c072013-12-06 10:52:09 -0800409 do
410 {
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800411 result = impl->waitForAlarm();
Greg Hackmann32b4c072013-12-06 10:52:09 -0800412 } while (result < 0 && errno == EINTR);
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700413
Greg Hackmann32b4c072013-12-06 10:52:09 -0800414 if (result < 0)
415 {
Steve Block3762c312012-01-06 19:20:56 +0000416 ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 return 0;
418 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421}
422
Daniel Micay76f6a862015-09-19 17:31:01 -0400423static const JNINativeMethod sMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 /* name, signature, funcPtr */
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800425 {"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},
Greg Hackmann38bf5142014-02-19 16:39:36 -0800429 {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
Greg Hackmanna1d6f922013-12-09 16:56:53 -0800430 {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431};
432
433int register_android_server_AlarmManagerService(JNIEnv* env)
434{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
436 sMethods, NELEM(sMethods));
437}
438
439} /* namespace android */