1/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp 2** 3** Copyright 2006, The Android Open Source Project 4** 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 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 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. 16*/ 17 18#define LOG_TAG "AlarmManagerService" 19 20#include "JNIHelp.h" 21#include "jni.h" 22#include <utils/Log.h> 23#include <utils/misc.h> 24#include <utils/String8.h> 25 26#include <dirent.h> 27#include <fcntl.h> 28#include <stdio.h> 29#include <string.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> 36#include <stdlib.h> 37#include <errno.h> 38#include <unistd.h> 39#include <linux/ioctl.h> 40#include <linux/rtc.h> 41 42#include <array> 43#include <memory> 44 45namespace android { 46 47static 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; 62static 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}; 71 72typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds; 73 74class AlarmImpl 75{ 76public: 77 AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) : 78 fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { } 79 ~AlarmImpl(); 80 81 int set(int type, struct timespec *ts); 82 int setTime(struct timeval *tv); 83 int waitForAlarm(); 84 85private: 86 const TimerFds fds; 87 const int epollfd; 88 const int rtc_id; 89}; 90 91AlarmImpl::~AlarmImpl() 92{ 93 for (auto fd : fds) { 94 epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr); 95 close(fd); 96 } 97 98 close(epollfd); 99} 100 101int AlarmImpl::set(int type, struct timespec *ts) 102{ 103 if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) { 104 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 121int AlarmImpl::setTime(struct timeval *tv) 122{ 123 struct rtc_time rtc; 124 struct tm tm, *gmtime_res; 125 int fd; 126 int res; 127 128 res = settimeofday(tv, NULL); 129 if (res < 0) { 130 ALOGV("settimeofday() failed: %s\n", strerror(errno)); 131 return -1; 132 } 133 134 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); 142 if (fd < 0) { 143 ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno)); 144 return res; 145 } 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 172int AlarmImpl::waitForAlarm() 173{ 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 200static 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 224static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest) 225{ 226 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) { 233 ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno)); 234 return -1; 235 } else { 236 ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest); 237 } 238 239 return 0; 240} 241 242static 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); 248 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{ 271 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(rtc_sysfs), closedir); 272 if (!dir.get()) { 273 ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno)); 274 return -1; 275 } 276 277 struct dirent *dirent; 278 while (errno = 0, dirent = readdir(dir.get())) { 279 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 301static 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 327static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) 328{ 329 int epollfd; 330 TimerFds fds; 331 332 epollfd = epoll_create(fds.size()); 333 if (epollfd < 0) { 334 ALOGE("epoll_create(%zu) failed: %s", fds.size(), 335 strerror(errno)); 336 return 0; 337 } 338 339 for (size_t i = 0; i < fds.size(); i++) { 340 fds[i] = timerfd_create(android_alarm_to_clockid[i], 0); 341 if (fds[i] < 0) { 342 log_timerfd_create_error(android_alarm_to_clockid[i]); 343 close(epollfd); 344 for (size_t j = 0; j < i; j++) { 345 close(fds[j]); 346 } 347 return 0; 348 } 349 } 350 351 AlarmImpl *ret = new AlarmImpl(fds, epollfd, wall_clock_rtc()); 352 353 for (size_t i = 0; i < fds.size(); i++) { 354 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) { 360 ALOGE("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno)); 361 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) { 374 ALOGE("timerfd_settime() failed: %s", strerror(errno)); 375 delete ret; 376 return 0; 377 } 378 379 return reinterpret_cast<jlong>(ret); 380} 381 382static 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); 391 struct timespec ts; 392 ts.tv_sec = seconds; 393 ts.tv_nsec = nanoseconds; 394 395 int result = impl->set(type, &ts); 396 if (result < 0) 397 { 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)); 401 } 402} 403 404static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData) 405{ 406 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); 407 int result = 0; 408 409 do 410 { 411 result = impl->waitForAlarm(); 412 } while (result < 0 && errno == EINTR); 413 414 if (result < 0) 415 { 416 ALOGE("Unable to wait on alarm: %s\n", strerror(errno)); 417 return 0; 418 } 419 420 return result; 421} 422 423static 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}, 431}; 432 433int register_android_server_AlarmManagerService(JNIEnv* env) 434{ 435 return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService", 436 sMethods, NELEM(sMethods)); 437} 438 439} /* namespace android */ 440