1 #include "base/EintrWrapper.h"
2 #include "base/StringFormat.h"
3 #include "base/System.h"
4
5 #ifdef _WIN32
6 #include "base/Win32UnicodeString.h"
7 #include <windows.h>
8 #include "msvc.h"
9 #endif
10
11 #include <vector>
12
13 #ifdef _MSC_VER
14 // #include "msvc-posix.h"
15 // #include <dirent.h>
16 #else
17 #include <time.h>
18 #include <sys/time.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/resource.h>
22 #include <unistd.h>
23 #endif
24
25 #include <string.h>
26
27 using FileSize = uint64_t;
28
29 #ifdef _WIN32
30
31 using android::base::Win32UnicodeString;
32
33 // Return |path| as a Unicode string, while discarding trailing separators.
win32Path(const char * path)34 Win32UnicodeString win32Path(const char* path) {
35 Win32UnicodeString wpath(path);
36 // Get rid of trailing directory separators, Windows doesn't like them.
37 size_t size = wpath.size();
38 while (size > 0U &&
39 (wpath[size - 1U] == L'\\' || wpath[size - 1U] == L'/')) {
40 size--;
41 }
42 if (size < wpath.size()) {
43 wpath.resize(size);
44 }
45 return wpath;
46 }
47
48 using PathStat = struct _stat64;
49
50 #else // _WIN32
51
52 using PathStat = struct stat;
53
54 #endif // _WIN32
55
56 namespace {
57
58 struct TickCountImpl {
59 private:
60 uint64_t mStartTimeUs;
61 #ifdef _WIN32
62 long long mFreqPerSec = 0; // 0 means 'high perf counter isn't available'
63 #elif defined(__APPLE__)
64 clock_serv_t mClockServ;
65 #endif
66
67 public:
TickCountImpl__anon5e8443ea0111::TickCountImpl68 TickCountImpl() {
69 #ifdef _WIN32
70 LARGE_INTEGER freq;
71 if (::QueryPerformanceFrequency(&freq)) {
72 mFreqPerSec = freq.QuadPart;
73 }
74 #elif defined(__APPLE__)
75 host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &mClockServ);
76 #endif
77 mStartTimeUs = getUs();
78 }
79
80 #ifdef __APPLE__
~TickCountImpl__anon5e8443ea0111::TickCountImpl81 ~TickCountImpl() {
82 mach_port_deallocate(mach_task_self(), mClockServ);
83 }
84 #endif
85
getStartTimeUs__anon5e8443ea0111::TickCountImpl86 uint64_t getStartTimeUs() const {
87 return mStartTimeUs;
88 }
89
getUs__anon5e8443ea0111::TickCountImpl90 uint64_t getUs() const {
91 #ifdef _WIN32
92 if (!mFreqPerSec) {
93 return ::GetTickCount() * 1000;
94 }
95 LARGE_INTEGER now;
96 ::QueryPerformanceCounter(&now);
97 return (now.QuadPart * 1000000ull) / mFreqPerSec;
98 #elif defined __linux__
99 timespec ts;
100 clock_gettime(CLOCK_MONOTONIC, &ts);
101 return ts.tv_sec * 1000000ll + ts.tv_nsec / 1000;
102 #else // APPLE
103 mach_timespec_t mts;
104 clock_get_time(mClockServ, &mts);
105 return mts.tv_sec * 1000000ll + mts.tv_nsec / 1000;
106 #endif
107 }
108 };
109
110 // This is, maybe, the only static variable that may not be a LazyInstance:
111 // it holds the actual timestamp at startup, and has to be initialized as
112 // soon as possible after the application launch.
113 static const TickCountImpl kTickCount;
114
115 } // namespace
116
117 namespace android {
118 namespace base {
119
getEnvironmentVariable(const std::string & key)120 std::string getEnvironmentVariable(const std::string& key) {
121 #ifdef _WIN32
122 Win32UnicodeString varname_unicode(key);
123 const wchar_t* value = _wgetenv(varname_unicode.c_str());
124 if (!value) {
125 return std::string();
126 } else {
127 return Win32UnicodeString::convertToUtf8(value);
128 }
129 #else
130 const char* value = getenv(key.c_str());
131 if (!value) {
132 value = "";
133 }
134 return std::string(value);
135 #endif
136 }
137
setEnvironmentVariable(const std::string & key,const std::string & value)138 void setEnvironmentVariable(const std::string& key, const std::string& value) {
139 #ifdef _WIN32
140 std::string envStr =
141 StringFormat("%s=%s", key, value);
142 // Note: this leaks the result of release().
143 _wputenv(Win32UnicodeString(envStr).release());
144 #else
145 if (value.empty()) {
146 unsetenv(key.c_str());
147 } else {
148 setenv(key.c_str(), value.c_str(), 1);
149 }
150 #endif
151 }
152
isVerboseLogging()153 bool isVerboseLogging() {
154 return false;
155 }
156
fdStat(int fd,PathStat * st)157 int fdStat(int fd, PathStat* st) {
158 #ifdef _WIN32
159 return _fstat64(fd, st);
160 #else // !_WIN32
161 return HANDLE_EINTR(fstat(fd, st));
162 #endif // !_WIN32
163 }
164
getFileSize(int fd,uint64_t * outFileSize)165 bool getFileSize(int fd, uint64_t* outFileSize) {
166 if (fd < 0) {
167 return false;
168 }
169 PathStat st;
170 int ret = fdStat(fd, &st);
171 #ifdef _WIN32
172 if (ret < 0 || !(st.st_mode & _S_IFREG)) {
173 return false;
174 }
175 #else
176 if (ret < 0 || !S_ISREG(st.st_mode)) {
177 return false;
178 }
179 #endif
180 // This is off_t on POSIX and a 32/64 bit integral type on windows based on
181 // the host / compiler combination. We cast everything to 64 bit unsigned to
182 // play safe.
183 *outFileSize = static_cast<FileSize>(st.st_size);
184 return true;
185 }
186
sleepMs(uint64_t n)187 void sleepMs(uint64_t n) {
188 #ifdef _WIN32
189 ::Sleep(n);
190 #else
191 usleep(n * 1000);
192 #endif
193 }
194
sleepUs(uint64_t n)195 void sleepUs(uint64_t n) {
196 #ifdef _WIN32
197 ::Sleep(n / 1000);
198 #else
199 usleep(n);
200 #endif
201 }
202
getUnixTimeUs()203 uint64_t getUnixTimeUs() {
204 timeval tv;
205 gettimeofday(&tv, nullptr);
206 return tv.tv_sec * 1000000LL + tv.tv_usec;
207 }
208
getHighResTimeUs()209 uint64_t getHighResTimeUs() {
210 return kTickCount.getUs();
211 }
212
getUptimeMs()213 uint64_t getUptimeMs() {
214 return (kTickCount.getUs() - kTickCount.getStartTimeUs()) / 1000;
215 }
216
getProgramDirectoryFromPlatform()217 std::string getProgramDirectoryFromPlatform() {
218 std::string res;
219 #if defined(__linux__)
220 char path[1024];
221 memset(path, 0, sizeof(path)); // happy valgrind!
222 int len = readlink("/proc/self/exe", path, sizeof(path));
223 if (len > 0 && len < (int)sizeof(path)) {
224 char* x = ::strrchr(path, '/');
225 if (x) {
226 *x = '\0';
227 res.assign(path);
228 }
229 }
230 #elif defined(__APPLE__)
231 char s[PATH_MAX];
232 auto pid = getpid();
233 proc_pidpath(pid, s, sizeof(s));
234 char* x = ::strrchr(s, '/');
235 if (x) {
236 // skip all slashes - there might be more than one
237 while (x > s && x[-1] == '/') {
238 --x;
239 }
240 *x = '\0';
241 res.assign(s);
242 } else {
243 res.assign("<unknown-application-dir>");
244 }
245 #elif defined(_WIN32)
246 Win32UnicodeString appDir(PATH_MAX);
247 int len = GetModuleFileNameW(0, appDir.data(), appDir.size());
248 res.assign("<unknown-application-dir>");
249 if (len > 0) {
250 if (len > (int)appDir.size()) {
251 appDir.resize(static_cast<size_t>(len));
252 GetModuleFileNameW(0, appDir.data(), appDir.size());
253 }
254 std::string dir = appDir.toString();
255 char* sep = ::strrchr(&dir[0], '\\');
256 if (sep) {
257 *sep = '\0';
258 res.assign(dir.c_str());
259 }
260 }
261 #else
262 #error "Unsupported platform!"
263 #endif
264 return res;
265 }
getProgramDirectory()266 std::string getProgramDirectory() {
267 static std::string progDir;
268 if (progDir.empty()) {
269 progDir.assign(getProgramDirectoryFromPlatform());
270 }
271 return progDir;
272 }
273
getLauncherDirectory()274 std::string getLauncherDirectory() {
275 return getProgramDirectory();
276 }
277
cpuTime()278 CpuTime cpuTime() {
279 CpuTime res;
280
281 res.wall_time_us = kTickCount.getUs();
282
283 #ifdef __APPLE__
284 cpuUsageCurrentThread_macImpl(
285 &res.user_time_us,
286 &res.system_time_us);
287 #else
288
289 #ifdef __linux__
290 struct rusage usage;
291 getrusage(RUSAGE_THREAD, &usage);
292 res.user_time_us =
293 usage.ru_utime.tv_sec * 1000000ULL +
294 usage.ru_utime.tv_usec;
295 res.system_time_us =
296 usage.ru_stime.tv_sec * 1000000ULL +
297 usage.ru_stime.tv_usec;
298 #else // Windows
299 FILETIME creation_time_struct;
300 FILETIME exit_time_struct;
301 FILETIME kernel_time_struct;
302 FILETIME user_time_struct;
303 GetThreadTimes(
304 GetCurrentThread(),
305 &creation_time_struct,
306 &exit_time_struct,
307 &kernel_time_struct,
308 &user_time_struct);
309 (void)creation_time_struct;
310 (void)exit_time_struct;
311 uint64_t user_time_100ns =
312 user_time_struct.dwLowDateTime |
313 ((uint64_t)user_time_struct.dwHighDateTime << 32);
314 uint64_t system_time_100ns =
315 kernel_time_struct.dwLowDateTime |
316 ((uint64_t)kernel_time_struct.dwHighDateTime << 32);
317 res.user_time_us = user_time_100ns / 10;
318 res.system_time_us = system_time_100ns / 10;
319 #endif
320
321 #endif
322 return res;
323 }
324
325
326 #ifdef _WIN32
327 // Based on chromium/src/base/file_version_info_win.cc's CreateFileVersionInfoWin
328 // Currently used to query Vulkan DLL's on the system and blacklist known
329 // problematic DLLs
330 // static
331 // Windows 10 funcs
332 typedef DWORD (*get_file_version_info_size_w_t)(LPCWSTR, LPDWORD);
333 typedef DWORD (*get_file_version_info_w_t)(LPCWSTR, DWORD, DWORD, LPVOID);
334 // Windows 8 funcs
335 typedef DWORD (*get_file_version_info_size_ex_w_t)(DWORD, LPCWSTR, LPDWORD);
336 typedef DWORD (*get_file_version_info_ex_w_t)(DWORD, LPCWSTR, DWORD, DWORD, LPVOID);
337 // common
338 typedef int (*ver_query_value_w_t)(LPCVOID, LPCWSTR, LPVOID, PUINT);
339 static get_file_version_info_size_w_t getFileVersionInfoSizeW_func = 0;
340 static get_file_version_info_w_t getFileVersionInfoW_func = 0;
341 static get_file_version_info_size_ex_w_t getFileVersionInfoSizeExW_func = 0;
342 static get_file_version_info_ex_w_t getFileVersionInfoExW_func = 0;
343 static ver_query_value_w_t verQueryValueW_func = 0;
344 static bool getFileVersionInfoFuncsAvailable = false;
345 static bool getFileVersionInfoExFuncsAvailable = false;
346 static bool canQueryFileVersion = false;
347
initFileVersionInfoFuncs()348 bool initFileVersionInfoFuncs() {
349 // LOG(VERBOSE) << "querying file version info API...";
350 if (canQueryFileVersion) return true;
351 HMODULE kernelLib = GetModuleHandleA("kernelbase");
352 if (!kernelLib) return false;
353 // LOG(VERBOSE) << "found kernelbase.dll";
354 getFileVersionInfoSizeW_func =
355 (get_file_version_info_size_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoSizeW");
356 if (!getFileVersionInfoSizeW_func) {
357 // LOG(VERBOSE) << "GetFileVersionInfoSizeW not found. Not on Windows 10?";
358 } else {
359 // LOG(VERBOSE) << "GetFileVersionInfoSizeW found. On Windows 10?";
360 }
361 getFileVersionInfoW_func =
362 (get_file_version_info_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoW");
363 if (!getFileVersionInfoW_func) {
364 // LOG(VERBOSE) << "GetFileVersionInfoW not found. Not on Windows 10?";
365 } else {
366 // LOG(VERBOSE) << "GetFileVersionInfoW found. On Windows 10?";
367 }
368 getFileVersionInfoFuncsAvailable =
369 getFileVersionInfoSizeW_func && getFileVersionInfoW_func;
370 if (!getFileVersionInfoFuncsAvailable) {
371 getFileVersionInfoSizeExW_func =
372 (get_file_version_info_size_ex_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoSizeExW");
373 getFileVersionInfoExW_func =
374 (get_file_version_info_ex_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoExW");
375 getFileVersionInfoExFuncsAvailable =
376 getFileVersionInfoSizeExW_func && getFileVersionInfoExW_func;
377 }
378 if (!getFileVersionInfoFuncsAvailable &&
379 !getFileVersionInfoExFuncsAvailable) {
380 // LOG(VERBOSE) << "Cannot get file version info funcs";
381 return false;
382 }
383 verQueryValueW_func =
384 (ver_query_value_w_t)GetProcAddress(kernelLib, "VerQueryValueW");
385 if (!verQueryValueW_func) {
386 // LOG(VERBOSE) << "VerQueryValueW not found";
387 return false;
388 }
389 // LOG(VERBOSE) << "VerQueryValueW found. Can query file versions";
390 canQueryFileVersion = true;
391 return true;
392 }
393
queryFileVersionInfo(const char * path,int * major,int * minor,int * build_1,int * build_2)394 bool queryFileVersionInfo(const char* path, int* major, int* minor, int* build_1, int* build_2) {
395 if (!initFileVersionInfoFuncs()) return false;
396 if (!canQueryFileVersion) return false;
397 const Win32UnicodeString pathWide(path);
398 DWORD dummy;
399 DWORD length = 0;
400 const DWORD fileVerGetNeutral = 0x02;
401 if (getFileVersionInfoFuncsAvailable) {
402 length = getFileVersionInfoSizeW_func(pathWide.c_str(), &dummy);
403 } else if (getFileVersionInfoExFuncsAvailable) {
404 length = getFileVersionInfoSizeExW_func(fileVerGetNeutral, pathWide.c_str(), &dummy);
405 }
406 if (length == 0) {
407 // LOG(VERBOSE) << "queryFileVersionInfo: path not found: " << path.str().c_str();
408 return false;
409 }
410 std::vector<uint8_t> data(length, 0);
411 if (getFileVersionInfoFuncsAvailable) {
412 if (!getFileVersionInfoW_func(pathWide.c_str(), dummy, length, data.data())) {
413 // LOG(VERBOSE) << "GetFileVersionInfoW failed";
414 return false;
415 }
416 } else if (getFileVersionInfoExFuncsAvailable) {
417 if (!getFileVersionInfoExW_func(fileVerGetNeutral, pathWide.c_str(), dummy, length, data.data())) {
418 // LOG(VERBOSE) << "GetFileVersionInfoExW failed";
419 return false;
420 }
421 }
422 VS_FIXEDFILEINFO* fixedFileInfo = nullptr;
423 UINT fixedFileInfoLength;
424 if (!verQueryValueW_func(
425 data.data(),
426 L"\\",
427 reinterpret_cast<void**>(&fixedFileInfo),
428 &fixedFileInfoLength)) {
429 // LOG(VERBOSE) << "VerQueryValueW failed";
430 return false;
431 }
432 if (major) *major = HIWORD(fixedFileInfo->dwFileVersionMS);
433 if (minor) *minor = LOWORD(fixedFileInfo->dwFileVersionMS);
434 if (build_1) *build_1 = HIWORD(fixedFileInfo->dwFileVersionLS);
435 if (build_2) *build_2 = LOWORD(fixedFileInfo->dwFileVersionLS);
436 return true;
437 }
438 #else
queryFileVersionInfo(const char *,int *,int *,int *,int *)439 bool queryFileVersionInfo(const char*, int*, int*, int*, int*) {
440 return false;
441 }
442 #endif // _WIN32
443
getCpuCoreCount()444 int getCpuCoreCount() {
445 #ifdef _WIN32
446 SYSTEM_INFO si = {};
447 ::GetSystemInfo(&si);
448 return si.dwNumberOfProcessors < 1 ? 1 : si.dwNumberOfProcessors;
449 #else
450 auto res = (int)sysconf(_SC_NPROCESSORS_ONLN);
451 return res < 1 ? 1 : res;
452 #endif
453 }
454
455 } // namespace base
456 } // namespace android
457