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
11 #include <stdlib.h>
12
13 #if defined(ANGLE_PLATFORM_ANDROID)
14 # include <sys/system_properties.h>
15 #endif
16
17 namespace angle
18 {
GetExecutableName()19 std::string GetExecutableName()
20 {
21 #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 21
22 // Support for "getprogname" function in bionic was introduced in L (API level 21)
23 const char *executableName = getprogname();
24 return (executableName) ? std::string(executableName) : "ANGLE";
25 #else
26 std::string executableName = GetExecutablePath();
27 size_t lastPathSepLoc = executableName.find_last_of(GetPathSeparator());
28 return (lastPathSepLoc > 0 ? executableName.substr(lastPathSepLoc + 1, executableName.length())
29 : "ANGLE");
30 #endif // ANGLE_PLATFORM_ANDROID
31 }
32
33 // On Android return value cached in the process environment, if none, call
34 // GetEnvironmentVarOrUnCachedAndroidProperty if not in environment.
GetEnvironmentVarOrAndroidProperty(const char * variableName,const char * propertyName)35 std::string GetEnvironmentVarOrAndroidProperty(const char *variableName, const char *propertyName)
36 {
37 #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 21
38 // Can't use GetEnvironmentVar here because that won't allow us to distinguish between the
39 // environment being set to an empty string vs. not set at all.
40 const char *variableValue = getenv(variableName);
41 if (variableValue != nullptr)
42 {
43 std::string value(variableValue);
44 return value;
45 }
46 #endif
47 return GetEnvironmentVarOrUnCachedAndroidProperty(variableName, propertyName);
48 }
49
50 // On Android call out to 'getprop' on a shell to get an Android property. On desktop, return
51 // the value of the environment variable.
GetEnvironmentVarOrUnCachedAndroidProperty(const char * variableName,const char * propertyName)52 std::string GetEnvironmentVarOrUnCachedAndroidProperty(const char *variableName,
53 const char *propertyName)
54 {
55 #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 26
56 std::string propertyValue;
57
58 const prop_info *propertyInfo = __system_property_find(propertyName);
59 if (propertyInfo != nullptr)
60 {
61 __system_property_read_callback(
62 propertyInfo,
63 [](void *cookie, const char *, const char *value, unsigned) {
64 auto propertyValue = reinterpret_cast<std::string *>(cookie);
65 *propertyValue = value;
66 },
67 &propertyValue);
68 }
69
70 return propertyValue;
71 #else
72 // Return the environment variable's value.
73 return GetEnvironmentVar(variableName);
74 #endif // ANGLE_PLATFORM_ANDROID
75 }
76
77 // Look up a property and add it to the application's environment.
78 // Adding to the env is a performance optimization, as getting properties is expensive.
79 // This should only be used in non-Release paths, i.e. when using FrameCapture or DebugUtils.
80 // It can cause race conditions in stress testing. See http://anglebug.com/6822
GetAndSetEnvironmentVarOrUnCachedAndroidProperty(const char * variableName,const char * propertyName)81 std::string GetAndSetEnvironmentVarOrUnCachedAndroidProperty(const char *variableName,
82 const char *propertyName)
83 {
84 std::string value = GetEnvironmentVarOrUnCachedAndroidProperty(variableName, propertyName);
85
86 #if defined(ANGLE_PLATFORM_ANDROID)
87 if (!value.empty())
88 {
89 // Set the environment variable with the value to improve future lookups (avoids
90 SetEnvironmentVar(variableName, value.c_str());
91 }
92 #endif
93
94 return value;
95 }
96
GetBoolEnvironmentVar(const char * variableName)97 bool GetBoolEnvironmentVar(const char *variableName)
98 {
99 std::string envVarString = GetEnvironmentVar(variableName);
100 return (!envVarString.empty() && envVarString == "1");
101 }
102
PrependPathToEnvironmentVar(const char * variableName,const char * path)103 bool PrependPathToEnvironmentVar(const char *variableName, const char *path)
104 {
105 std::string oldValue = GetEnvironmentVar(variableName);
106 const char *newValue = nullptr;
107 std::string buf;
108 if (oldValue.empty())
109 {
110 newValue = path;
111 }
112 else
113 {
114 buf = path;
115 buf += GetPathSeparatorForEnvironmentVar();
116 buf += oldValue;
117 newValue = buf.c_str();
118 }
119 return SetEnvironmentVar(variableName, newValue);
120 }
121
IsFullPath(std::string dirName)122 bool IsFullPath(std::string dirName)
123 {
124 if (dirName.find(GetRootDirectory()) == 0)
125 {
126 return true;
127 }
128 return false;
129 }
130
ConcatenatePath(std::string first,std::string second)131 std::string ConcatenatePath(std::string first, std::string second)
132 {
133 if (first.empty())
134 {
135 return second;
136 }
137 if (second.empty())
138 {
139 return first;
140 }
141 if (IsFullPath(second))
142 {
143 return second;
144 }
145 bool firstRedundantPathSeparator = first.find_last_of(GetPathSeparator()) == first.length() - 1;
146 bool secondRedundantPathSeparator = second.find(GetPathSeparator()) == 0;
147 if (firstRedundantPathSeparator && secondRedundantPathSeparator)
148 {
149 return first + second.substr(1);
150 }
151 else if (firstRedundantPathSeparator || secondRedundantPathSeparator)
152 {
153 return first + second;
154 }
155 return first + GetPathSeparator() + second;
156 }
157
PageFaultHandler(PageFaultCallback callback)158 PageFaultHandler::PageFaultHandler(PageFaultCallback callback) : mCallback(callback) {}
~PageFaultHandler()159 PageFaultHandler::~PageFaultHandler() {}
160
OpenSharedLibrary(const char * libraryName,SearchType searchType)161 Library *OpenSharedLibrary(const char *libraryName, SearchType searchType)
162 {
163 void *libraryHandle = OpenSystemLibraryAndGetError(libraryName, searchType, nullptr);
164 return new Library(libraryHandle);
165 }
166
OpenSharedLibraryWithExtension(const char * libraryName,SearchType searchType)167 Library *OpenSharedLibraryWithExtension(const char *libraryName, SearchType searchType)
168 {
169 void *libraryHandle =
170 OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, nullptr);
171 return new Library(libraryHandle);
172 }
173
OpenSharedLibraryAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)174 Library *OpenSharedLibraryAndGetError(const char *libraryName,
175 SearchType searchType,
176 std::string *errorOut)
177 {
178 void *libraryHandle = OpenSystemLibraryAndGetError(libraryName, searchType, errorOut);
179 return new Library(libraryHandle);
180 }
181
OpenSharedLibraryWithExtensionAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)182 Library *OpenSharedLibraryWithExtensionAndGetError(const char *libraryName,
183 SearchType searchType,
184 std::string *errorOut)
185 {
186 void *libraryHandle =
187 OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, errorOut);
188 return new Library(libraryHandle);
189 }
190
OpenSystemLibrary(const char * libraryName,SearchType searchType)191 void *OpenSystemLibrary(const char *libraryName, SearchType searchType)
192 {
193 return OpenSystemLibraryAndGetError(libraryName, searchType, nullptr);
194 }
195
OpenSystemLibraryWithExtension(const char * libraryName,SearchType searchType)196 void *OpenSystemLibraryWithExtension(const char *libraryName, SearchType searchType)
197 {
198 return OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, nullptr);
199 }
200
OpenSystemLibraryAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)201 void *OpenSystemLibraryAndGetError(const char *libraryName,
202 SearchType searchType,
203 std::string *errorOut)
204 {
205 std::string libraryWithExtension = std::string(libraryName) + "." + GetSharedLibraryExtension();
206 return OpenSystemLibraryWithExtensionAndGetError(libraryWithExtension.c_str(), searchType,
207 errorOut);
208 }
209 } // namespace angle
210