felipeg@chromium.org | 406c7ba | 2012-07-17 01:12:16 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/os_compat_android.h" |
| 6 | |
nileshagrawal@chromium.org | e415325 | 2013-06-07 07:42:47 +0900 | [diff] [blame] | 7 | #include <asm/unistd.h> |
felipeg@chromium.org | 406c7ba | 2012-07-17 01:12:16 +0900 | [diff] [blame] | 8 | #include <errno.h> |
avi | a6a6a68 | 2015-12-27 07:15:14 +0900 | [diff] [blame] | 9 | #include <limits.h> |
felipeg@chromium.org | 406c7ba | 2012-07-17 01:12:16 +0900 | [diff] [blame] | 10 | #include <math.h> |
| 11 | #include <sys/stat.h> |
nileshagrawal@chromium.org | e415325 | 2013-06-07 07:42:47 +0900 | [diff] [blame] | 12 | #include <sys/syscall.h> |
primiano@chromium.org | 660e78b | 2014-04-29 09:05:57 +0900 | [diff] [blame] | 13 | |
| 14 | #if !defined(__LP64__) |
nileshagrawal@chromium.org | f9d216a | 2011-12-16 12:18:13 +0900 | [diff] [blame] | 15 | #include <time64.h> |
primiano@chromium.org | 660e78b | 2014-04-29 09:05:57 +0900 | [diff] [blame] | 16 | #endif |
nileshagrawal@chromium.org | f9d216a | 2011-12-16 12:18:13 +0900 | [diff] [blame] | 17 | |
felipeg@chromium.org | 406c7ba | 2012-07-17 01:12:16 +0900 | [diff] [blame] | 18 | #include "base/rand_util.h" |
tfarina@chromium.org | b6d4911 | 2013-03-30 23:29:00 +0900 | [diff] [blame] | 19 | #include "base/strings/string_piece.h" |
avi@chromium.org | 67d593d | 2013-06-11 04:06:57 +0900 | [diff] [blame] | 20 | #include "base/strings/stringprintf.h" |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 21 | |
nileshagrawal@chromium.org | e415325 | 2013-06-07 07:42:47 +0900 | [diff] [blame] | 22 | extern "C" { |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 23 | // There is no futimes() avaiable in Bionic, so we provide our own |
| 24 | // implementation until it is there. |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 25 | int futimes(int fd, const struct timeval tv[2]) { |
nileshagrawal@chromium.org | e415325 | 2013-06-07 07:42:47 +0900 | [diff] [blame] | 26 | if (tv == NULL) |
| 27 | return syscall(__NR_utimensat, fd, NULL, NULL, 0); |
| 28 | |
| 29 | if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 || |
| 30 | tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000) { |
| 31 | errno = EINVAL; |
| 32 | return -1; |
| 33 | } |
| 34 | |
| 35 | // Convert timeval to timespec. |
| 36 | struct timespec ts[2]; |
| 37 | ts[0].tv_sec = tv[0].tv_sec; |
| 38 | ts[0].tv_nsec = tv[0].tv_usec * 1000; |
| 39 | ts[1].tv_sec = tv[1].tv_sec; |
| 40 | ts[1].tv_nsec = tv[1].tv_usec * 1000; |
| 41 | return syscall(__NR_utimensat, fd, NULL, ts, 0); |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 42 | } |
| 43 | |
primiano@chromium.org | 660e78b | 2014-04-29 09:05:57 +0900 | [diff] [blame] | 44 | #if !defined(__LP64__) |
| 45 | // 32-bit Android has only timegm64() and not timegm(). |
nileshagrawal@chromium.org | f9d216a | 2011-12-16 12:18:13 +0900 | [diff] [blame] | 46 | // We replicate the behaviour of timegm() when the result overflows time_t. |
| 47 | time_t timegm(struct tm* const t) { |
| 48 | // time_t is signed on Android. |
zhenyu.liang@intel.com | 0fa4b88 | 2014-03-19 21:00:47 +0900 | [diff] [blame] | 49 | static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1)); |
| 50 | static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1)); |
nileshagrawal@chromium.org | f9d216a | 2011-12-16 12:18:13 +0900 | [diff] [blame] | 51 | time64_t result = timegm64(t); |
| 52 | if (result < kTimeMin || result > kTimeMax) |
| 53 | return -1; |
| 54 | return result; |
| 55 | } |
primiano@chromium.org | 660e78b | 2014-04-29 09:05:57 +0900 | [diff] [blame] | 56 | #endif |
nileshagrawal@chromium.org | f9d216a | 2011-12-16 12:18:13 +0900 | [diff] [blame] | 57 | |
felipeg@chromium.org | 406c7ba | 2012-07-17 01:12:16 +0900 | [diff] [blame] | 58 | // The following is only needed when building with GCC 4.6 or higher |
| 59 | // (i.e. not with Android GCC 4.4.3, nor with Clang). |
| 60 | // |
| 61 | // GCC is now capable of optimizing successive calls to sin() and cos() into |
| 62 | // a single call to sincos(). This means that source code that looks like: |
| 63 | // |
| 64 | // double c, s; |
| 65 | // c = cos(angle); |
| 66 | // s = sin(angle); |
| 67 | // |
| 68 | // Will generate machine code that looks like: |
| 69 | // |
| 70 | // double c, s; |
| 71 | // sincos(angle, &s, &c); |
| 72 | // |
| 73 | // Unfortunately, sincos() and friends are not part of the Android libm.so |
| 74 | // library provided by the NDK for API level 9. When the optimization kicks |
| 75 | // in, it makes the final build fail with a puzzling message (puzzling |
| 76 | // because 'sincos' doesn't appear anywhere in the sources!). |
| 77 | // |
| 78 | // To solve this, we provide our own implementation of the sincos() function |
| 79 | // and related friends. Note that we must also explicitely tell GCC to disable |
| 80 | // optimizations when generating these. Otherwise, the generated machine code |
| 81 | // for each function would simply end up calling itself, resulting in a |
| 82 | // runtime crash due to stack overflow. |
| 83 | // |
torne@chromium.org | 21005a9 | 2013-08-29 04:41:50 +0900 | [diff] [blame] | 84 | #if defined(__GNUC__) && !defined(__clang__) && \ |
| 85 | !defined(ANDROID_SINCOS_PROVIDED) |
felipeg@chromium.org | 406c7ba | 2012-07-17 01:12:16 +0900 | [diff] [blame] | 86 | |
| 87 | // For the record, Clang does not support the 'optimize' attribute. |
| 88 | // In the unlikely event that it begins performing this optimization too, |
| 89 | // we'll have to find a different way to achieve this. NOTE: Tested with O1 |
| 90 | // which still performs the optimization. |
| 91 | // |
| 92 | #define GCC_NO_OPTIMIZE __attribute__((optimize("O0"))) |
| 93 | |
| 94 | GCC_NO_OPTIMIZE |
| 95 | void sincos(double angle, double* s, double *c) { |
| 96 | *c = cos(angle); |
| 97 | *s = sin(angle); |
| 98 | } |
| 99 | |
| 100 | GCC_NO_OPTIMIZE |
| 101 | void sincosf(float angle, float* s, float* c) { |
| 102 | *c = cosf(angle); |
| 103 | *s = sinf(angle); |
| 104 | } |
| 105 | |
| 106 | #endif // __GNUC__ && !__clang__ |
| 107 | |
| 108 | // An implementation of mkdtemp, since it is not exposed by the NDK |
| 109 | // for native API level 9 that we target. |
| 110 | // |
| 111 | // For any changes in the mkdtemp function, you should manually run the unittest |
| 112 | // OsCompatAndroidTest.DISABLED_TestMkdTemp in your local machine to check if it |
| 113 | // passes. Please don't enable it, since it creates a directory and may be |
| 114 | // source of flakyness. |
| 115 | char* mkdtemp(char* path) { |
| 116 | if (path == NULL) { |
| 117 | errno = EINVAL; |
| 118 | return NULL; |
| 119 | } |
| 120 | |
| 121 | const int path_len = strlen(path); |
| 122 | |
| 123 | // The last six characters of 'path' must be XXXXXX. |
| 124 | const base::StringPiece kSuffix("XXXXXX"); |
| 125 | const int kSuffixLen = kSuffix.length(); |
| 126 | if (!base::StringPiece(path, path_len).ends_with(kSuffix)) { |
| 127 | errno = EINVAL; |
| 128 | return NULL; |
| 129 | } |
| 130 | |
| 131 | // If the path contains a directory, as in /tmp/foo/XXXXXXXX, make sure |
| 132 | // that /tmp/foo exists, otherwise we're going to loop a really long |
| 133 | // time for nothing below |
| 134 | char* dirsep = strrchr(path, '/'); |
| 135 | if (dirsep != NULL) { |
| 136 | struct stat st; |
| 137 | int ret; |
| 138 | |
| 139 | *dirsep = '\0'; // Terminating directory path temporarily |
| 140 | |
| 141 | ret = stat(path, &st); |
| 142 | |
| 143 | *dirsep = '/'; // Restoring directory separator |
| 144 | if (ret < 0) // Directory probably does not exist |
| 145 | return NULL; |
| 146 | if (!S_ISDIR(st.st_mode)) { // Not a directory |
| 147 | errno = ENOTDIR; |
| 148 | return NULL; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | // Max number of tries using different random suffixes. |
| 153 | const int kMaxTries = 100; |
| 154 | |
| 155 | // Now loop until we CAN create a directory by that name or we reach the max |
| 156 | // number of tries. |
| 157 | for (int i = 0; i < kMaxTries; ++i) { |
| 158 | // Fill the suffix XXXXXX with a random string composed of a-z chars. |
| 159 | for (int pos = 0; pos < kSuffixLen; ++pos) { |
| 160 | char rand_char = static_cast<char>(base::RandInt('a', 'z')); |
| 161 | path[path_len - kSuffixLen + pos] = rand_char; |
| 162 | } |
| 163 | if (mkdir(path, 0700) == 0) { |
| 164 | // We just created the directory succesfully. |
| 165 | return path; |
| 166 | } |
| 167 | if (errno != EEXIST) { |
| 168 | // The directory doesn't exist, but an error occured |
| 169 | return NULL; |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | // We reached the max number of tries. |
| 174 | return NULL; |
| 175 | } |
| 176 | |
michaelbai@google.com | 2251c62 | 2011-06-22 07:34:50 +0900 | [diff] [blame] | 177 | } // extern "C" |