android_os_SystemClock.cpp revision b7bbca2d6a0ba8e7a0cee5f7683a8193c0e30140
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18/*
19 * System clock functions.
20 */
21
22#ifdef HAVE_ANDROID_OS
23#include <linux/ioctl.h>
24#include <linux/rtc.h>
25#include <utils/Atomic.h>
26#include <linux/android_alarm.h>
27#endif
28
29#include <sys/time.h>
30#include <limits.h>
31#include <fcntl.h>
32#include <errno.h>
33#include <string.h>
34
35#include "JNIHelp.h"
36#include "jni.h"
37#include "android_runtime/AndroidRuntime.h"
38
39#include <sys/time.h>
40#include <time.h>
41
42#include <utils/SystemClock.h>
43
44namespace android {
45
46static int setCurrentTimeMillisAlarmDriver(struct timeval *tv)
47{
48    struct timespec ts;
49    int fd;
50    int res;
51
52    fd = open("/dev/alarm", O_RDWR);
53    if(fd < 0) {
54        ALOGV("Unable to open alarm driver: %s\n", strerror(errno));
55        return -1;
56    }
57    ts.tv_sec = tv->tv_sec;
58    ts.tv_nsec = tv->tv_usec * 1000;
59    res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
60    if (res < 0)
61        ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno));
62    close(fd);
63    return res;
64}
65
66static int setCurrentTimeMillisRtc(struct timeval *tv)
67{
68    struct rtc_time rtc;
69    struct tm tm, *gmtime_res;
70    int fd;
71    int res;
72
73    fd = open("/dev/rtc0", O_RDWR);
74    if (fd < 0) {
75        ALOGV("Unable to open RTC driver: %s\n", strerror(errno));
76        return -1;
77    }
78
79    res = settimeofday(tv, NULL);
80    if (res < 0) {
81        ALOGV("settimeofday() failed: %s\n", strerror(errno));
82        goto done;
83    }
84
85    gmtime_res = gmtime_r(&tv->tv_sec, &tm);
86    if (!gmtime_res) {
87        ALOGV("gmtime_r() failed: %s\n", strerror(errno));
88        res = -1;
89        goto done;
90    }
91
92    memset(&rtc, 0, sizeof(rtc));
93    rtc.tm_sec = tm.tm_sec;
94    rtc.tm_min = tm.tm_min;
95    rtc.tm_hour = tm.tm_hour;
96    rtc.tm_mday = tm.tm_mday;
97    rtc.tm_mon = tm.tm_mon;
98    rtc.tm_year = tm.tm_year;
99    rtc.tm_wday = tm.tm_wday;
100    rtc.tm_yday = tm.tm_yday;
101    rtc.tm_isdst = tm.tm_isdst;
102    res = ioctl(fd, RTC_SET_TIME, &rtc);
103    if (res < 0)
104        ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
105done:
106    close(fd);
107    return res;
108}
109
110/*
111 * Set the current time.  This only works when running as root.
112 */
113static int setCurrentTimeMillis(int64_t millis)
114{
115    struct timeval tv;
116    int ret;
117
118    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
119        return -1;
120    }
121
122    tv.tv_sec = (time_t) (millis / 1000LL);
123    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
124
125    ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
126
127    ret = setCurrentTimeMillisAlarmDriver(&tv);
128    if (ret < 0)
129        ret = setCurrentTimeMillisRtc(&tv);
130
131    if(ret < 0) {
132        ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
133        ret = -1;
134    }
135    return ret;
136}
137
138/*
139 * native public static void setCurrentTimeMillis(long millis)
140 *
141 * Set the current time.  This only works when running as root.
142 */
143static jboolean android_os_SystemClock_setCurrentTimeMillis(JNIEnv* env,
144    jobject clazz, jlong millis)
145{
146    return (setCurrentTimeMillis(millis) == 0);
147}
148
149/*
150 * native public static long uptimeMillis();
151 */
152static jlong android_os_SystemClock_uptimeMillis(JNIEnv* env,
153        jobject clazz)
154{
155    return (jlong)uptimeMillis();
156}
157
158/*
159 * native public static long elapsedRealtime();
160 */
161static jlong android_os_SystemClock_elapsedRealtime(JNIEnv* env,
162        jobject clazz)
163{
164    return (jlong)elapsedRealtime();
165}
166
167/*
168 * native public static long currentThreadTimeMillis();
169 */
170static jlong android_os_SystemClock_currentThreadTimeMillis(JNIEnv* env,
171        jobject clazz)
172{
173#if defined(HAVE_POSIX_CLOCKS)
174    struct timespec tm;
175
176    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
177
178    return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
179#else
180    struct timeval tv;
181
182    gettimeofday(&tv, NULL);
183    return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
184#endif
185}
186
187/*
188 * native public static long currentThreadTimeMicro();
189 */
190static jlong android_os_SystemClock_currentThreadTimeMicro(JNIEnv* env,
191        jobject clazz)
192{
193#if defined(HAVE_POSIX_CLOCKS)
194    struct timespec tm;
195
196    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
197
198    return tm.tv_sec * 1000000LL + tm.tv_nsec / 1000;
199#else
200    struct timeval tv;
201
202    gettimeofday(&tv, NULL);
203    return tv.tv_sec * 1000000LL + tv.tv_nsec / 1000;
204#endif
205}
206
207/*
208 * native public static long currentTimeMicro();
209 */
210static jlong android_os_SystemClock_currentTimeMicro(JNIEnv* env,
211        jobject clazz)
212{
213    struct timeval tv;
214
215    gettimeofday(&tv, NULL);
216    return tv.tv_sec * 1000000LL + tv.tv_usec;
217}
218
219/*
220 * public static native long elapsedRealtimeNano();
221 */
222static jlong android_os_SystemClock_elapsedRealtimeNano(JNIEnv* env,
223        jobject clazz)
224{
225    return (jlong)elapsedRealtimeNano();
226}
227
228/*
229 * JNI registration.
230 */
231static JNINativeMethod gMethods[] = {
232    /* name, signature, funcPtr */
233    { "setCurrentTimeMillis",      "(J)Z",
234            (void*) android_os_SystemClock_setCurrentTimeMillis },
235    { "uptimeMillis",      "()J",
236            (void*) android_os_SystemClock_uptimeMillis },
237    { "elapsedRealtime",      "()J",
238            (void*) android_os_SystemClock_elapsedRealtime },
239    { "currentThreadTimeMillis",      "()J",
240            (void*) android_os_SystemClock_currentThreadTimeMillis },
241    { "currentThreadTimeMicro",       "()J",
242            (void*) android_os_SystemClock_currentThreadTimeMicro },
243    { "currentTimeMicro",             "()J",
244            (void*) android_os_SystemClock_currentTimeMicro },
245    { "elapsedRealtimeNanos",      "()J",
246            (void*) android_os_SystemClock_elapsedRealtimeNano },
247};
248int register_android_os_SystemClock(JNIEnv* env)
249{
250    return AndroidRuntime::registerNativeMethods(env,
251            "android/os/SystemClock", gMethods, NELEM(gMethods));
252}
253
254}; // namespace android
255
256