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 <nativehelper/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 
     45 namespace android {
     46 
     47 static 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  */
     61 static const size_t ANDROID_ALARM_TYPE_COUNT = 5;
     62 static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
     63 static 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 
     72 typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
     73 
     74 class AlarmImpl
     75 {
     76 public:
     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 
     85 private:
     86     const TimerFds fds;
     87     const int epollfd;
     88     const int rtc_id;
     89 };
     90 
     91 AlarmImpl::~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 
    101 int 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 
    121 int 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));
    167 done:
    168     close(fd);
    169     return res;
    170 }
    171 
    172 int 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 
    200 static 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 
    224 static 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 
    242 static const char rtc_sysfs[] = "/sys/class/rtc";
    243 
    244 static 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 
    269 static 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 
    301 static 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 
    327 static 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 
    382 static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
    383 {
    384     AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
    385     delete impl;
    386 }
    387 
    388 static jint 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     const 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     return result >= 0 ? 0 : errno;
    403 }
    404 
    405 static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
    406 {
    407     AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
    408     int result = 0;
    409 
    410     do
    411     {
    412         result = impl->waitForAlarm();
    413     } while (result < 0 && errno == EINTR);
    414 
    415     if (result < 0)
    416     {
    417         ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
    418         return 0;
    419     }
    420 
    421     return result;
    422 }
    423 
    424 static const JNINativeMethod sMethods[] = {
    425      /* name, signature, funcPtr */
    426     {"init", "()J", (void*)android_server_AlarmManagerService_init},
    427     {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
    428     {"set", "(JIJJ)I", (void*)android_server_AlarmManagerService_set},
    429     {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
    430     {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
    431     {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
    432 };
    433 
    434 int register_android_server_AlarmManagerService(JNIEnv* env)
    435 {
    436     return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
    437                                     sMethods, NELEM(sMethods));
    438 }
    439 
    440 } /* namespace android */
    441