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>
41 #include <cutils/properties.h>
48 static constexpr int ANDROID_ALARM_TIME_CHANGE_MASK = 1 << 16;
51 * The AlarmManager alarm constants:
57 * SYSTEMTIME (only defined in old alarm driver header, possibly unused?)
59 * We also need an extra CLOCK_REALTIME fd which exists specifically to be
60 * canceled on RTC changes.
62 static const size_t ANDROID_ALARM_TYPE_COUNT = 5;
63 static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
64 static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
73 typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
78 AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) :
79 fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { }
82 int set(int type, struct timespec *ts);
83 int setTime(struct timeval *tv);
92 AlarmImpl::~AlarmImpl()
95 epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr);
102 int AlarmImpl::set(int type, struct timespec *ts)
104 if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) {
109 if (!ts->tv_nsec && !ts->tv_sec) {
112 /* timerfd interprets 0 = disarm, so replace with a practically
113 equivalent deadline of 1 ns */
115 struct itimerspec spec;
116 memset(&spec, 0, sizeof(spec));
117 memcpy(&spec.it_value, ts, sizeof(spec.it_value));
119 return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
122 int AlarmImpl::setTime(struct timeval *tv)
125 struct tm tm, *localtime_res, *gmtime_res;
129 res = settimeofday(tv, NULL);
131 ALOGV("settimeofday() failed: %s\n", strerror(errno));
136 ALOGV("Not setting RTC because wall clock RTC was not found");
141 android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
142 fd = open(rtc_dev.string(), O_RDWR);
144 ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
148 // @jide when persist.rtc_local_time is set to 1, we store the localtime to rtc
150 bool rtc_local_time = property_get_bool("persist.rtc_local_time", false);
151 if (rtc_local_time) {
152 localtime_res = localtime_r(&tv->tv_sec, &tm);
153 if (!localtime_res) {
154 ALOGV("localtime_r() failed: %s\n", strerror(errno));
159 gmtime_res = gmtime_r(&tv->tv_sec, &tm);
161 ALOGV("gmtime_r() failed: %s\n", strerror(errno));
167 memset(&rtc, 0, sizeof(rtc));
168 rtc.tm_sec = tm.tm_sec;
169 rtc.tm_min = tm.tm_min;
170 rtc.tm_hour = tm.tm_hour;
171 rtc.tm_mday = tm.tm_mday;
172 rtc.tm_mon = tm.tm_mon;
173 rtc.tm_year = tm.tm_year;
174 rtc.tm_wday = tm.tm_wday;
175 rtc.tm_yday = tm.tm_yday;
176 rtc.tm_isdst = tm.tm_isdst;
177 res = ioctl(fd, RTC_SET_TIME, &rtc);
179 ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
185 int AlarmImpl::waitForAlarm()
187 epoll_event events[N_ANDROID_TIMERFDS];
189 int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);
195 for (int i = 0; i < nevents; i++) {
196 uint32_t alarm_idx = events[i].data.u32;
198 ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
200 if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
201 result |= ANDROID_ALARM_TIME_CHANGE_MASK;
206 result |= (1 << alarm_idx);
213 static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
215 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
219 if (millis <= 0 || millis / 1000LL >= INT_MAX) {
223 tv.tv_sec = (time_t) (millis / 1000LL);
224 tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
226 ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
228 ret = impl->setTime(&tv);
231 ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
237 static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
241 tz.tz_minuteswest = minswest;
244 int result = settimeofday(NULL, &tz);
246 ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
249 ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
255 static const char rtc_sysfs[] = "/sys/class/rtc";
257 static bool rtc_is_hctosys(unsigned int rtc_id)
259 android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
261 FILE *file = fopen(hctosys_path.string(), "re");
263 ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
267 unsigned int hctosys;
269 int err = fscanf(file, "%u", &hctosys);
271 ALOGE("failed to read from %s: %s", hctosys_path.string(),
274 ALOGE("%s did not have expected contents", hctosys_path.string());
282 static int wall_clock_rtc()
284 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(rtc_sysfs), closedir);
286 ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
290 struct dirent *dirent;
291 while (errno = 0, dirent = readdir(dir.get())) {
293 int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id);
297 else if (matched != 1)
300 if (rtc_is_hctosys(rtc_id)) {
301 ALOGV("found wall clock RTC %u", rtc_id);
307 ALOGW("no wall clock RTC found");
309 ALOGE("failed to enumerate RTCs: %s", strerror(errno));
314 static void log_timerfd_create_error(clockid_t id)
316 if (errno == EINVAL) {
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");
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)");
337 ALOGE("timerfd_create(%u) failed: %s", id, strerror(errno));
340 static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
345 epollfd = epoll_create(fds.size());
347 ALOGE("epoll_create(%zu) failed: %s", fds.size(),
352 for (size_t i = 0; i < fds.size(); i++) {
353 fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
355 log_timerfd_create_error(android_alarm_to_clockid[i]);
357 for (size_t j = 0; j < i; j++) {
364 AlarmImpl *ret = new AlarmImpl(fds, epollfd, wall_clock_rtc());
366 for (size_t i = 0; i < fds.size(); i++) {
368 event.events = EPOLLIN | EPOLLWAKEUP;
371 int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
373 ALOGE("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
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 */
384 int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
385 TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
387 ALOGE("timerfd_settime() failed: %s", strerror(errno));
392 return reinterpret_cast<jlong>(ret);
395 static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
397 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
401 static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
403 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
406 ts.tv_nsec = nanoseconds;
408 int result = impl->set(type, &ts);
411 ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
412 static_cast<long long>(seconds),
413 static_cast<long long>(nanoseconds), strerror(errno));
417 static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
419 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
424 result = impl->waitForAlarm();
425 } while (result < 0 && errno == EINTR);
429 ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
436 static const JNINativeMethod sMethods[] = {
437 /* name, signature, funcPtr */
438 {"init", "()J", (void*)android_server_AlarmManagerService_init},
439 {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
440 {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
441 {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
442 {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
443 {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
446 int register_android_server_AlarmManagerService(JNIEnv* env)
448 return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
449 sMethods, NELEM(sMethods));
452 } /* namespace android */