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 // Call out to 'getprop' on a shell to get an Android property.  If the value was set, set an
51 // environment variable with that value.  Return 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     // Set the environment variable with the value.
71     SetEnvironmentVar(variableName, propertyValue.c_str());
72     return propertyValue;
73 #endif  // ANGLE_PLATFORM_ANDROID
74     // Return the environment variable's value.
75     return GetEnvironmentVar(variableName);
76 }
77 
GetBoolEnvironmentVar(const char * variableName)78 bool GetBoolEnvironmentVar(const char *variableName)
79 {
80     std::string envVarString = GetEnvironmentVar(variableName);
81     return (!envVarString.empty() && envVarString == "1");
82 }
83 
PrependPathToEnvironmentVar(const char * variableName,const char * path)84 bool PrependPathToEnvironmentVar(const char *variableName, const char *path)
85 {
86     std::string oldValue = GetEnvironmentVar(variableName);
87     const char *newValue = nullptr;
88     std::string buf;
89     if (oldValue.empty())
90     {
91         newValue = path;
92     }
93     else
94     {
95         buf = path;
96         buf += GetPathSeparatorForEnvironmentVar();
97         buf += oldValue;
98         newValue = buf.c_str();
99     }
100     return SetEnvironmentVar(variableName, newValue);
101 }
102 
IsFullPath(std::string dirName)103 bool IsFullPath(std::string dirName)
104 {
105     if (dirName.find(GetRootDirectory()) == 0)
106     {
107         return true;
108     }
109     return false;
110 }
111 
ConcatenatePath(std::string first,std::string second)112 std::string ConcatenatePath(std::string first, std::string second)
113 {
114     if (first.empty())
115     {
116         return second;
117     }
118     if (second.empty())
119     {
120         return first;
121     }
122     if (IsFullPath(second))
123     {
124         return first;
125     }
126     bool firstRedundantPathSeparator = first.find_last_of(GetPathSeparator()) == first.length() - 1;
127     bool secondRedundantPathSeparator = second.find(GetPathSeparator()) == 0;
128     if (firstRedundantPathSeparator && secondRedundantPathSeparator)
129     {
130         return first + second.substr(1);
131     }
132     else if (firstRedundantPathSeparator || secondRedundantPathSeparator)
133     {
134         return first + second;
135     }
136     return first + GetPathSeparator() + second;
137 }
138 }  // namespace angle
139