system_utils.cpp (8853B)
1 // 2 // Copyright 2018 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // system_utils.cpp: Implementation of common functions 8 9 #include "common/system_utils.h" 10 #include "common/debug.h" 11 12 #include <stdlib.h> 13 #include <atomic> 14 15 #if defined(ANGLE_PLATFORM_ANDROID) 16 # include <sys/system_properties.h> 17 #endif 18 19 #if defined(ANGLE_PLATFORM_APPLE) 20 # include <dispatch/dispatch.h> 21 # include <pthread.h> 22 #endif 23 24 namespace angle 25 { 26 std::string GetExecutableName() 27 { 28 #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 21 29 // Support for "getprogname" function in bionic was introduced in L (API level 21) 30 const char *executableName = getprogname(); 31 return (executableName) ? std::string(executableName) : "ANGLE"; 32 #else 33 std::string executableName = GetExecutablePath(); 34 size_t lastPathSepLoc = executableName.find_last_of(GetPathSeparator()); 35 return (lastPathSepLoc > 0 ? executableName.substr(lastPathSepLoc + 1, executableName.length()) 36 : "ANGLE"); 37 #endif // ANGLE_PLATFORM_ANDROID 38 } 39 40 // On Android return value cached in the process environment, if none, call 41 // GetEnvironmentVarOrUnCachedAndroidProperty if not in environment. 42 std::string GetEnvironmentVarOrAndroidProperty(const char *variableName, const char *propertyName) 43 { 44 #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 21 45 // Can't use GetEnvironmentVar here because that won't allow us to distinguish between the 46 // environment being set to an empty string vs. not set at all. 47 const char *variableValue = getenv(variableName); 48 if (variableValue != nullptr) 49 { 50 std::string value(variableValue); 51 return value; 52 } 53 #endif 54 return GetEnvironmentVarOrUnCachedAndroidProperty(variableName, propertyName); 55 } 56 57 // On Android call out to 'getprop' on a shell to get an Android property. On desktop, return 58 // the value of the environment variable. 59 std::string GetEnvironmentVarOrUnCachedAndroidProperty(const char *variableName, 60 const char *propertyName) 61 { 62 #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 26 63 std::string propertyValue; 64 65 const prop_info *propertyInfo = __system_property_find(propertyName); 66 if (propertyInfo != nullptr) 67 { 68 __system_property_read_callback( 69 propertyInfo, 70 [](void *cookie, const char *, const char *value, unsigned) { 71 auto propertyValue = reinterpret_cast<std::string *>(cookie); 72 *propertyValue = value; 73 }, 74 &propertyValue); 75 } 76 77 return propertyValue; 78 #else 79 // Return the environment variable's value. 80 return GetEnvironmentVar(variableName); 81 #endif // ANGLE_PLATFORM_ANDROID 82 } 83 84 // Look up a property and add it to the application's environment. 85 // Adding to the env is a performance optimization, as getting properties is expensive. 86 // This should only be used in non-Release paths, i.e. when using FrameCapture or DebugUtils. 87 // It can cause race conditions in stress testing. See http://anglebug.com/6822 88 std::string GetAndSetEnvironmentVarOrUnCachedAndroidProperty(const char *variableName, 89 const char *propertyName) 90 { 91 std::string value = GetEnvironmentVarOrUnCachedAndroidProperty(variableName, propertyName); 92 93 #if defined(ANGLE_PLATFORM_ANDROID) 94 if (!value.empty()) 95 { 96 // Set the environment variable with the value to improve future lookups (avoids 97 SetEnvironmentVar(variableName, value.c_str()); 98 } 99 #endif 100 101 return value; 102 } 103 104 bool GetBoolEnvironmentVar(const char *variableName) 105 { 106 std::string envVarString = GetEnvironmentVar(variableName); 107 return (!envVarString.empty() && envVarString == "1"); 108 } 109 110 bool PrependPathToEnvironmentVar(const char *variableName, const char *path) 111 { 112 std::string oldValue = GetEnvironmentVar(variableName); 113 const char *newValue = nullptr; 114 std::string buf; 115 if (oldValue.empty()) 116 { 117 newValue = path; 118 } 119 else 120 { 121 buf = path; 122 buf += GetPathSeparatorForEnvironmentVar(); 123 buf += oldValue; 124 newValue = buf.c_str(); 125 } 126 return SetEnvironmentVar(variableName, newValue); 127 } 128 129 bool IsFullPath(std::string dirName) 130 { 131 if (dirName.find(GetRootDirectory()) == 0) 132 { 133 return true; 134 } 135 return false; 136 } 137 138 std::string ConcatenatePath(std::string first, std::string second) 139 { 140 if (first.empty()) 141 { 142 return second; 143 } 144 if (second.empty()) 145 { 146 return first; 147 } 148 if (IsFullPath(second)) 149 { 150 return second; 151 } 152 bool firstRedundantPathSeparator = first.find_last_of(GetPathSeparator()) == first.length() - 1; 153 bool secondRedundantPathSeparator = second.find(GetPathSeparator()) == 0; 154 if (firstRedundantPathSeparator && secondRedundantPathSeparator) 155 { 156 return first + second.substr(1); 157 } 158 else if (firstRedundantPathSeparator || secondRedundantPathSeparator) 159 { 160 return first + second; 161 } 162 return first + GetPathSeparator() + second; 163 } 164 165 Optional<std::string> CreateTemporaryFile() 166 { 167 const Optional<std::string> tempDir = GetTempDirectory(); 168 if (!tempDir.valid()) 169 return Optional<std::string>::Invalid(); 170 171 return CreateTemporaryFileInDirectory(tempDir.value()); 172 } 173 174 PageFaultHandler::PageFaultHandler(PageFaultCallback callback) : mCallback(callback) {} 175 PageFaultHandler::~PageFaultHandler() {} 176 177 Library *OpenSharedLibrary(const char *libraryName, SearchType searchType) 178 { 179 void *libraryHandle = OpenSystemLibraryAndGetError(libraryName, searchType, nullptr); 180 return new Library(libraryHandle); 181 } 182 183 Library *OpenSharedLibraryWithExtension(const char *libraryName, SearchType searchType) 184 { 185 void *libraryHandle = 186 OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, nullptr); 187 return new Library(libraryHandle); 188 } 189 190 Library *OpenSharedLibraryAndGetError(const char *libraryName, 191 SearchType searchType, 192 std::string *errorOut) 193 { 194 void *libraryHandle = OpenSystemLibraryAndGetError(libraryName, searchType, errorOut); 195 return new Library(libraryHandle); 196 } 197 198 Library *OpenSharedLibraryWithExtensionAndGetError(const char *libraryName, 199 SearchType searchType, 200 std::string *errorOut) 201 { 202 void *libraryHandle = 203 OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, errorOut); 204 return new Library(libraryHandle); 205 } 206 207 void *OpenSystemLibrary(const char *libraryName, SearchType searchType) 208 { 209 return OpenSystemLibraryAndGetError(libraryName, searchType, nullptr); 210 } 211 212 void *OpenSystemLibraryWithExtension(const char *libraryName, SearchType searchType) 213 { 214 return OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, nullptr); 215 } 216 217 void *OpenSystemLibraryAndGetError(const char *libraryName, 218 SearchType searchType, 219 std::string *errorOut) 220 { 221 std::string libraryWithExtension = std::string(libraryName) + "." + GetSharedLibraryExtension(); 222 #if ANGLE_PLATFORM_IOS 223 // On iOS, libraryWithExtension is a directory in which the library resides. 224 // The actual library name doesn't have an extension at all. 225 // E.g. "libEGL.framework/libEGL" 226 libraryWithExtension = libraryWithExtension + "/" + libraryName; 227 #endif 228 return OpenSystemLibraryWithExtensionAndGetError(libraryWithExtension.c_str(), searchType, 229 errorOut); 230 } 231 232 std::string StripFilenameFromPath(const std::string &path) 233 { 234 size_t lastPathSepLoc = path.find_last_of("\\/"); 235 return (lastPathSepLoc != std::string::npos) ? path.substr(0, lastPathSepLoc) : ""; 236 } 237 238 static std::atomic<uint64_t> globalThreadSerial(1); 239 240 #if defined(ANGLE_PLATFORM_APPLE) 241 // https://anglebug.com/6479, similar to egl::GetCurrentThread() in libGLESv2/global_state.cpp 242 uint64_t GetCurrentThreadUniqueId() 243 { 244 static pthread_key_t tlsIndex; 245 static dispatch_once_t once; 246 dispatch_once(&once, ^{ 247 ASSERT(pthread_key_create(&tlsIndex, nullptr) == 0); 248 }); 249 250 void *tlsValue = pthread_getspecific(tlsIndex); 251 if (tlsValue == nullptr) 252 { 253 uint64_t threadId = globalThreadSerial++; 254 ASSERT(pthread_setspecific(tlsIndex, reinterpret_cast<void *>(threadId)) == 0); 255 return threadId; 256 } 257 return reinterpret_cast<uint64_t>(tlsValue); 258 } 259 #else 260 uint64_t GetCurrentThreadUniqueId() 261 { 262 thread_local uint64_t threadId(globalThreadSerial++); 263 return threadId; 264 } 265 #endif 266 267 } // namespace angle