1 /* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
3 ** Copyright 2006, The Android Open Source Project
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
9 ** http://www.apache.org/licenses/LICENSE-2.0
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.
18 #define LOG_TAG "AlarmManagerService"
20 #include <nativehelper/JNIHelp.h>
22 #include <utils/Log.h>
23 #include <utils/misc.h>
24 #include <utils/String8.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>
39 #include <linux/ioctl.h>
40 #include <linux/rtc.h>
47 static constexpr int ANDROID_ALARM_TIME_CHANGE_MASK = 1 << 16;
50 * The AlarmManager alarm constants:
56 * SYSTEMTIME (only defined in old alarm driver header, possibly unused?)
58 * We also need an extra CLOCK_REALTIME fd which exists specifically to be
59 * canceled on RTC changes.
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] = {
72 typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
77 AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) :
78 fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { }
81 int set(int type, struct timespec *ts);
82 int setTime(struct timeval *tv);
91 AlarmImpl::~AlarmImpl()
94 epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr);
101 int AlarmImpl::set(int type, struct timespec *ts)
103 if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) {
108 if (!ts->tv_nsec && !ts->tv_sec) {
111 /* timerfd interprets 0 = disarm, so replace with a practically
112 equivalent deadline of 1 ns */
114 struct itimerspec spec;
115 memset(&spec, 0, sizeof(spec));
116 memcpy(&spec.it_value, ts, sizeof(spec.it_value));
118 return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
121 int AlarmImpl::setTime(struct timeval *tv)
124 struct tm tm, *gmtime_res;
128 res = settimeofday(tv, NULL);
130 ALOGV("settimeofday() failed: %s\n", strerror(errno));
135 ALOGV("Not setting RTC because wall clock RTC was not found");
140 android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
141 fd = open(rtc_dev.string(), O_RDWR);
143 ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
147 gmtime_res = gmtime_r(&tv->tv_sec, &tm);
149 ALOGV("gmtime_r() failed: %s\n", strerror(errno));
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);
166 ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
172 int AlarmImpl::waitForAlarm()
174 epoll_event events[N_ANDROID_TIMERFDS];
176 int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);
182 for (int i = 0; i < nevents; i++) {
183 uint32_t alarm_idx = events[i].data.u32;
185 ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
187 if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
188 result |= ANDROID_ALARM_TIME_CHANGE_MASK;
193 result |= (1 << alarm_idx);
200 static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
202 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
206 if (millis <= 0 || millis / 1000LL >= INT_MAX) {
210 tv.tv_sec = (time_t) (millis / 1000LL);
211 tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
213 ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
215 ret = impl->setTime(&tv);
218 ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
224 static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
228 tz.tz_minuteswest = minswest;
231 int result = settimeofday(NULL, &tz);
233 ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
236 ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
242 static const char rtc_sysfs[] = "/sys/class/rtc";
244 static bool rtc_is_hctosys(unsigned int rtc_id)
246 android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
248 FILE *file = fopen(hctosys_path.string(), "re");
250 ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
254 unsigned int hctosys;
256 int err = fscanf(file, "%u", &hctosys);
258 ALOGE("failed to read from %s: %s", hctosys_path.string(),
261 ALOGE("%s did not have expected contents", hctosys_path.string());
269 static int wall_clock_rtc()
271 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(rtc_sysfs), closedir);
273 ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
277 struct dirent *dirent;
278 while (errno = 0, dirent = readdir(dir.get())) {
280 int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id);
284 else if (matched != 1)
287 if (rtc_is_hctosys(rtc_id)) {
288 ALOGV("found wall clock RTC %u", rtc_id);
294 ALOGW("no wall clock RTC found");
296 ALOGE("failed to enumerate RTCs: %s", strerror(errno));
301 static void log_timerfd_create_error(clockid_t id)
303 if (errno == EINVAL) {
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");
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)");
324 ALOGE("timerfd_create(%u) failed: %s", id, strerror(errno));
327 static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
332 epollfd = epoll_create(fds.size());
334 ALOGE("epoll_create(%zu) failed: %s", fds.size(),
339 for (size_t i = 0; i < fds.size(); i++) {
340 fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
342 log_timerfd_create_error(android_alarm_to_clockid[i]);
344 for (size_t j = 0; j < i; j++) {
351 AlarmImpl *ret = new AlarmImpl(fds, epollfd, wall_clock_rtc());
353 for (size_t i = 0; i < fds.size(); i++) {
355 event.events = EPOLLIN | EPOLLWAKEUP;
358 int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
360 ALOGE("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
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 */
371 int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
372 TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
374 ALOGE("timerfd_settime() failed: %s", strerror(errno));
379 return reinterpret_cast<jlong>(ret);
382 static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
384 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
388 static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
390 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
393 ts.tv_nsec = nanoseconds;
395 int result = impl->set(type, &ts);
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));
404 static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
406 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
411 result = impl->waitForAlarm();
412 } while (result < 0 && errno == EINTR);
416 ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
423 static 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},
433 int register_android_server_AlarmManagerService(JNIEnv* env)
435 return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
436 sMethods, NELEM(sMethods));
439 } /* namespace android */