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