OSDN Git Service

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