1 // Copyright (C) 2014 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "aemu/base/SharedLibrary.h"
16
17 #include <stddef.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include <functional>
22 #include <vector>
23
24 #include "aemu/base/files/PathUtils.h"
25 #include "host-common/logging.h"
26
27 #ifndef _WIN32
28 #include <dlfcn.h>
29 #include <stdlib.h>
30 #endif
31
32 using android::base::PathUtils;
33
34 namespace android {
35 namespace base {
36
37 class LibrarySearchPaths {
38 public:
39 LibrarySearchPaths() = default;
40
addPath(const char * path)41 void addPath(const char* path) {
42 mPaths.push_back(path);
43 }
44
forEachPath(std::function<void (const std::string &)> func)45 void forEachPath(std::function<void(const std::string&)> func) {
46 for (const auto& path: mPaths) {
47 func(path);
48 }
49 }
50
51 private:
52 std::vector<std::string> mPaths;
53 };
54
sSearchPaths()55 LibrarySearchPaths* sSearchPaths() {
56 static LibrarySearchPaths* paths = new LibrarySearchPaths;
57 return paths;
58 }
59
60 static SharedLibrary::LibraryMap s_libraryMap;
61
62 // static
open(const char * libraryName)63 SharedLibrary* SharedLibrary::open(const char* libraryName) {
64 INFO("SharedLibrary::open for [%s]", libraryName);
65 char error[1];
66 return open(libraryName, error, sizeof(error));
67 }
68
open(const char * libraryName,char * error,size_t errorSize)69 SharedLibrary* SharedLibrary::open(const char* libraryName,
70 char* error,
71 size_t errorSize) {
72 auto lib = s_libraryMap.find(libraryName);
73
74 if (lib == s_libraryMap.end()) {
75 INFO("SharedLibrary::open for [%s]: not found in map, open for the first time",
76 libraryName);
77 SharedLibrary* load = do_open(libraryName, error, errorSize);
78 if (load != nullptr) {
79 s_libraryMap[libraryName] =
80 std::unique_ptr<SharedLibrary, SharedLibrary::Deleter>(load);
81 }
82 return load;
83 }
84
85 return lib->second.get();
86 }
87
88 #ifdef _WIN32
89
90 // static
do_open(const char * libraryName,char * error,size_t errorSize)91 SharedLibrary* SharedLibrary::do_open(const char* libraryName,
92 char* error,
93 size_t errorSize) {
94 INFO("SharedLibrary::open for [%s] (win32): call LoadLibrary", libraryName);
95 HMODULE lib = LoadLibraryA(libraryName);
96
97 // Try a bit harder to find the shared library if we cannot find it.
98 if (!lib) {
99 INFO("SharedLibrary::open for [%s] can't find in default path. Searching alternatives...",
100 libraryName);
101 sSearchPaths()->forEachPath([&lib, libraryName](const std::string& path) {
102 if (!lib) {
103 auto libName = PathUtils::join(path, libraryName);
104 INFO("SharedLibrary::open for [%s]: trying [%s]", libraryName, libName.c_str());
105 lib = LoadLibraryA(libName.c_str());
106 INFO("SharedLibrary::open for [%s]: trying [%s]. found? %d", libraryName,
107 libName.c_str(), lib != nullptr);
108 }
109 });
110 }
111
112 if (lib) {
113 constexpr size_t kMaxPathLength = 2048;
114 char fullPath[kMaxPathLength];
115 GetModuleFileNameA(lib, fullPath, kMaxPathLength);
116 INFO("SharedLibrary::open succeeded for [%s]. File name: [%s]", libraryName, fullPath);
117 return new SharedLibrary(lib);
118 }
119
120 if (errorSize == 0) {
121 INFO("SharedLibrary::open for [%s] failed, but no error", libraryName);
122 return NULL;
123 }
124
125 // Convert error into human-readable message.
126 DWORD errorCode = ::GetLastError();
127 LPSTR message = NULL;
128 size_t messageLen = FormatMessageA(
129 FORMAT_MESSAGE_ALLOCATE_BUFFER |
130 FORMAT_MESSAGE_FROM_SYSTEM |
131 FORMAT_MESSAGE_IGNORE_INSERTS,
132 NULL,
133 errorCode,
134 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
135 (LPSTR) &message,
136 0,
137 NULL);
138
139 int ret = snprintf(error, errorSize, "%.*s", (int)messageLen, message);
140 if (ret < 0 || ret == static_cast<int>(errorSize)) {
141 // snprintf() on Windows doesn't behave as expected by C99,
142 // this path is to ensure that the result is always properly
143 // zero-terminated.
144 ret = static_cast<int>(errorSize - 1);
145 error[ret] = '\0';
146 }
147 // Remove any trailing \r\n added by FormatMessage
148 if (ret > 0 && error[ret - 1] == '\n') {
149 error[--ret] = '\0';
150 }
151 if (ret > 0 && error[ret - 1] == '\r') {
152 error[--ret] = '\0';
153 }
154 INFO("Failed to load [%s]. Error string: [%s]", libraryName, error);
155
156 return NULL;
157 }
158
SharedLibrary(HandleType lib)159 SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
160
~SharedLibrary()161 SharedLibrary::~SharedLibrary() {
162 if (mLib) {
163 // BUG: 66013149
164 // In windows it sometimes hang on exit when destroying s_libraryMap.
165 // Let's skip freeing the library, since pretty much the only situation
166 // we need to do it, is on exit.
167 //FreeLibrary(mLib);
168 }
169 }
170
findSymbol(const char * symbolName) const171 SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
172 const char* symbolName) const {
173 if (!mLib || !symbolName) {
174 return NULL;
175 }
176 return reinterpret_cast<FunctionPtr>(
177 GetProcAddress(mLib, symbolName));
178 }
179
180 #else // !_WIN32
181
182 // static
do_open(const char * libraryName,char * error,size_t errorSize)183 SharedLibrary* SharedLibrary::do_open(const char* libraryName,
184 char* error,
185 size_t errorSize) {
186 INFO("SharedLibrary::open for [%s] (posix): begin", libraryName);
187
188 const char* libPath = libraryName;
189 char* path = NULL;
190
191 const char* libBaseName = strrchr(libraryName, '/');
192 if (!libBaseName) {
193 libBaseName = libraryName;
194 }
195
196 if (!strchr(libBaseName, '.')) {
197 // There is no extension in this library name, so append one.
198 #ifdef __APPLE__
199 static const char kDllExtension[] = ".dylib";
200 #else
201 static const char kDllExtension[] = ".so";
202 #endif
203 size_t pathLen = strlen(libraryName) + sizeof(kDllExtension);
204 path = static_cast<char*>(malloc(pathLen));
205 snprintf(path, pathLen, "%s%s", libraryName, kDllExtension);
206 libPath = path;
207 }
208
209 dlerror(); // clear error.
210
211 #ifdef __APPLE__
212 // On OSX, some libraries don't include an extension (notably OpenGL)
213 // On OSX we try to open |libraryName| first. If that doesn't exist,
214 // we try |libraryName|.dylib
215 INFO("SharedLibrary::open for [%s] (posix,darwin): call dlopen", libraryName);
216 void* lib = dlopen(libraryName, RTLD_NOW);
217 if (lib == NULL) {
218 INFO(
219 "SharedLibrary::open for [%s] (posix,darwin): failed, "
220 "try again with [%s]",
221 libraryName, libPath);
222 lib = dlopen(libPath, RTLD_NOW);
223
224 sSearchPaths()->forEachPath([&lib, libraryName, libPath](const std::string& path) {
225 if (!lib) {
226 auto libName = PathUtils::join(path, libraryName);
227 INFO(
228 "SharedLibrary::open for [%s] (posix,darwin): still failed, "
229 "try [%s]",
230 libraryName, libName.c_str());
231 lib = dlopen(libName.c_str(), RTLD_NOW);
232 if (!lib) {
233 auto libPathName = PathUtils::join(path, libPath);
234 INFO(
235 "SharedLibrary::open for [%s] (posix,darwin): still failed, "
236 "try [%s]",
237 libraryName, libPathName.c_str());
238 lib = dlopen(libPathName.c_str(), RTLD_NOW);
239 }
240 }
241 });
242 }
243 #else
244 INFO("SharedLibrary::open for [%s] (posix,linux): call dlopen on [%s]", libraryName, libPath);
245 void* lib = dlopen(libPath, RTLD_NOW);
246 #endif
247
248 sSearchPaths()->forEachPath([&lib, libPath, libraryName](const std::string& path) {
249 if (!lib) {
250 auto libPathName = PathUtils::join(path, libPath);
251 INFO("SharedLibrary::open for [%s] (posix): try again with %s", libraryName,
252 libPathName.c_str());
253 lib = dlopen(libPathName.c_str(), RTLD_NOW);
254 }
255 });
256
257 if (path) {
258 free(path);
259 }
260
261 if (lib) {
262 INFO("SharedLibrary::open succeeded for [%s].", libraryName);
263 return new SharedLibrary(lib);
264 }
265
266 snprintf(error, errorSize, "%s", dlerror());
267 INFO("SharedLibrary::open for [%s] failed (posix). dlerror: [%s]", libraryName, error);
268 return NULL;
269 }
270
SharedLibrary(HandleType lib)271 SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
272
~SharedLibrary()273 SharedLibrary::~SharedLibrary() {
274 if (mLib) {
275 dlclose(mLib);
276 }
277 }
278
findSymbol(const char * symbolName) const279 SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
280 const char* symbolName) const {
281 if (!mLib || !symbolName) {
282 return NULL;
283 }
284 return reinterpret_cast<FunctionPtr>(dlsym(mLib, symbolName));
285 }
286
287 #endif // !_WIN32
288
289 // static
addLibrarySearchPath(const char * path)290 void SharedLibrary::addLibrarySearchPath(const char* path) {
291 sSearchPaths()->addPath(path);
292 }
293
294 } // namespace base
295 } // namespace android
296