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