• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
GetExecutableName()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.
GetEnvironmentVarOrAndroidProperty(const char * variableName,const char * propertyName)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.
GetEnvironmentVarOrUnCachedAndroidProperty(const char * variableName,const char * propertyName)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
GetAndSetEnvironmentVarOrUnCachedAndroidProperty(const char * variableName,const char * propertyName)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 
GetBoolEnvironmentVar(const char * variableName)104 bool GetBoolEnvironmentVar(const char *variableName)
105 {
106     std::string envVarString = GetEnvironmentVar(variableName);
107     return (!envVarString.empty() && envVarString == "1");
108 }
109 
PrependPathToEnvironmentVar(const char * variableName,const char * path)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 
IsFullPath(std::string dirName)129 bool IsFullPath(std::string dirName)
130 {
131     if (dirName.find(GetRootDirectory()) == 0)
132     {
133         return true;
134     }
135     return false;
136 }
137 
ConcatenatePath(std::string first,std::string second)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 
CreateTemporaryFile()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 
PageFaultHandler(PageFaultCallback callback)174 PageFaultHandler::PageFaultHandler(PageFaultCallback callback) : mCallback(callback) {}
~PageFaultHandler()175 PageFaultHandler::~PageFaultHandler() {}
176 
OpenSharedLibrary(const char * libraryName,SearchType searchType)177 Library *OpenSharedLibrary(const char *libraryName, SearchType searchType)
178 {
179     void *libraryHandle = OpenSystemLibraryAndGetError(libraryName, searchType, nullptr);
180     return new Library(libraryHandle);
181 }
182 
OpenSharedLibraryWithExtension(const char * libraryName,SearchType searchType)183 Library *OpenSharedLibraryWithExtension(const char *libraryName, SearchType searchType)
184 {
185     void *libraryHandle =
186         OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, nullptr);
187     return new Library(libraryHandle);
188 }
189 
OpenSharedLibraryAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)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 
OpenSharedLibraryWithExtensionAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)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 
OpenSystemLibrary(const char * libraryName,SearchType searchType)207 void *OpenSystemLibrary(const char *libraryName, SearchType searchType)
208 {
209     return OpenSystemLibraryAndGetError(libraryName, searchType, nullptr);
210 }
211 
OpenSystemLibraryWithExtension(const char * libraryName,SearchType searchType)212 void *OpenSystemLibraryWithExtension(const char *libraryName, SearchType searchType)
213 {
214     return OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, nullptr);
215 }
216 
OpenSystemLibraryAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)217 void *OpenSystemLibraryAndGetError(const char *libraryName,
218                                    SearchType searchType,
219                                    std::string *errorOut)
220 {
221     std::string libraryWithExtension = std::string(libraryName);
222     std::string dotExtension         = std::string(".") + GetSharedLibraryExtension();
223     // Only append the extension if it's not already present. This enables building libEGL.so.1
224     // and libGLESv2.so.2 by setting these as ANGLE_EGL_LIBRARY_NAME and ANGLE_GLESV2_LIBRARY_NAME.
225     if (libraryWithExtension.find(dotExtension) == std::string::npos)
226     {
227         libraryWithExtension += dotExtension;
228     }
229 #if ANGLE_PLATFORM_IOS_FAMILY
230     // On iOS, libraryWithExtension is a directory in which the library resides.
231     // The actual library name doesn't have an extension at all.
232     // E.g. "libEGL.framework/libEGL"
233     libraryWithExtension = libraryWithExtension + "/" + libraryName;
234 #endif
235     return OpenSystemLibraryWithExtensionAndGetError(libraryWithExtension.c_str(), searchType,
236                                                      errorOut);
237 }
238 
StripFilenameFromPath(const std::string & path)239 std::string StripFilenameFromPath(const std::string &path)
240 {
241     size_t lastPathSepLoc = path.find_last_of("\\/");
242     return (lastPathSepLoc != std::string::npos) ? path.substr(0, lastPathSepLoc) : "";
243 }
244 
245 #if defined(ANGLE_PLATFORM_APPLE)
246 // https://anglebug.com/6479, similar to egl::GetCurrentThread() in libGLESv2/global_state.cpp
GetCurrentThreadUniqueId()247 uint64_t GetCurrentThreadUniqueId()
248 {
249     static std::atomic<uint64_t> globalThreadSerial;
250     static pthread_key_t tlsIndex;
251     static dispatch_once_t once;
252     dispatch_once(&once, ^{
253       auto result = pthread_key_create(&tlsIndex, nullptr);
254       ASSERT(result == 0);
255     });
256     void *tlsValue = pthread_getspecific(tlsIndex);
257     if (ANGLE_UNLIKELY(tlsValue == nullptr))
258     {
259         uint64_t threadId = ++globalThreadSerial;
260         auto result       = pthread_setspecific(tlsIndex, reinterpret_cast<void *>(threadId));
261         ASSERT(result == 0);
262         return threadId;
263     }
264     return reinterpret_cast<uint64_t>(tlsValue);
265 }
266 #else
GetCurrentThreadUniqueId()267 uint64_t GetCurrentThreadUniqueId()
268 {
269     static std::atomic<uint64_t> globalThreadSerial;
270     thread_local uint64_t threadId(++globalThreadSerial);
271     return threadId;
272 }
273 #endif
274 
275 }  // namespace angle
276