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