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