OSDN Git Service

Merge cherrypicks of [7077328, 7074021, 7074022, 7077576, 7077577, 7077578, 7077579...
[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
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 void 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     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 }
403
404 static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
405 {
406     AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
407     int result = 0;
408
409     do
410     {
411         result = impl->waitForAlarm();
412     } while (result < 0 && errno == EINTR);
413
414     if (result < 0)
415     {
416         ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
417         return 0;
418     }
419
420     return result;
421 }
422
423 static const JNINativeMethod sMethods[] = {
424      /* name, signature, funcPtr */
425     {"init", "()J", (void*)android_server_AlarmManagerService_init},
426     {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
427     {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
428     {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
429     {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
430     {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
431 };
432
433 int register_android_server_AlarmManagerService(JNIEnv* env)
434 {
435     return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
436                                     sMethods, NELEM(sMethods));
437 }
438
439 } /* namespace android */