• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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