• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
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 
16 #include "native_module_manager.h"
17 
18 #include "native_engine/native_engine.h"
19 
20 #include <dirent.h>
21 
22 #include "securec.h"
23 #include "utils/log.h"
24 
25 namespace {
26 constexpr static int32_t NATIVE_PATH_NUMBER = 2;
27 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__)
28 constexpr static char DL_NAMESPACE[] = "ace";
29 #endif
30 } // namespace
31 
32 NativeModuleManager NativeModuleManager::instance_;
33 
NativeModuleManager()34 NativeModuleManager::NativeModuleManager()
35 {
36     firstNativeModule_ = nullptr;
37     lastNativeModule_ = nullptr;
38     appLibPath_ = nullptr;
39 
40     pthread_mutex_init(&mutex_, nullptr);
41 }
42 
~NativeModuleManager()43 NativeModuleManager::~NativeModuleManager()
44 {
45     NativeModule* nativeModule = firstNativeModule_;
46     while (nativeModule != nullptr) {
47         nativeModule = nativeModule->next;
48         delete firstNativeModule_;
49         firstNativeModule_ = nativeModule;
50     }
51     firstNativeModule_ = lastNativeModule_ = nullptr;
52     if (appLibPath_) {
53         delete[] appLibPath_;
54     }
55 
56     pthread_mutex_destroy(&mutex_);
57 }
58 
GetInstance()59 NativeModuleManager* NativeModuleManager::GetInstance()
60 {
61     return &instance_;
62 }
63 
Register(NativeModule * nativeModule)64 void NativeModuleManager::Register(NativeModule* nativeModule)
65 {
66     if (nativeModule == nullptr) {
67         HILOG_ERROR("nativeModule value is null");
68         return;
69     }
70 
71     if (firstNativeModule_ == lastNativeModule_ && lastNativeModule_ == nullptr) {
72         firstNativeModule_ = new NativeModule();
73         if (firstNativeModule_ == nullptr) {
74             HILOG_ERROR("first NativeModule create failed");
75             return;
76         }
77         lastNativeModule_ = firstNativeModule_;
78     } else {
79         auto next = new NativeModule();
80         if (next == nullptr) {
81             HILOG_ERROR("next NativeModule create failed");
82             return;
83         }
84         lastNativeModule_->next = next;
85         lastNativeModule_ = lastNativeModule_->next;
86     }
87 
88     lastNativeModule_->version = nativeModule->version;
89     lastNativeModule_->fileName = nativeModule->fileName;
90     lastNativeModule_->name = nativeModule->name;
91     lastNativeModule_->refCount = nativeModule->refCount;
92     lastNativeModule_->registerCallback = nativeModule->registerCallback;
93     lastNativeModule_->next = nullptr;
94 }
95 
CreateLdNamespace(const char * lib_ld_path)96 void NativeModuleManager::CreateLdNamespace(const char* lib_ld_path)
97 {
98 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__)
99     dlns_init(&ns_, DL_NAMESPACE);
100     dlns_create(&ns_, lib_ld_path);
101 #endif
102 }
103 
SetAppLibPath(const char * appLibPath)104 void NativeModuleManager::SetAppLibPath(const char* appLibPath)
105 {
106     HILOG_INFO("create ld namespace, path: %{private}s", appLibPath);
107     char* tmp = new char[NAPI_PATH_MAX];
108     errno_t err = EOK;
109     err = memset_s(tmp, NAPI_PATH_MAX, 0, NAPI_PATH_MAX);
110     if (err != EOK) {
111         delete[] tmp;
112         return;
113     }
114     err = strcpy_s(tmp, NAPI_PATH_MAX, appLibPath);
115     if (err != EOK) {
116         delete[] tmp;
117         return;
118     }
119     if (appLibPath_ != nullptr) {
120         delete[] appLibPath_;
121     }
122     appLibPath_ = tmp;
123     CreateLdNamespace(appLibPath_);
124 }
125 
LoadNativeModule(const char * moduleName,const char * path,bool isAppModule,bool internal,bool isArk)126 NativeModule* NativeModuleManager::LoadNativeModule(const char* moduleName,
127     const char* path, bool isAppModule, bool internal, bool isArk)
128 {
129     if (moduleName == nullptr) {
130         HILOG_ERROR("moduleName value is null");
131         return nullptr;
132     }
133 
134     if (pthread_mutex_lock(&mutex_) != 0) {
135         HILOG_ERROR("pthread_mutex_lock is failed");
136         return nullptr;
137     }
138 
139     NativeModule* nativeModule = FindNativeModuleByCache(moduleName);
140     if (nativeModule == nullptr) {
141         HILOG_INFO("not in cache: moduleName: %{public}s", moduleName);
142         nativeModule = FindNativeModuleByDisk(moduleName, internal, isAppModule, isArk);
143     }
144 
145     if (pthread_mutex_unlock(&mutex_) != 0) {
146         HILOG_ERROR("pthread_mutex_unlock is failed");
147         return nullptr;
148     }
149 
150     return nativeModule;
151 }
152 
GetNativeModulePath(const char * moduleName,const bool isAppModule,char nativeModulePath[][NAPI_PATH_MAX],int32_t pathLength) const153 bool NativeModuleManager::GetNativeModulePath(
154     const char* moduleName, const bool isAppModule, char nativeModulePath[][NAPI_PATH_MAX], int32_t pathLength) const
155 {
156 #ifdef WINDOWS_PLATFORM
157     const char* soPostfix = ".dll";
158     const char* sysPrefix = "./module";
159     const char* zfix = "";
160 #elif defined(MAC_PLATFORM)
161     const char* soPostfix = ".dylib";
162     const char* sysPrefix = "./module";
163     const char* zfix = "";
164 #elif defined(_ARM64_)
165     const char* soPostfix = ".so";
166     const char* sysPrefix = "/system/lib64/module";
167     const char* zfix = ".z";
168 #else
169     const char* soPostfix = ".so";
170     const char* sysPrefix = "/system/lib/module";
171     const char* zfix = ".z";
172 #endif
173     int32_t lengthOfModuleName = strlen(moduleName);
174     char dupModuleName[NAPI_PATH_MAX] = { 0 };
175     if (strcpy_s(dupModuleName, NAPI_PATH_MAX, moduleName) != 0) {
176         HILOG_ERROR("strcpy moduleName failed");
177         return false;
178     }
179 
180     const char* prefix = nullptr;
181     if (isAppModule && appLibPath_) {
182         prefix = appLibPath_;
183     } else {
184         prefix = sysPrefix;
185         for (int32_t i = 0; i < lengthOfModuleName; i++) {
186             dupModuleName[i] = tolower(dupModuleName[i]);
187         }
188     }
189 
190     int32_t lengthOfPostfix = strlen(soPostfix);
191     if ((lengthOfModuleName > lengthOfPostfix) &&
192         (strcmp(dupModuleName + lengthOfModuleName - lengthOfPostfix, soPostfix) == 0)) {
193         if (sprintf_s(nativeModulePath[0], pathLength, "%s/%s", prefix, dupModuleName) == -1) {
194             return false;
195         }
196         return true;
197     }
198 
199     char* lastDot = strrchr(dupModuleName, '.');
200     if (lastDot == nullptr) {
201         if (!isAppModule || !appLibPath_) {
202             if (sprintf_s(nativeModulePath[0], pathLength, "%s/lib%s%s%s",
203                 prefix, dupModuleName, zfix, soPostfix) == -1) {
204                 return false;
205             }
206             if (sprintf_s(nativeModulePath[1], pathLength, "%s/lib%s_napi%s%s",
207                 prefix, dupModuleName, zfix, soPostfix) == -1) {
208                 return false;
209             }
210         } else {
211             if (sprintf_s(nativeModulePath[0], pathLength, "%s/lib%s%s",
212                 prefix, dupModuleName, soPostfix) == -1) {
213                 return false;
214             }
215         }
216     } else {
217         char* afterDot = lastDot + 1;
218         if (*afterDot == '\0') {
219             return false;
220         }
221         *lastDot = '\0';
222         lengthOfModuleName = strlen(dupModuleName);
223         for (int32_t i = 0; i < lengthOfModuleName; i++) {
224             if (*(dupModuleName + i) == '.') {
225                 *(dupModuleName + i) = '/';
226             }
227         }
228         if (!isAppModule || !appLibPath_) {
229             if (sprintf_s(nativeModulePath[0], pathLength, "%s/%s/lib%s%s%s",
230                 prefix, dupModuleName, afterDot, zfix, soPostfix) == -1) {
231                 return false;
232             }
233             if (sprintf_s(nativeModulePath[1], pathLength, "%s/%s/lib%s_napi%s%s",
234                 prefix, dupModuleName, afterDot, zfix, soPostfix) == -1) {
235                 return false;
236             }
237         } else {
238             if (sprintf_s(nativeModulePath[0], pathLength, "%s/%s/lib%s%s",
239                 prefix, dupModuleName, afterDot, soPostfix) == -1) {
240                 return false;
241             }
242         }
243     }
244     return true;
245 }
246 
LoadModuleLibrary(const char * path,const bool isAppModule)247 LIBHANDLE NativeModuleManager::LoadModuleLibrary(const char* path, const bool isAppModule)
248 {
249     if (strlen(path) == 0) {
250         HILOG_ERROR("primary module path is empty");
251         return nullptr;
252     }
253     LIBHANDLE lib = nullptr;
254 #if defined(WINDOWS_PLATFORM)
255     lib = LoadLibrary(path);
256     if (lib == nullptr) {
257         HILOG_ERROR("LoadLibrary failed, error: %{public}d", GetLastError());
258     }
259 #elif defined(MAC_PLATFORM) || defined(__BIONIC__)
260     lib = dlopen(path, RTLD_LAZY);
261     if (lib == nullptr) {
262         HILOG_ERROR("dlopen failed: %{public}s", dlerror());
263     }
264 #else
265     if (isAppModule) {
266         lib = dlopen_ns(&ns_, path, RTLD_LAZY);
267     } else {
268         lib = dlopen(path, RTLD_LAZY);
269     }
270     if (lib == nullptr) {
271         HILOG_ERROR("dlopen failed: %{public}s", dlerror());
272     }
273 #endif
274     return lib;
275 }
276 
277 using NAPIGetJSCode = void (*)(const char** buf, int* bufLen);
FindNativeModuleByDisk(const char * moduleName,bool internal,const bool isAppModule,bool isArk)278 NativeModule* NativeModuleManager::FindNativeModuleByDisk(
279     const char* moduleName, bool internal, const bool isAppModule, bool isArk)
280 {
281     char nativeModulePath[NATIVE_PATH_NUMBER][NAPI_PATH_MAX];
282     nativeModulePath[0][0] = 0;
283     nativeModulePath[1][0] = 0;
284     if (!GetNativeModulePath(moduleName, isAppModule, nativeModulePath, NAPI_PATH_MAX)) {
285         HILOG_ERROR("get module filed");
286         return nullptr;
287     }
288 
289     // load primary module path first
290     char* loadPath = nativeModulePath[0];
291     HILOG_INFO("get primary module path: %{public}s", loadPath);
292     LIBHANDLE lib = LoadModuleLibrary(loadPath, isAppModule);
293     if (lib == nullptr) {
294         loadPath = nativeModulePath[1];
295         HILOG_WARN("primary module path load failed, try to load secondary module path: %{public}s", loadPath);
296         lib = LoadModuleLibrary(loadPath, isAppModule);
297         if (lib == nullptr) {
298             HILOG_ERROR("secondary module path load failed, load native module failed");
299             return nullptr;
300         }
301     }
302 
303     if (lastNativeModule_ && strcmp(lastNativeModule_->name, moduleName)) {
304         HILOG_WARN("moduleName '%{public}s' does not match plugin's name '%{public}s'",
305             moduleName, lastNativeModule_->name);
306     }
307 
308     if (!internal) {
309         char symbol[NAPI_PATH_MAX] = { 0 };
310         if (!isArk) {
311             if (sprintf_s(symbol, sizeof(symbol), "NAPI_%s_GetJSCode", moduleName) == -1) {
312                 LIBFREE(lib);
313                 return nullptr;
314             }
315         } else {
316             if (sprintf_s(symbol, sizeof(symbol), "NAPI_%s_GetABCCode", moduleName) == -1) {
317                 LIBFREE(lib);
318                 return nullptr;
319             }
320         }
321 
322         // replace '.' with '_'
323         for (char* p = strchr(symbol, '.'); p != nullptr; p = strchr(p + 1, '.')) {
324             *p = '_';
325         }
326 
327 
328         auto getJSCode = reinterpret_cast<NAPIGetJSCode>(LIBSYM(lib, symbol));
329         if (getJSCode != nullptr) {
330             const char* buf = nullptr;
331             int bufLen = 0;
332             getJSCode(&buf, &bufLen);
333             if (lastNativeModule_ != nullptr) {
334                 HILOG_INFO("get js code from module: bufLen: %{public}d", bufLen);
335                 lastNativeModule_->jsCode = buf;
336                 lastNativeModule_->jsCodeLen = bufLen;
337             }
338         } else {
339             HILOG_INFO("ignore: no %{public}s in %{public}s", symbol, loadPath);
340         }
341     }
342     if (lastNativeModule_) {
343         lastNativeModule_->moduleLoaded = true;
344     }
345     return lastNativeModule_;
346 }
347 
FindNativeModuleByCache(const char * moduleName)348 NativeModule* NativeModuleManager::FindNativeModuleByCache(const char* moduleName)
349 {
350     NativeModule* result = nullptr;
351     NativeModule* preNativeModule = nullptr;
352     for (NativeModule* temp = firstNativeModule_; temp != nullptr; temp = temp->next) {
353         if (!strcasecmp(temp->name, moduleName)) {
354             if (strcmp(temp->name, moduleName)) {
355                 HILOG_WARN("moduleName '%{public}s' does not match plugin's name '%{public}s'",
356                     moduleName, temp->name);
357             }
358             result = temp;
359             break;
360         }
361         preNativeModule = temp;
362     }
363 
364     if (result && !result->moduleLoaded) {
365         if (preNativeModule) {
366             preNativeModule->next = result->next;
367         } else {
368             firstNativeModule_ = firstNativeModule_->next;
369         }
370         result->next = nullptr;
371         lastNativeModule_->next = result;
372         lastNativeModule_ = result;
373         return nullptr;
374     }
375     return result;
376 }
377