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