com_android_server_AlarmManagerService.cpp revision 76f6a86de25e1bf74717e047e55fd44b089673f3
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/android_alarm.h> 41#include <linux/rtc.h> 42 43namespace android { 44 45static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1; 46static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = { 47 CLOCK_REALTIME_ALARM, 48 CLOCK_REALTIME, 49 CLOCK_BOOTTIME_ALARM, 50 CLOCK_BOOTTIME, 51 CLOCK_MONOTONIC, 52 CLOCK_REALTIME, 53}; 54/* to match the legacy alarm driver implementation, we need an extra 55 CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */ 56 57class AlarmImpl 58{ 59public: 60 AlarmImpl(int *fds, size_t n_fds); 61 virtual ~AlarmImpl(); 62 63 virtual int set(int type, struct timespec *ts) = 0; 64 virtual int setTime(struct timeval *tv) = 0; 65 virtual int waitForAlarm() = 0; 66 67protected: 68 int *fds; 69 size_t n_fds; 70}; 71 72class AlarmImplAlarmDriver : public AlarmImpl 73{ 74public: 75 AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { } 76 77 int set(int type, struct timespec *ts); 78 int setTime(struct timeval *tv); 79 int waitForAlarm(); 80}; 81 82class AlarmImplTimerFd : public AlarmImpl 83{ 84public: 85 AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) : 86 AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { } 87 ~AlarmImplTimerFd(); 88 89 int set(int type, struct timespec *ts); 90 int setTime(struct timeval *tv); 91 int waitForAlarm(); 92 93private: 94 int epollfd; 95 int rtc_id; 96}; 97 98AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]), 99 n_fds(n_fds) 100{ 101 memcpy(fds, fds_, n_fds * sizeof(fds[0])); 102} 103 104AlarmImpl::~AlarmImpl() 105{ 106 for (size_t i = 0; i < n_fds; i++) { 107 close(fds[i]); 108 } 109 delete [] fds; 110} 111 112int AlarmImplAlarmDriver::set(int type, struct timespec *ts) 113{ 114 return ioctl(fds[0], ANDROID_ALARM_SET(type), ts); 115} 116 117int AlarmImplAlarmDriver::setTime(struct timeval *tv) 118{ 119 struct timespec ts; 120 int res; 121 122 ts.tv_sec = tv->tv_sec; 123 ts.tv_nsec = tv->tv_usec * 1000; 124 res = ioctl(fds[0], ANDROID_ALARM_SET_RTC, &ts); 125 if (res < 0) 126 ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno)); 127 return res; 128} 129 130int AlarmImplAlarmDriver::waitForAlarm() 131{ 132 return ioctl(fds[0], ANDROID_ALARM_WAIT); 133} 134 135AlarmImplTimerFd::~AlarmImplTimerFd() 136{ 137 for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { 138 epoll_ctl(epollfd, EPOLL_CTL_DEL, fds[i], NULL); 139 } 140 close(epollfd); 141} 142 143int AlarmImplTimerFd::set(int type, struct timespec *ts) 144{ 145 if (type > ANDROID_ALARM_TYPE_COUNT) { 146 errno = EINVAL; 147 return -1; 148 } 149 150 if (!ts->tv_nsec && !ts->tv_sec) { 151 ts->tv_nsec = 1; 152 } 153 /* timerfd interprets 0 = disarm, so replace with a practically 154 equivalent deadline of 1 ns */ 155 156 struct itimerspec spec; 157 memset(&spec, 0, sizeof(spec)); 158 memcpy(&spec.it_value, ts, sizeof(spec.it_value)); 159 160 return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL); 161} 162 163int AlarmImplTimerFd::setTime(struct timeval *tv) 164{ 165 struct rtc_time rtc; 166 struct tm tm, *gmtime_res; 167 int fd; 168 int res; 169 170 res = settimeofday(tv, NULL); 171 if (res < 0) { 172 ALOGV("settimeofday() failed: %s\n", strerror(errno)); 173 return -1; 174 } 175 176 if (rtc_id < 0) { 177 ALOGV("Not setting RTC because wall clock RTC was not found"); 178 errno = ENODEV; 179 return -1; 180 } 181 182 android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id); 183 fd = open(rtc_dev.string(), O_RDWR); 184 if (fd < 0) { 185 ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno)); 186 return res; 187 } 188 189 gmtime_res = gmtime_r(&tv->tv_sec, &tm); 190 if (!gmtime_res) { 191 ALOGV("gmtime_r() failed: %s\n", strerror(errno)); 192 res = -1; 193 goto done; 194 } 195 196 memset(&rtc, 0, sizeof(rtc)); 197 rtc.tm_sec = tm.tm_sec; 198 rtc.tm_min = tm.tm_min; 199 rtc.tm_hour = tm.tm_hour; 200 rtc.tm_mday = tm.tm_mday; 201 rtc.tm_mon = tm.tm_mon; 202 rtc.tm_year = tm.tm_year; 203 rtc.tm_wday = tm.tm_wday; 204 rtc.tm_yday = tm.tm_yday; 205 rtc.tm_isdst = tm.tm_isdst; 206 res = ioctl(fd, RTC_SET_TIME, &rtc); 207 if (res < 0) 208 ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno)); 209done: 210 close(fd); 211 return res; 212} 213 214int AlarmImplTimerFd::waitForAlarm() 215{ 216 epoll_event events[N_ANDROID_TIMERFDS]; 217 218 int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1); 219 if (nevents < 0) { 220 return nevents; 221 } 222 223 int result = 0; 224 for (int i = 0; i < nevents; i++) { 225 uint32_t alarm_idx = events[i].data.u32; 226 uint64_t unused; 227 ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused)); 228 if (err < 0) { 229 if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) { 230 result |= ANDROID_ALARM_TIME_CHANGE_MASK; 231 } else { 232 return err; 233 } 234 } else { 235 result |= (1 << alarm_idx); 236 } 237 } 238 239 return result; 240} 241 242static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis) 243{ 244 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); 245 struct timeval tv; 246 int ret; 247 248 if (millis <= 0 || millis / 1000LL >= INT_MAX) { 249 return -1; 250 } 251 252 tv.tv_sec = (time_t) (millis / 1000LL); 253 tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL); 254 255 ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec); 256 257 ret = impl->setTime(&tv); 258 259 if(ret < 0) { 260 ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno)); 261 ret = -1; 262 } 263 return ret; 264} 265 266static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest) 267{ 268 struct timezone tz; 269 270 tz.tz_minuteswest = minswest; 271 tz.tz_dsttime = 0; 272 273 int result = settimeofday(NULL, &tz); 274 if (result < 0) { 275 ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno)); 276 return -1; 277 } else { 278 ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest); 279 } 280 281 return 0; 282} 283 284static jlong init_alarm_driver() 285{ 286 int fd = open("/dev/alarm", O_RDWR); 287 if (fd < 0) { 288 ALOGV("opening alarm driver failed: %s", strerror(errno)); 289 return 0; 290 } 291 292 AlarmImpl *ret = new AlarmImplAlarmDriver(fd); 293 return reinterpret_cast<jlong>(ret); 294} 295 296static const char rtc_sysfs[] = "/sys/class/rtc"; 297 298static bool rtc_is_hctosys(unsigned int rtc_id) 299{ 300 android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys", 301 rtc_sysfs, rtc_id); 302 303 FILE *file = fopen(hctosys_path.string(), "re"); 304 if (!file) { 305 ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno)); 306 return false; 307 } 308 309 unsigned int hctosys; 310 bool ret = false; 311 int err = fscanf(file, "%u", &hctosys); 312 if (err == EOF) 313 ALOGE("failed to read from %s: %s", hctosys_path.string(), 314 strerror(errno)); 315 else if (err == 0) 316 ALOGE("%s did not have expected contents", hctosys_path.string()); 317 else 318 ret = hctosys; 319 320 fclose(file); 321 return ret; 322} 323 324static int wall_clock_rtc() 325{ 326 DIR *dir = opendir(rtc_sysfs); 327 if (!dir) { 328 ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno)); 329 return -1; 330 } 331 332 struct dirent *dirent; 333 while (errno = 0, dirent = readdir(dir)) { 334 unsigned int rtc_id; 335 int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id); 336 337 if (matched < 0) 338 break; 339 else if (matched != 1) 340 continue; 341 342 if (rtc_is_hctosys(rtc_id)) { 343 ALOGV("found wall clock RTC %u", rtc_id); 344 return rtc_id; 345 } 346 } 347 348 if (errno == 0) 349 ALOGW("no wall clock RTC found"); 350 else 351 ALOGE("failed to enumerate RTCs: %s", strerror(errno)); 352 353 return -1; 354} 355 356static jlong init_timerfd() 357{ 358 int epollfd; 359 int fds[N_ANDROID_TIMERFDS]; 360 361 epollfd = epoll_create(N_ANDROID_TIMERFDS); 362 if (epollfd < 0) { 363 ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS, 364 strerror(errno)); 365 return 0; 366 } 367 368 for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { 369 fds[i] = timerfd_create(android_alarm_to_clockid[i], 0); 370 if (fds[i] < 0) { 371 ALOGV("timerfd_create(%u) failed: %s", android_alarm_to_clockid[i], 372 strerror(errno)); 373 close(epollfd); 374 for (size_t j = 0; j < i; j++) { 375 close(fds[j]); 376 } 377 return 0; 378 } 379 } 380 381 AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc()); 382 383 for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { 384 epoll_event event; 385 event.events = EPOLLIN | EPOLLWAKEUP; 386 event.data.u32 = i; 387 388 int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event); 389 if (err < 0) { 390 ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno)); 391 delete ret; 392 return 0; 393 } 394 } 395 396 struct itimerspec spec; 397 memset(&spec, 0, sizeof(spec)); 398 /* 0 = disarmed; the timerfd doesn't need to be armed to get 399 RTC change notifications, just set up as cancelable */ 400 401 int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT], 402 TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL); 403 if (err < 0) { 404 ALOGV("timerfd_settime() failed: %s", strerror(errno)); 405 delete ret; 406 return 0; 407 } 408 409 return reinterpret_cast<jlong>(ret); 410} 411 412static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) 413{ 414 jlong ret = init_alarm_driver(); 415 if (ret) { 416 return ret; 417 } 418 419 return init_timerfd(); 420} 421 422static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData) 423{ 424 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); 425 delete impl; 426} 427 428static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds) 429{ 430 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); 431 struct timespec ts; 432 ts.tv_sec = seconds; 433 ts.tv_nsec = nanoseconds; 434 435 int result = impl->set(type, &ts); 436 if (result < 0) 437 { 438 ALOGE("Unable to set alarm to %lld.%09lld: %s\n", 439 static_cast<long long>(seconds), 440 static_cast<long long>(nanoseconds), strerror(errno)); 441 } 442} 443 444static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData) 445{ 446 AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); 447 int result = 0; 448 449 do 450 { 451 result = impl->waitForAlarm(); 452 } while (result < 0 && errno == EINTR); 453 454 if (result < 0) 455 { 456 ALOGE("Unable to wait on alarm: %s\n", strerror(errno)); 457 return 0; 458 } 459 460 return result; 461} 462 463static const JNINativeMethod sMethods[] = { 464 /* name, signature, funcPtr */ 465 {"init", "()J", (void*)android_server_AlarmManagerService_init}, 466 {"close", "(J)V", (void*)android_server_AlarmManagerService_close}, 467 {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set}, 468 {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm}, 469 {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime}, 470 {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone}, 471}; 472 473int register_android_server_AlarmManagerService(JNIEnv* env) 474{ 475 return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService", 476 sMethods, NELEM(sMethods)); 477} 478 479} /* namespace android */ 480