• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/SharedLibrary.h"
16 #include "base/PathUtils.h"
17 
18 #include <functional>
19 #include <vector>
20 
21 #include <stddef.h>
22 #include <string.h>
23 #include <stdio.h>
24 
25 #ifndef _WIN32
26 #include <dlfcn.h>
27 #include <stdlib.h>
28 #endif
29 
30 #define GL_LOG(fmt,...) fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ##__VA_ARGS__);
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     GL_LOG("SharedLibrary::open for [%s]\n", 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         GL_LOG("SharedLibrary::open for [%s]: not found in map, open for the first time\n", libraryName);
76         SharedLibrary* load = do_open(libraryName, error, errorSize);
77         if (load != nullptr) {
78             s_libraryMap[libraryName] =
79                 std::unique_ptr<SharedLibrary, SharedLibrary::Deleter>(load);
80         }
81         return load;
82     }
83 
84     return lib->second.get();
85 }
86 
87 #ifdef _WIN32
88 
89 // static
do_open(const char * libraryName,char * error,size_t errorSize)90 SharedLibrary* SharedLibrary::do_open(const char* libraryName,
91                                    char* error,
92                                    size_t errorSize) {
93     GL_LOG("SharedLibrary::open for [%s] (win32): call LoadLibrary\n", libraryName);
94     HMODULE lib = LoadLibraryA(libraryName);
95 
96     // Try a bit harder to find the shared library if we cannot find it.
97     if (!lib) {
98         GL_LOG("SharedLibrary::open for [%s] can't find in default path. Searching alternatives...\n",
99                libraryName);
100         sSearchPaths()->forEachPath([&lib, libraryName](const std::string& path) {
101             if (!lib) {
102                 auto libName = PathUtils::join(path, libraryName);
103                 GL_LOG("SharedLibrary::open for [%s]: trying [%s]\n",
104                        libraryName, libName.c_str());
105                 lib = LoadLibraryA(libName.c_str());
106                 GL_LOG("SharedLibrary::open for [%s]: trying [%s]. found? %d\n",
107                        libraryName, 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         GL_LOG("SharedLibrary::open succeeded for [%s]. File name: [%s]\n",
117                libraryName, fullPath);
118         return new SharedLibrary(lib);
119     }
120 
121     if (errorSize == 0) {
122         GL_LOG("SharedLibrary::open for [%s] failed, but no error\n",
123                libraryName);
124         return NULL;
125     }
126 
127     // Convert error into human-readable message.
128     DWORD errorCode = ::GetLastError();
129     LPSTR message = NULL;
130     size_t messageLen = FormatMessageA(
131             FORMAT_MESSAGE_ALLOCATE_BUFFER |
132             FORMAT_MESSAGE_FROM_SYSTEM |
133             FORMAT_MESSAGE_IGNORE_INSERTS,
134             NULL,
135             errorCode,
136             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
137             (LPSTR) &message,
138             0,
139             NULL);
140 
141     int ret = snprintf(error, errorSize, "%.*s", (int)messageLen, message);
142     if (ret < 0 || ret == static_cast<int>(errorSize)) {
143         // snprintf() on Windows doesn't behave as expected by C99,
144         // this path is to ensure that the result is always properly
145         // zero-terminated.
146         ret = static_cast<int>(errorSize - 1);
147         error[ret] = '\0';
148     }
149     // Remove any trailing \r\n added by FormatMessage
150     if (ret > 0 && error[ret - 1] == '\n') {
151         error[--ret] = '\0';
152     }
153     if (ret > 0 && error[ret - 1] == '\r') {
154         error[--ret] = '\0';
155     }
156     GL_LOG("Failed to load [%s]. Error string: [%s]\n",
157            libraryName, error);
158 
159     return NULL;
160 }
161 
SharedLibrary(HandleType lib)162 SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
163 
~SharedLibrary()164 SharedLibrary::~SharedLibrary() {
165     if (mLib) {
166         // BUG: 66013149
167         // In windows it sometimes hang on exit when destroying s_libraryMap.
168         // Let's skip freeing the library, since pretty much the only situation
169         // we need to do it, is on exit.
170         //FreeLibrary(mLib);
171     }
172 }
173 
findSymbol(const char * symbolName) const174 SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
175         const char* symbolName) const {
176     if (!mLib || !symbolName) {
177         return NULL;
178     }
179     return reinterpret_cast<FunctionPtr>(
180                 GetProcAddress(mLib, symbolName));
181 }
182 
183 #else // !_WIN32
184 
185 // static
do_open(const char * libraryName,char * error,size_t errorSize)186 SharedLibrary* SharedLibrary::do_open(const char* libraryName,
187                                    char* error,
188                                    size_t errorSize) {
189     GL_LOG("SharedLibrary::open for [%s] (posix): begin\n", libraryName);
190 
191     const char* libPath = libraryName;
192     char* path = NULL;
193 
194     const char* libBaseName = strrchr(libraryName, '/');
195     if (!libBaseName) {
196         libBaseName = libraryName;
197     }
198 
199     if (!strchr(libBaseName, '.')) {
200         // There is no extension in this library name, so append one.
201 #ifdef __APPLE__
202         static const char kDllExtension[] = ".dylib";
203 #else
204         static const char kDllExtension[] = ".so";
205 #endif
206         size_t pathLen = strlen(libraryName) + sizeof(kDllExtension);
207         path = static_cast<char*>(malloc(pathLen));
208         snprintf(path, pathLen, "%s%s", libraryName, kDllExtension);
209         libPath = path;
210     }
211 
212     dlerror();  // clear error.
213 
214 #ifdef __APPLE__
215     // On OSX, some libraries don't include an extension (notably OpenGL)
216     // On OSX we try to open |libraryName| first.  If that doesn't exist,
217     // we try |libraryName|.dylib
218     GL_LOG("SharedLibrary::open for [%s] (posix,darwin): call dlopen\n", libraryName);
219     void* lib = dlopen(libraryName, RTLD_NOW);
220     if (lib == NULL) {
221         GL_LOG("SharedLibrary::open for [%s] (posix,darwin): failed, "
222                "try again with [%s]\n", libraryName, libPath);
223         lib = dlopen(libPath, RTLD_NOW);
224 
225         sSearchPaths()->forEachPath([&lib, libraryName, libPath](const std::string& path) {
226             if (!lib) {
227                 auto libName = PathUtils::join(path, libraryName);
228                 GL_LOG("SharedLibrary::open for [%s] (posix,darwin): still failed, "
229                        "try [%s]\n", libraryName, libName.c_str());
230                 lib = dlopen(libName.c_str(), RTLD_NOW);
231                 if (!lib) {
232                     auto libPathName = PathUtils::join(path, libPath);
233                     GL_LOG("SharedLibrary::open for [%s] (posix,darwin): still failed, "
234                            "try [%s]\n", libraryName, libPathName.c_str());
235                     lib = dlopen(libPathName.c_str(), RTLD_NOW);
236                 }
237             }
238         });
239     }
240 #else
241     GL_LOG("SharedLibrary::open for [%s] (posix,linux): call dlopen on [%s]\n",
242            libraryName, libPath);
243     void* lib = dlopen(libPath, RTLD_NOW);
244 #endif
245 
246     sSearchPaths()->forEachPath([&lib, libPath, libraryName](const std::string& path) {
247         if (!lib) {
248             auto libPathName = PathUtils::join(path, libPath);
249             GL_LOG("SharedLibrary::open for [%s] (posix): try again with %s\n",
250                    libraryName,
251                    libPathName.c_str());
252             lib = dlopen(libPathName.c_str(), RTLD_NOW);
253         }
254     });
255 
256     if (path) {
257         free(path);
258     }
259 
260     if (lib) {
261         return new SharedLibrary(lib);
262     }
263 
264     snprintf(error, errorSize, "%s", dlerror());
265     GL_LOG("SharedLibrary::open for [%s] failed (posix). dlerror: [%s]\n",
266            libraryName, error);
267     return NULL;
268 }
269 
SharedLibrary(HandleType lib)270 SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
271 
~SharedLibrary()272 SharedLibrary::~SharedLibrary() {
273     if (mLib) {
274         dlclose(mLib);
275     }
276 }
277 
findSymbol(const char * symbolName) const278 SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
279         const char* symbolName) const {
280     if (!mLib || !symbolName) {
281         return NULL;
282     }
283     return reinterpret_cast<FunctionPtr>(dlsym(mLib, symbolName));
284 }
285 
286 #endif  // !_WIN32
287 
288 // static
addLibrarySearchPath(const char * path)289 void SharedLibrary::addLibrarySearchPath(const char* path) {
290     sSearchPaths()->addPath(path);
291 }
292 
293 }  // namespace base
294 }  // namespace android
295