1 #include "aemu/base/EintrWrapper.h"
2 #include "aemu/base/StringFormat.h"
3 #include "aemu/base/system/System.h"
4 #include "aemu/base/threads/Thread.h"
5
6 #ifdef _WIN32
7 #include <windows.h>
8
9 #include "aemu/base/system/Win32UnicodeString.h"
10 #include "aemu/base/msvc.h"
11 #endif
12
13 #include <vector>
14
15 #ifdef __QNX__
16 #include <fcntl.h>
17 #include <devctl.h>
18 #include <sys/procfs.h>
19 #endif
20
21 #ifdef __APPLE__
22 #include <libproc.h>
23 #include <mach/clock.h>
24 #include <mach/mach.h>
25 #endif // __APPLE__
26
27 #ifdef _MSC_VER
28 // #include "msvc-posix.h"
29 // #include <dirent.h>
30 #else
31 #include <time.h>
32 #include <sys/time.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/resource.h>
36 #include <unistd.h>
37 #endif
38
39 #include <string.h>
40
41 using FileSize = uint64_t;
42
43 #ifdef _WIN32
44
45 using android::base::Win32UnicodeString;
46
47 // Return |path| as a Unicode string, while discarding trailing separators.
win32Path(const char * path)48 Win32UnicodeString win32Path(const char* path) {
49 Win32UnicodeString wpath(path);
50 // Get rid of trailing directory separators, Windows doesn't like them.
51 size_t size = wpath.size();
52 while (size > 0U &&
53 (wpath[size - 1U] == L'\\' || wpath[size - 1U] == L'/')) {
54 size--;
55 }
56 if (size < wpath.size()) {
57 wpath.resize(size);
58 }
59 return wpath;
60 }
61
62 using PathStat = struct _stat64;
63
64 #else // _WIN32
65
66 using PathStat = struct stat;
67
68 #endif // _WIN32
69
70 namespace {
71
72 struct TickCountImpl {
73 private:
74 uint64_t mStartTimeUs;
75 #ifdef _WIN32
76 long long mFreqPerSec = 0; // 0 means 'high perf counter isn't available'
77 #elif defined(__APPLE__)
78 clock_serv_t mClockServ;
79 #endif
80
81 public:
TickCountImpl__anonfc4080e40111::TickCountImpl82 TickCountImpl() {
83 #ifdef _WIN32
84 LARGE_INTEGER freq;
85 if (::QueryPerformanceFrequency(&freq)) {
86 mFreqPerSec = freq.QuadPart;
87 }
88 #elif defined(__APPLE__)
89 host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &mClockServ);
90 #endif
91 mStartTimeUs = getUs();
92 }
93
94 #ifdef __APPLE__
~TickCountImpl__anonfc4080e40111::TickCountImpl95 ~TickCountImpl() {
96 mach_port_deallocate(mach_task_self(), mClockServ);
97 }
98 #endif
99
getStartTimeUs__anonfc4080e40111::TickCountImpl100 uint64_t getStartTimeUs() const {
101 return mStartTimeUs;
102 }
103
getUs__anonfc4080e40111::TickCountImpl104 uint64_t getUs() const {
105 #ifdef _WIN32
106 if (!mFreqPerSec) {
107 return ::GetTickCount() * 1000;
108 }
109 LARGE_INTEGER now;
110 ::QueryPerformanceCounter(&now);
111 return (now.QuadPart * 1000000ULL) / mFreqPerSec;
112 #elif defined __linux__ || defined __QNX__
113 timespec ts;
114 clock_gettime(CLOCK_MONOTONIC, &ts);
115 return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
116 #else // APPLE
117 mach_timespec_t mts;
118 clock_get_time(mClockServ, &mts);
119 return mts.tv_sec * 1000000LL + mts.tv_nsec / 1000;
120 #endif
121 }
122 };
123
124 // This is, maybe, the only static variable that may not be a LazyInstance:
125 // it holds the actual timestamp at startup, and has to be initialized as
126 // soon as possible after the application launch.
127 static const TickCountImpl kTickCount;
128
129 } // namespace
130
131 namespace android {
132 namespace base {
133
getEnvironmentVariable(const std::string & key)134 std::string getEnvironmentVariable(const std::string& key) {
135 #ifdef _WIN32
136 Win32UnicodeString varname_unicode(key);
137 const wchar_t* value = _wgetenv(varname_unicode.c_str());
138 if (!value) {
139 return std::string();
140 } else {
141 return Win32UnicodeString::convertToUtf8(value);
142 }
143 #else
144 const char* value = getenv(key.c_str());
145 if (!value) {
146 value = "";
147 }
148 return std::string(value);
149 #endif
150 }
151
setEnvironmentVariable(const std::string & key,const std::string & value)152 void setEnvironmentVariable(const std::string& key, const std::string& value) {
153 #ifdef _WIN32
154 std::string envStr =
155 StringFormat("%s=%s", key, value);
156 // Note: this leaks the result of release().
157 _wputenv(Win32UnicodeString(envStr).release());
158 #else
159 if (value.empty()) {
160 unsetenv(key.c_str());
161 } else {
162 setenv(key.c_str(), value.c_str(), 1);
163 }
164 #endif
165 }
166
isVerboseLogging()167 bool isVerboseLogging() {
168 return false;
169 }
170
fdStat(int fd,PathStat * st)171 int fdStat(int fd, PathStat* st) {
172 #ifdef _WIN32
173 return _fstat64(fd, st);
174 #else // !_WIN32
175 return HANDLE_EINTR(fstat(fd, st));
176 #endif // !_WIN32
177 }
178
getFileSize(int fd,uint64_t * outFileSize)179 bool getFileSize(int fd, uint64_t* outFileSize) {
180 if (fd < 0) {
181 return false;
182 }
183 PathStat st;
184 int ret = fdStat(fd, &st);
185 #ifdef _WIN32
186 if (ret < 0 || !(st.st_mode & _S_IFREG)) {
187 return false;
188 }
189 #else
190 if (ret < 0 || !S_ISREG(st.st_mode)) {
191 return false;
192 }
193 #endif
194 // This is off_t on POSIX and a 32/64 bit integral type on windows based on
195 // the host / compiler combination. We cast everything to 64 bit unsigned to
196 // play safe.
197 *outFileSize = static_cast<FileSize>(st.st_size);
198 return true;
199 }
200
sleepMs(uint64_t n)201 void sleepMs(uint64_t n) {
202 #ifdef _WIN32
203 ::Sleep(n);
204 #else
205 usleep(n * 1000);
206 #endif
207 }
208
sleepUs(uint64_t n)209 void sleepUs(uint64_t n) {
210 #ifdef _WIN32
211 ::Sleep(n / 1000);
212 #else
213 usleep(n);
214 #endif
215 }
216
sleepToUs(uint64_t absTimeUs)217 void sleepToUs(uint64_t absTimeUs) {
218 // Approach will vary based on platform.
219 //
220 // Linux has clock_nanosleep with TIMER_ABSTIME which does
221 // exactly what we want, a sleep to some absolute time.
222 //
223 // Mac only has relative nanosleep(), so we'll need to calculate a time
224 // difference.
225 //
226 // Windows has waitable timers. Pre Windows 10 1803, 1 ms was the best resolution. Past that, we can use high resolution waitable timers.
227 #ifdef __APPLE__
228 uint64_t current = getHighResTimeUs();
229
230 // Already passed deadline, return.
231 if (absTimeUs < current) return;
232 uint64_t diff = absTimeUs - current;
233
234 struct timespec ts;
235 ts.tv_sec = diff / 1000000ULL;
236 ts.tv_nsec = diff * 1000ULL - ts.tv_sec * 1000000000ULL;
237 int ret;
238 do {
239 ret = nanosleep(&ts, nullptr);
240 } while (ret == -1 && errno == EINTR);
241 #elif defined(__linux__)
242 struct timespec ts;
243 ts.tv_sec = absTimeUs / 1000000ULL;
244 ts.tv_nsec = absTimeUs * 1000ULL - ts.tv_sec * 1000000000ULL;
245 int ret;
246 do {
247 ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr);
248 } while (ret == -1 && errno == EINTR);
249 #else // _WIN32
250
251 // Create a persistent thread local timer object
252 struct ThreadLocalTimerState {
253 ThreadLocalTimerState() {
254 timerHandle = CreateWaitableTimerEx(
255 nullptr /* no security attributes */,
256 nullptr /* no timer name */,
257 CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
258 TIMER_ALL_ACCESS);
259
260 if (!timerHandle) {
261 // Use an older version of waitable timer as backup.
262 timerHandle = CreateWaitableTimer(nullptr, FALSE, nullptr);
263 }
264 }
265
266 ~ThreadLocalTimerState() {
267 if (timerHandle) {
268 CloseHandle(timerHandle);
269 }
270 }
271
272 HANDLE timerHandle = 0;
273 };
274
275 static thread_local ThreadLocalTimerState tl_timerInfo;
276
277 uint64_t current = getHighResTimeUs();
278 // Already passed deadline, return.
279 if (absTimeUs < current) return;
280 uint64_t diff = absTimeUs - current;
281
282 // Waitable Timer appraoch
283
284 // We failed to create ANY usable timer. Sleep instead.
285 if (!tl_timerInfo.timerHandle) {
286 Thread::sleepUs(diff);
287 return;
288 }
289
290 LARGE_INTEGER dueTime;
291 dueTime.QuadPart = -1LL * diff * 10LL; // 1 us = 1x 100ns
292 SetWaitableTimer(
293 tl_timerInfo.timerHandle,
294 &dueTime,
295 0 /* one shot timer */,
296 0 /* no callback on finish */,
297 NULL /* no arg to completion routine */,
298 FALSE /* no suspend */);
299 WaitForSingleObject(tl_timerInfo.timerHandle, INFINITE);
300 #endif
301 }
302
getUnixTimeUs()303 uint64_t getUnixTimeUs() {
304 timeval tv;
305 gettimeofday(&tv, nullptr);
306 return tv.tv_sec * 1000000LL + tv.tv_usec;
307 }
308
getHighResTimeUs()309 uint64_t getHighResTimeUs() {
310 return kTickCount.getUs();
311 }
312
getUptimeMs()313 uint64_t getUptimeMs() {
314 return (kTickCount.getUs() - kTickCount.getStartTimeUs()) / 1000;
315 }
316
getProgramDirectoryFromPlatform()317 std::string getProgramDirectoryFromPlatform() {
318 std::string res;
319 #if defined(__linux__)
320 char path[1024];
321 memset(path, 0, sizeof(path)); // happy valgrind!
322 int len = readlink("/proc/self/exe", path, sizeof(path));
323 if (len > 0 && len < (int)sizeof(path)) {
324 char* x = ::strrchr(path, '/');
325 if (x) {
326 *x = '\0';
327 res.assign(path);
328 }
329 }
330 #elif defined(__APPLE__)
331 char s[PATH_MAX];
332 auto pid = getpid();
333 proc_pidpath(pid, s, sizeof(s));
334 char* x = ::strrchr(s, '/');
335 if (x) {
336 // skip all slashes - there might be more than one
337 while (x > s && x[-1] == '/') {
338 --x;
339 }
340 *x = '\0';
341 res.assign(s);
342 } else {
343 res.assign("<unknown-application-dir>");
344 }
345 #elif defined(_WIN32)
346 Win32UnicodeString appDir(PATH_MAX);
347 int len = GetModuleFileNameW(0, appDir.data(), appDir.size());
348 res.assign("<unknown-application-dir>");
349 if (len > 0) {
350 if (len > (int)appDir.size()) {
351 appDir.resize(static_cast<size_t>(len));
352 GetModuleFileNameW(0, appDir.data(), appDir.size());
353 }
354 std::string dir = appDir.toString();
355 char* sep = ::strrchr(&dir[0], '\\');
356 if (sep) {
357 *sep = '\0';
358 res.assign(dir.c_str());
359 }
360 }
361 #elif defined(__QNX__)
362 char path[1024];
363 memset(path, 0, sizeof(path));
364 int fd = open ("/proc/self/exefile", O_RDONLY);
365 if (fd != -1) {
366 ssize_t len = read(fd, path, sizeof(path));
367 if (len > 0 && len < sizeof(path)) {
368 char* x = ::strrchr(path, '/');
369 if (x) {
370 *x = '\0';
371 res.assign(path);
372 }
373 }
374 close(fd);
375 }
376 #else
377 #error "Unsupported platform!"
378 #endif
379 return res;
380 }
getProgramDirectory()381 std::string getProgramDirectory() {
382 static std::string progDir;
383 if (progDir.empty()) {
384 progDir.assign(getProgramDirectoryFromPlatform());
385 }
386 return progDir;
387 }
388
getLauncherDirectory()389 std::string getLauncherDirectory() {
390 return getProgramDirectory();
391 }
392
393 #ifdef __APPLE__
394 void cpuUsageCurrentThread_macImpl(uint64_t* user, uint64_t* sys);
395 #endif // __APPLE__
396
cpuTime()397 CpuTime cpuTime() {
398 CpuTime res;
399
400 res.wall_time_us = kTickCount.getUs();
401
402 #ifdef __APPLE__
403 cpuUsageCurrentThread_macImpl(
404 &res.user_time_us,
405 &res.system_time_us);
406 #elif __linux__
407 struct rusage usage;
408 getrusage(RUSAGE_THREAD, &usage);
409 res.user_time_us =
410 usage.ru_utime.tv_sec * 1000000ULL +
411 usage.ru_utime.tv_usec;
412 res.system_time_us =
413 usage.ru_stime.tv_sec * 1000000ULL +
414 usage.ru_stime.tv_usec;
415 #elif __QNX__
416 int fd = open("/proc/self/as", O_RDONLY);
417 if (fd != -1) {
418 procfs_info info;
419 if (devctl(fd, DCMD_PROC_INFO, &info, sizeof(info), NULL) == EOK) {
420 res.user_time_us = info.utime / 1000; // time is in nanoseconds
421 res.system_time_us = info.stime / 1000;
422 }
423 close(fd);
424 }
425 #else // Windows
426 FILETIME creation_time_struct;
427 FILETIME exit_time_struct;
428 FILETIME kernel_time_struct;
429 FILETIME user_time_struct;
430 GetThreadTimes(
431 GetCurrentThread(),
432 &creation_time_struct,
433 &exit_time_struct,
434 &kernel_time_struct,
435 &user_time_struct);
436 (void)creation_time_struct;
437 (void)exit_time_struct;
438 uint64_t user_time_100ns =
439 user_time_struct.dwLowDateTime |
440 ((uint64_t)user_time_struct.dwHighDateTime << 32);
441 uint64_t system_time_100ns =
442 kernel_time_struct.dwLowDateTime |
443 ((uint64_t)kernel_time_struct.dwHighDateTime << 32);
444 res.user_time_us = user_time_100ns / 10;
445 res.system_time_us = system_time_100ns / 10;
446 #endif
447
448 return res;
449 }
450
451
452 #ifdef _WIN32
453 // Based on chromium/src/base/file_version_info_win.cc's CreateFileVersionInfoWin
454 // Currently used to query Vulkan DLL's on the system and blacklist known
455 // problematic DLLs
456 // static
457 // Windows 10 funcs
458 typedef DWORD (*get_file_version_info_size_w_t)(LPCWSTR, LPDWORD);
459 typedef DWORD (*get_file_version_info_w_t)(LPCWSTR, DWORD, DWORD, LPVOID);
460 // Windows 8 funcs
461 typedef DWORD (*get_file_version_info_size_ex_w_t)(DWORD, LPCWSTR, LPDWORD);
462 typedef DWORD (*get_file_version_info_ex_w_t)(DWORD, LPCWSTR, DWORD, DWORD, LPVOID);
463 // common
464 typedef int (*ver_query_value_w_t)(LPCVOID, LPCWSTR, LPVOID, PUINT);
465 static get_file_version_info_size_w_t getFileVersionInfoSizeW_func = 0;
466 static get_file_version_info_w_t getFileVersionInfoW_func = 0;
467 static get_file_version_info_size_ex_w_t getFileVersionInfoSizeExW_func = 0;
468 static get_file_version_info_ex_w_t getFileVersionInfoExW_func = 0;
469 static ver_query_value_w_t verQueryValueW_func = 0;
470 static bool getFileVersionInfoFuncsAvailable = false;
471 static bool getFileVersionInfoExFuncsAvailable = false;
472 static bool canQueryFileVersion = false;
473
initFileVersionInfoFuncs()474 bool initFileVersionInfoFuncs() {
475 // LOG(VERBOSE) << "querying file version info API...";
476 if (canQueryFileVersion) return true;
477 HMODULE kernelLib = GetModuleHandleA("kernelbase");
478 if (!kernelLib) return false;
479 // LOG(VERBOSE) << "found kernelbase.dll";
480 getFileVersionInfoSizeW_func =
481 (get_file_version_info_size_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoSizeW");
482 if (!getFileVersionInfoSizeW_func) {
483 // LOG(VERBOSE) << "GetFileVersionInfoSizeW not found. Not on Windows 10?";
484 } else {
485 // LOG(VERBOSE) << "GetFileVersionInfoSizeW found. On Windows 10?";
486 }
487 getFileVersionInfoW_func =
488 (get_file_version_info_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoW");
489 if (!getFileVersionInfoW_func) {
490 // LOG(VERBOSE) << "GetFileVersionInfoW not found. Not on Windows 10?";
491 } else {
492 // LOG(VERBOSE) << "GetFileVersionInfoW found. On Windows 10?";
493 }
494 getFileVersionInfoFuncsAvailable =
495 getFileVersionInfoSizeW_func && getFileVersionInfoW_func;
496 if (!getFileVersionInfoFuncsAvailable) {
497 getFileVersionInfoSizeExW_func =
498 (get_file_version_info_size_ex_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoSizeExW");
499 getFileVersionInfoExW_func =
500 (get_file_version_info_ex_w_t)GetProcAddress(kernelLib, "GetFileVersionInfoExW");
501 getFileVersionInfoExFuncsAvailable =
502 getFileVersionInfoSizeExW_func && getFileVersionInfoExW_func;
503 }
504 if (!getFileVersionInfoFuncsAvailable &&
505 !getFileVersionInfoExFuncsAvailable) {
506 // LOG(VERBOSE) << "Cannot get file version info funcs";
507 return false;
508 }
509 verQueryValueW_func =
510 (ver_query_value_w_t)GetProcAddress(kernelLib, "VerQueryValueW");
511 if (!verQueryValueW_func) {
512 // LOG(VERBOSE) << "VerQueryValueW not found";
513 return false;
514 }
515 // LOG(VERBOSE) << "VerQueryValueW found. Can query file versions";
516 canQueryFileVersion = true;
517 return true;
518 }
519
queryFileVersionInfo(const char * path,int * major,int * minor,int * build_1,int * build_2)520 bool queryFileVersionInfo(const char* path, int* major, int* minor, int* build_1, int* build_2) {
521 if (!initFileVersionInfoFuncs()) return false;
522 if (!canQueryFileVersion) return false;
523 const Win32UnicodeString pathWide(path);
524 DWORD dummy;
525 DWORD length = 0;
526 const DWORD fileVerGetNeutral = 0x02;
527 if (getFileVersionInfoFuncsAvailable) {
528 length = getFileVersionInfoSizeW_func(pathWide.c_str(), &dummy);
529 } else if (getFileVersionInfoExFuncsAvailable) {
530 length = getFileVersionInfoSizeExW_func(fileVerGetNeutral, pathWide.c_str(), &dummy);
531 }
532 if (length == 0) {
533 // LOG(VERBOSE) << "queryFileVersionInfo: path not found: " << path.str().c_str();
534 return false;
535 }
536 std::vector<uint8_t> data(length, 0);
537 if (getFileVersionInfoFuncsAvailable) {
538 if (!getFileVersionInfoW_func(pathWide.c_str(), dummy, length, data.data())) {
539 // LOG(VERBOSE) << "GetFileVersionInfoW failed";
540 return false;
541 }
542 } else if (getFileVersionInfoExFuncsAvailable) {
543 if (!getFileVersionInfoExW_func(fileVerGetNeutral, pathWide.c_str(), dummy, length, data.data())) {
544 // LOG(VERBOSE) << "GetFileVersionInfoExW failed";
545 return false;
546 }
547 }
548 VS_FIXEDFILEINFO* fixedFileInfo = nullptr;
549 UINT fixedFileInfoLength;
550 if (!verQueryValueW_func(
551 data.data(),
552 L"\\",
553 reinterpret_cast<void**>(&fixedFileInfo),
554 &fixedFileInfoLength)) {
555 // LOG(VERBOSE) << "VerQueryValueW failed";
556 return false;
557 }
558 if (major) *major = HIWORD(fixedFileInfo->dwFileVersionMS);
559 if (minor) *minor = LOWORD(fixedFileInfo->dwFileVersionMS);
560 if (build_1) *build_1 = HIWORD(fixedFileInfo->dwFileVersionLS);
561 if (build_2) *build_2 = LOWORD(fixedFileInfo->dwFileVersionLS);
562 return true;
563 }
564 #else
queryFileVersionInfo(const char *,int *,int *,int *,int *)565 bool queryFileVersionInfo(const char*, int*, int*, int*, int*) {
566 return false;
567 }
568 #endif // _WIN32
569
getCpuCoreCount()570 int getCpuCoreCount() {
571 #ifdef _WIN32
572 SYSTEM_INFO si = {};
573 ::GetSystemInfo(&si);
574 return si.dwNumberOfProcessors < 1 ? 1 : si.dwNumberOfProcessors;
575 #else
576 auto res = (int)sysconf(_SC_NPROCESSORS_ONLN);
577 return res < 1 ? 1 : res;
578 #endif
579 }
580
581 } // namespace base
582 } // namespace android
583