• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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__anon2131d8950111::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__anon2131d8950111::TickCountImpl109     ~TickCountImpl() {
110         mach_port_deallocate(mach_task_self(), mClockServ);
111     }
112 #endif
113 
getStartTimeUs__anon2131d8950111::TickCountImpl114     uint64_t getStartTimeUs() const {
115         return mStartTimeUs;
116     }
117 
getUs__anon2131d8950111::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 
fdStat(int fd,PathStat * st)181 int fdStat(int fd, PathStat* st) {
182 #ifdef _WIN32
183     return _fstat64(fd, st);
184 #else   // !_WIN32
185     return HANDLE_EINTR(fstat(fd, st));
186 #endif  // !_WIN32
187 }
188 
getFileSize(int fd,uint64_t * outFileSize)189 bool getFileSize(int fd, uint64_t* outFileSize) {
190     if (fd < 0) {
191         return false;
192     }
193     PathStat st;
194     int ret = fdStat(fd, &st);
195 #ifdef _WIN32
196     if (ret < 0 || !(st.st_mode & _S_IFREG)) {
197         return false;
198     }
199 #else
200     if (ret < 0 || !S_ISREG(st.st_mode)) {
201         return false;
202     }
203 #endif
204     // This is off_t on POSIX and a 32/64 bit integral type on windows based on
205     // the host / compiler combination. We cast everything to 64 bit unsigned to
206     // play safe.
207     *outFileSize = static_cast<FileSize>(st.st_size);
208     return true;
209 }
210 
sleepMs(uint64_t n)211 void sleepMs(uint64_t n) {
212 #ifdef _WIN32
213     ::Sleep(n);
214 #else
215     usleep(n * 1000);
216 #endif
217 }
218 
sleepUs(uint64_t n)219 void sleepUs(uint64_t n) {
220 #ifdef _WIN32
221     ::Sleep(n / 1000);
222 #else
223     usleep(n);
224 #endif
225 }
226 
sleepToUs(uint64_t absTimeUs)227 void sleepToUs(uint64_t absTimeUs) {
228     // Approach will vary based on platform.
229     //
230     // Linux/QNX has clock_nanosleep with TIMER_ABSTIME which does
231     // exactly what we want, a sleep to some absolute time.
232     //
233     // Mac only has relative nanosleep(), so we'll need to calculate a time
234     // difference.
235     //
236     // Windows has waitable timers. Pre Windows 10 1803, 1 ms was the best resolution. Past that, we can use high resolution waitable timers.
237 #ifdef __APPLE__
238     uint64_t current = getHighResTimeUs();
239 
240     // Already passed deadline, return.
241     if (absTimeUs < current) return;
242     uint64_t diff = absTimeUs - current;
243 
244     struct timespec ts;
245     ts.tv_sec = diff / 1000000ULL;
246     ts.tv_nsec = diff * 1000ULL - ts.tv_sec * 1000000000ULL;
247     int ret;
248     do {
249         ret = nanosleep(&ts, nullptr);
250     } while (ret == -1 && errno == EINTR);
251 #elif defined __linux__ || defined __QNX__
252     struct timespec ts;
253     ts.tv_sec = absTimeUs / 1000000ULL;
254     ts.tv_nsec = absTimeUs * 1000ULL - ts.tv_sec * 1000000000ULL;
255     int ret;
256     do {
257         ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr);
258     } while (ret == -1 && errno == EINTR);
259 #else // _WIN32
260 
261     // Create a persistent thread local timer object
262     struct ThreadLocalTimerState {
263         ThreadLocalTimerState() {
264             timerHandle = CreateWaitableTimerEx(
265                 nullptr /* no security attributes */,
266                 nullptr /* no timer name */,
267                 CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
268                 TIMER_ALL_ACCESS);
269 
270             if (!timerHandle) {
271                 // Use an older version of waitable timer as backup.
272                 timerHandle = CreateWaitableTimer(nullptr, FALSE, nullptr);
273             }
274         }
275 
276         ~ThreadLocalTimerState() {
277             if (timerHandle) {
278                 CloseHandle(timerHandle);
279             }
280         }
281 
282         HANDLE timerHandle = 0;
283     };
284 
285     static thread_local ThreadLocalTimerState tl_timerInfo;
286 
287     uint64_t current = getHighResTimeUs();
288     // Already passed deadline, return.
289     if (absTimeUs < current) return;
290     uint64_t diff = absTimeUs - current;
291 
292     // Waitable Timer appraoch
293 
294     // We failed to create ANY usable timer. Sleep instead.
295     if (!tl_timerInfo.timerHandle) {
296         Thread::sleepUs(diff);
297         return;
298     }
299 
300     LARGE_INTEGER dueTime;
301     dueTime.QuadPart = -1LL * diff * 10LL; // 1 us = 1x 100ns
302     SetWaitableTimer(
303         tl_timerInfo.timerHandle,
304         &dueTime,
305         0 /* one shot timer */,
306         0 /* no callback on finish */,
307         NULL /* no arg to completion routine */,
308         FALSE /* no suspend */);
309     WaitForSingleObject(tl_timerInfo.timerHandle, INFINITE);
310 #endif
311 }
312 
getUnixTimeUs()313 uint64_t getUnixTimeUs() {
314     timeval tv;
315     gettimeofday(&tv, nullptr);
316     return tv.tv_sec * 1000000LL + tv.tv_usec;
317 }
318 
getHighResTimeUs()319 uint64_t getHighResTimeUs() {
320     return kTickCount.getUs();
321 }
322 
getUptimeMs()323 uint64_t getUptimeMs() {
324     return (kTickCount.getUs() - kTickCount.getStartTimeUs()) / 1000;
325 }
326 
getProgramDirectoryFromPlatform()327 std::string getProgramDirectoryFromPlatform() {
328     std::string res;
329 #if defined(__linux__)
330     char path[1024];
331     memset(path, 0, sizeof(path));  // happy valgrind!
332     int len = readlink("/proc/self/exe", path, sizeof(path));
333     if (len > 0 && len < (int)sizeof(path)) {
334         char* x = ::strrchr(path, '/');
335         if (x) {
336             *x = '\0';
337             res.assign(path);
338         }
339     }
340 #elif defined(__APPLE__)
341     char s[PATH_MAX];
342     auto pid = getpid();
343     proc_pidpath(pid, s, sizeof(s));
344     char* x = ::strrchr(s, '/');
345     if (x) {
346         // skip all slashes - there might be more than one
347         while (x > s && x[-1] == '/') {
348             --x;
349         }
350         *x = '\0';
351         res.assign(s);
352     } else {
353         res.assign("<unknown-application-dir>");
354     }
355 #elif defined(_WIN32)
356     Win32UnicodeString appDir(PATH_MAX);
357     int len = GetModuleFileNameW(0, appDir.data(), appDir.size());
358     res.assign("<unknown-application-dir>");
359     if (len > 0) {
360         if (len > (int)appDir.size()) {
361             appDir.resize(static_cast<size_t>(len));
362             GetModuleFileNameW(0, appDir.data(), appDir.size());
363         }
364         std::string dir = appDir.toString();
365         char* sep = ::strrchr(&dir[0], '\\');
366         if (sep) {
367             *sep = '\0';
368             res.assign(dir.c_str());
369         }
370     }
371 #elif defined(__QNX__)
372     char path[1024];
373     memset(path, 0, sizeof(path));
374     int fd = open ("/proc/self/exefile", O_RDONLY);
375     if (fd != -1) {
376         ssize_t len = read(fd, path, sizeof(path));
377         if (len > 0 && len < sizeof(path)) {
378             char* x = ::strrchr(path, '/');
379             if (x) {
380                 *x = '\0';
381                 res.assign(path);
382             }
383         }
384         close(fd);
385     }
386 #else
387 #error "Unsupported platform!"
388 #endif
389     return res;
390 }
getProgramDirectory()391 std::string getProgramDirectory() {
392     static std::string progDir;
393     if (progDir.empty()) {
394         progDir.assign(getProgramDirectoryFromPlatform());
395     }
396     return progDir;
397 }
398 
getLauncherDirectory()399 std::string getLauncherDirectory() {
400     std::string launcherDirEnv = getEnvironmentVariable("ANDROID_EMULATOR_LAUNCHER_DIR");
401     if (!launcherDirEnv.empty()) {
402         return launcherDirEnv;
403     }
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