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 <utils/SystemClock.h> 36#include <utils/Timers.h> 37 38#define LOG_TAG "SystemClock" 39#include "utils/Log.h" 40 41namespace android { 42 43/* 44 * Set the current time. This only works when running as root. 45 */ 46int setCurrentTimeMillis(int64_t millis) 47{ 48#if WIN32 49 // not implemented 50 return -1; 51#else 52 struct timeval tv; 53#ifdef HAVE_ANDROID_OS 54 struct timespec ts; 55 int fd; 56 int res; 57#endif 58 int ret = 0; 59 60 if (millis <= 0 || millis / 1000LL >= INT_MAX) { 61 return -1; 62 } 63 64 tv.tv_sec = (time_t) (millis / 1000LL); 65 tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL); 66 67 ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec); 68 69#ifdef HAVE_ANDROID_OS 70 fd = open("/dev/alarm", O_RDWR); 71 if(fd < 0) { 72 ALOGW("Unable to open alarm driver: %s\n", strerror(errno)); 73 return -1; 74 } 75 ts.tv_sec = tv.tv_sec; 76 ts.tv_nsec = tv.tv_usec * 1000; 77 res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts); 78 if(res < 0) { 79 ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno)); 80 ret = -1; 81 } 82 close(fd); 83#else 84 if (settimeofday(&tv, NULL) != 0) { 85 ALOGW("Unable to set clock to %d.%d: %s\n", 86 (int) tv.tv_sec, (int) tv.tv_usec, strerror(errno)); 87 ret = -1; 88 } 89#endif 90 91 return ret; 92#endif // WIN32 93} 94 95/* 96 * native public static long uptimeMillis(); 97 */ 98int64_t uptimeMillis() 99{ 100 int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); 101 return (int64_t) nanoseconds_to_milliseconds(when); 102} 103 104/* 105 * native public static long elapsedRealtime(); 106 */ 107int64_t elapsedRealtime() 108{ 109 return nanoseconds_to_milliseconds(elapsedRealtimeNano()); 110} 111 112#define METHOD_CLOCK_GETTIME 0 113#define METHOD_IOCTL 1 114#define METHOD_SYSTEMTIME 2 115 116static const char *gettime_method_names[] = { 117 "clock_gettime", 118 "ioctl", 119 "systemTime", 120}; 121 122static inline void checkTimeStamps(int64_t timestamp, 123 int64_t volatile *prevTimestampPtr, 124 int volatile *prevMethodPtr, 125 int curMethod) 126{ 127 /* 128 * Disable the check for SDK since the prebuilt toolchain doesn't contain 129 * gettid, and int64_t is different on the ARM platform 130 * (ie long vs long long). 131 */ 132#ifdef ARCH_ARM 133 int64_t prevTimestamp = *prevTimestampPtr; 134 int prevMethod = *prevMethodPtr; 135 136 if (timestamp < prevTimestamp) { 137 ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d", 138 prevTimestamp, gettime_method_names[prevMethod], 139 timestamp, gettime_method_names[curMethod], 140 gettid()); 141 } 142 // NOTE - not atomic and may generate spurious warnings if the 64-bit 143 // write is interrupted or not observed as a whole. 144 *prevTimestampPtr = timestamp; 145 *prevMethodPtr = curMethod; 146#endif 147} 148 149/* 150 * native public static long elapsedRealtimeNano(); 151 */ 152int64_t elapsedRealtimeNano() 153{ 154#ifdef HAVE_ANDROID_OS 155 struct timespec ts; 156 int result; 157 int64_t timestamp; 158 static volatile int64_t prevTimestamp; 159 static volatile int prevMethod; 160 161#if 0 162 /* 163 * b/7100774 164 * clock_gettime appears to have clock skews and can sometimes return 165 * backwards values. Disable its use until we find out what's wrong. 166 */ 167 result = clock_gettime(CLOCK_BOOTTIME, &ts); 168 if (result == 0) { 169 timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; 170 checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, 171 METHOD_CLOCK_GETTIME); 172 return timestamp; 173 } 174#endif 175 176 // CLOCK_BOOTTIME doesn't exist, fallback to /dev/alarm 177 static int s_fd = -1; 178 179 if (s_fd == -1) { 180 int fd = open("/dev/alarm", O_RDONLY); 181 if (android_atomic_cmpxchg(-1, fd, &s_fd)) { 182 close(fd); 183 } 184 } 185 186 result = ioctl(s_fd, 187 ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts); 188 189 if (result == 0) { 190 timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; 191 checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL); 192 return timestamp; 193 } 194 195 // XXX: there was an error, probably because the driver didn't 196 // exist ... this should return 197 // a real error, like an exception! 198 timestamp = systemTime(SYSTEM_TIME_MONOTONIC); 199 checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, 200 METHOD_SYSTEMTIME); 201 return timestamp; 202#else 203 return systemTime(SYSTEM_TIME_MONOTONIC); 204#endif 205} 206 207}; // namespace android 208