• 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 <cstring>
19 #include <dirent.h>
20 #include <fstream>
21 #include <iostream>
22 #include <mutex>
23 #include <sstream>
24 
25 #ifdef ENABLE_HITRACE
26 #include "hitrace_meter.h"
27 #endif
28 #include "module_load_checker.h"
29 #include "native_engine/native_engine.h"
30 #include "securec.h"
31 #include "utils/log.h"
32 
33 #define NDK "ndk"
34 #define ALLOW_ALL_SHARED_LIBS "allow_all_shared_libs"
35 
36 namespace {
37     constexpr static int32_t NATIVE_PATH_NUMBER = 3;
38 } // namespace
39 
40 NativeModuleManager* NativeModuleManager::instance_ = NULL;
41 std::mutex g_instanceMutex;
42 
NativeModuleManager()43 NativeModuleManager::NativeModuleManager()
44 {
45     HILOG_INFO("enter");
46     pthread_mutex_init(&mutex_, nullptr);
47     moduleLoadChecker_ = std::make_unique<ModuleLoadChecker>();
48 }
49 
~NativeModuleManager()50 NativeModuleManager::~NativeModuleManager()
51 {
52     HILOG_INFO("enter");
53     {
54         std::lock_guard<std::mutex> lock(nativeModuleListMutex_);
55         NativeModule* nativeModule = firstNativeModule_;
56         while (nativeModule != nullptr) {
57             nativeModule = nativeModule->next;
58             delete[] firstNativeModule_->name;
59             if (firstNativeModule_->jsABCCode) {
60                 delete[] firstNativeModule_->jsABCCode;
61             }
62             delete firstNativeModule_;
63             firstNativeModule_ = nativeModule;
64         }
65         firstNativeModule_ = nullptr;
66         lastNativeModule_ = nullptr;
67     }
68 
69 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__) && !defined(IOS_PLATFORM) && \
70     !defined(LINUX_PLATFORM)
71     if (sharedLibsSonames_) {
72         delete[] sharedLibsSonames_;
73     }
74 #endif
75 
76     for (const auto& item : appLibPathMap_) {
77         delete[] item.second;
78     }
79     std::map<std::string, char*>().swap(appLibPathMap_);
80 
81     while (nativeEngineList_.size() > 0) {
82         NativeEngine* wraper = nativeEngineList_.begin()->second;
83         if (wraper != nullptr) {
84             delete wraper;
85             wraper = nullptr;
86         }
87         nativeEngineList_.erase(nativeEngineList_.begin());
88     }
89     pthread_mutex_destroy(&mutex_);
90 }
91 
GetInstance()92 NativeModuleManager* NativeModuleManager::GetInstance()
93 {
94     if (instance_ == NULL) {
95         std::lock_guard<std::mutex> lock(g_instanceMutex);
96         if (instance_ == NULL) {
97             instance_ = new NativeModuleManager();
98             HILOG_DEBUG("create native module manager instance");
99         }
100     }
101     return instance_;
102 }
103 
SetNativeEngine(std::string moduleKey,NativeEngine * nativeEngine)104 void NativeModuleManager::SetNativeEngine(std::string moduleKey, NativeEngine* nativeEngine)
105 {
106     HILOG_DEBUG("modulekey is '%{public}s'", moduleKey.c_str());
107     if (nativeEngine != nullptr) {
108         nativeEngine->SetModuleName(moduleKey);
109     }
110     std::lock_guard<std::mutex> lock(nativeEngineListMutex_);
111     nativeEngineList_.emplace(moduleKey, nativeEngine);
112 }
113 
EmplaceModuleLib(std::string moduleKey,const LIBHANDLE lib)114 void NativeModuleManager::EmplaceModuleLib(std::string moduleKey, const LIBHANDLE lib)
115 {
116     HILOG_DEBUG("modulekey is '%{public}s'", moduleKey.c_str());
117     std::lock_guard<std::mutex> lock(moduleLibMutex_);
118     if (lib != nullptr) {
119         moduleLibMap_.emplace(moduleKey, lib);
120     }
121 }
122 
RemoveModuleLib(const std::string moduleKey)123 bool NativeModuleManager::RemoveModuleLib(const std::string moduleKey)
124 {
125     HILOG_DEBUG("moduleKey is '%{public}s'", moduleKey.c_str());
126     bool deleted = false;
127     std::lock_guard<std::mutex> lock(moduleLibMutex_);
128     auto it = moduleLibMap_.find(moduleKey);
129     if (it != moduleLibMap_.end()) {
130         moduleLibMap_.erase(it);
131         HILOG_DEBUG("module '%{public}s' erased", moduleKey.c_str());
132         deleted = true;
133     }
134     return deleted;
135 }
136 
GetNativeModuleHandle(const std::string & moduleKey) const137 LIBHANDLE NativeModuleManager::GetNativeModuleHandle(const std::string& moduleKey) const
138 {
139     HILOG_DEBUG("moduleKey is '%{public}s'", moduleKey.c_str());
140     std::lock_guard<std::mutex> lock(moduleLibMutex_);
141     auto it = moduleLibMap_.find(moduleKey);
142     if (it == moduleLibMap_.end()) {
143         return nullptr;
144     }
145     return it->second;
146 }
147 
EmplaceModuleBuffer(const std::string moduleKey,const uint8_t * lib)148 void NativeModuleManager::EmplaceModuleBuffer(const std::string moduleKey, const uint8_t* lib)
149 {
150     HILOG_DEBUG("modulekey is '%{public}s'", moduleKey.c_str());
151     std::lock_guard<std::mutex> lock(moduleBufMutex_);
152     if (lib != nullptr) {
153         moduleBufMap_.emplace(moduleKey, lib);
154     }
155 }
156 
RemoveModuleBuffer(const std::string moduleKey)157 bool NativeModuleManager::RemoveModuleBuffer(const std::string moduleKey)
158 {
159     HILOG_DEBUG("moduleKey is '%{public}s'", moduleKey.c_str());
160     bool deleted = false;
161     std::lock_guard<std::mutex> lock(moduleBufMutex_);
162     auto it = moduleBufMap_.find(moduleKey);
163     if (it != moduleBufMap_.end()) {
164         moduleBufMap_.erase(it);
165         HILOG_DEBUG("module '%{public}s' erased", moduleKey.c_str());
166         deleted = true;
167     }
168     return deleted;
169 }
170 
GetBufferHandle(const std::string & moduleKey) const171 const uint8_t* NativeModuleManager::GetBufferHandle(const std::string& moduleKey) const
172 {
173     HILOG_DEBUG("moduleKey is '%{public}s'", moduleKey.c_str());
174     std::lock_guard<std::mutex> lock(moduleBufMutex_);
175     auto it = moduleBufMap_.find(moduleKey);
176     if (it == moduleBufMap_.end()) {
177         return nullptr;
178     }
179     return it->second;
180 }
181 
RemoveNativeModule(const std::string & moduleKey)182 bool NativeModuleManager::RemoveNativeModule(const std::string& moduleKey)
183 {
184     bool handleAbcRemoved = RemoveModuleBuffer(moduleKey);
185     bool handleRemoved = RemoveModuleLib(moduleKey);
186     bool moduleRemoved = RemoveNativeModuleByCache(moduleKey);
187 
188     HILOG_DEBUG("handleAbcRemoved is %{public}d, handleRemoved is %{public}d, moduleRemoved is %{public}d",
189         handleAbcRemoved, handleRemoved, moduleRemoved);
190     return ((handleRemoved || handleAbcRemoved) && moduleRemoved);
191 }
192 
UnloadNativeModule(const std::string & moduleKey)193 bool NativeModuleManager::UnloadNativeModule(const std::string& moduleKey)
194 {
195     HILOG_DEBUG("moduleKey is '%{public}s'", moduleKey.c_str());
196     LIBHANDLE handle = GetNativeModuleHandle(moduleKey);
197     if (handle == nullptr) {
198         HILOG_ERROR("failed to get native module handle.");
199         return false;
200     }
201 
202     if (RemoveNativeModule(moduleKey) == false) {
203         HILOG_ERROR("remove native module failed.");
204         return false;
205     }
206 
207     return UnloadModuleLibrary(handle);
208 }
209 
GetModuleFileName(const char * moduleName,bool isAppModule)210 std::string NativeModuleManager::GetModuleFileName(const char* moduleName, bool isAppModule)
211 {
212     HILOG_INFO("moduleName is '%{public}s', isAppModule is %{public}d", moduleName, isAppModule);
213 
214     std::string loadPath;
215     std::string name = isAppModule ? (prefix_ + "/" + moduleName) : moduleName;
216     NativeModule* module = FindNativeModuleByCache(name.c_str());
217     if (module != nullptr) {
218         char nativeModulePath[NATIVE_PATH_NUMBER][NAPI_PATH_MAX];
219         const char* pathKey = "default";
220         if (!GetNativeModulePath(moduleName, pathKey, "", isAppModule, nativeModulePath, NAPI_PATH_MAX)) {
221             HILOG_ERROR("get native module path failed");
222             return loadPath;
223         }
224         loadPath = nativeModulePath[0];
225         if (isAppModule && IsExistedPath(pathKey)) {
226             loadPath = std::string(appLibPathMap_[pathKey]) + "/" + nativeModulePath[0];
227         }
228         return loadPath;
229     }
230     HILOG_ERROR("get module file name failed");
231     return loadPath;
232 }
233 
Register(NativeModule * nativeModule)234 void NativeModuleManager::Register(NativeModule* nativeModule)
235 {
236     if (nativeModule == nullptr) {
237         HILOG_ERROR("nativeModule value is null");
238         return;
239     }
240 
241     HILOG_DEBUG("native module name is '%{public}s'", nativeModule->name);
242     std::lock_guard<std::mutex> lock(nativeModuleListMutex_);
243     if (!CreateNewNativeModule()) {
244         HILOG_ERROR("create new nativeModule failed");
245         return;
246     }
247 
248     const char *nativeModuleName = nativeModule->name == nullptr ? "" : nativeModule->name;
249     std::string appName = prefix_ + "/" + nativeModuleName;
250     const char *tmpName = isAppModule_ ? appName.c_str() : nativeModuleName;
251     char *moduleName = strdup(tmpName);
252     if (moduleName == nullptr) {
253         HILOG_ERROR("strdup failed. tmpName is %{public}s", tmpName);
254         return;
255     }
256 
257     lastNativeModule_->version = nativeModule->version;
258     lastNativeModule_->fileName = nativeModule->fileName;
259     lastNativeModule_->isAppModule = isAppModule_;
260     lastNativeModule_->name = moduleName;
261     lastNativeModule_->refCount = nativeModule->refCount;
262     lastNativeModule_->registerCallback = nativeModule->registerCallback;
263     lastNativeModule_->getJSCode = nativeModule->getJSCode;
264     lastNativeModule_->getABCCode = nativeModule->getABCCode;
265     lastNativeModule_->next = nullptr;
266     lastNativeModule_->moduleLoaded = true;
267 
268     HILOG_DEBUG("register module name is '%{public}s', isAppModule is %{public}d",
269         lastNativeModule_->name, isAppModule_);
270 }
271 
CreateNewNativeModule()272 bool NativeModuleManager::CreateNewNativeModule()
273 {
274     if (firstNativeModule_ == lastNativeModule_ && lastNativeModule_ == nullptr) {
275         firstNativeModule_ = new NativeModule();
276         if (firstNativeModule_ == nullptr) {
277             HILOG_ERROR("first NativeModule create failed");
278             return false;
279         }
280         lastNativeModule_ = firstNativeModule_;
281     } else {
282         auto next = new NativeModule();
283         if (next == nullptr) {
284             HILOG_ERROR("next NativeModule create failed");
285             return false;
286         }
287         if (lastNativeModule_) {
288             lastNativeModule_->next = next;
289             lastNativeModule_ = lastNativeModule_->next;
290         }
291     }
292     return true;
293 }
294 
295 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__) && !defined(IOS_PLATFORM) && \
296     !defined(LINUX_PLATFORM)
CreateSharedLibsSonames()297 void NativeModuleManager::CreateSharedLibsSonames()
298 {
299     HILOG_DEBUG("enter");
300     const char* allowList[] = {
301         // bionic library
302         "libc.so",
303         "libdl.so",
304         "libm.so",
305         "libz.so",
306         "libclang_rt.asan.so",
307         // z library
308         "libace_napi.z.so",
309         "libace_ndk.z.so",
310         "libbundle_ndk.z.so",
311         "libdeviceinfo_ndk.z.so",
312         "libEGL.so",
313         "libGLESv3.so",
314         "libhiappevent_ndk.z.so",
315         "libhuks_ndk.z.so",
316         "libhukssdk.z.so",
317         "libnative_drawing.so",
318         "libnative_window.so",
319         "libnative_buffer.so",
320         "libnative_vsync.so",
321         "libOpenSLES.so",
322         "libpixelmap_ndk.z.so",
323         "libimage_ndk.z.so",
324         "libimage_receiver_ndk.z.so",
325         "libimage_source_ndk.z.so",
326         "librawfile.z.so",
327         "libuv.so",
328         "libhilog.so",
329         "libnative_image.so",
330         "libnative_media_adec.so",
331         "libnative_media_aenc.so",
332         "libnative_media_codecbase.so",
333         "libnative_media_core.so",
334         "libnative_media_vdec.so",
335         "libnative_media_venc.so",
336         "libnative_media_avmuxer.so",
337         "libnative_media_avdemuxer.so",
338         "libnative_media_avsource.so",
339         "libnative_avscreen_capture.so",
340         "libavplayer.so",
341         // adaptor library
342         "libohosadaptor.so",
343         "libusb_ndk.z.so",
344         "libvulkan.so",
345     };
346 
347     size_t allowListLength = sizeof(allowList) / sizeof(char*);
348     int32_t sharedLibsSonamesLength = 1;
349     for (size_t i = 0; i < allowListLength; i++) {
350         sharedLibsSonamesLength += strlen(allowList[i]) + 1;
351     }
352     sharedLibsSonames_ = new char[sharedLibsSonamesLength];
353     int32_t cursor = 0;
354     for (size_t i = 0; i < allowListLength; i++) {
355         if (sprintf_s(sharedLibsSonames_ + cursor, sharedLibsSonamesLength - cursor, "%s:", allowList[i]) == -1) {
356             delete[] sharedLibsSonames_;
357             sharedLibsSonames_ = nullptr;
358             return;
359         }
360         cursor += strlen(allowList[i]) + 1;
361     }
362     sharedLibsSonames_[cursor] = '\0';
363 }
364 #endif
365 
CreateLdNamespace(const std::string moduleName,const char * lib_ld_path,const bool & isSystemApp)366 void NativeModuleManager::CreateLdNamespace(const std::string moduleName, const char* lib_ld_path,
367                                             [[maybe_unused]] const bool& isSystemApp)
368 {
369 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__) && !defined(IOS_PLATFORM) && \
370     !defined(LINUX_PLATFORM)
371     Dl_namespace current_ns;
372     Dl_namespace ns;
373 
374     // Create module ns.
375     std::string nsName = "moduleNs_" + moduleName;
376     dlns_init(&ns, nsName.c_str());
377     dlns_get(nullptr, &current_ns);
378 
379     Dl_namespace ndk_ns;
380     dlns_get(NDK, &ndk_ns);
381 
382     if (isSystemApp) {
383         /*
384          * The app's so may have the same name as the system library, LOCAL_NS_PREFERED means linker will check
385          * and use the app's so first.
386          */
387         dlns_create2(&ns, lib_ld_path, LOCAL_NS_PREFERED);
388         // Performs a namespace check on the full path passed directly or the full path converted after setting rpath.
389         dlns_set_namespace_separated(nsName.c_str(), true);
390         // Allows access to subdirectories of this directory for shared objects (so).
391         dlns_set_namespace_permitted_paths(nsName.c_str(), lib_ld_path);
392         // System app can visit all ndk and default ns libs.
393         if (strlen(ndk_ns.name) > 0) {
394             dlns_inherit(&ns, &ndk_ns, ALLOW_ALL_SHARED_LIBS);
395             dlns_inherit(&ndk_ns, &current_ns, ALLOW_ALL_SHARED_LIBS);
396             dlns_inherit(&current_ns, &ndk_ns, ALLOW_ALL_SHARED_LIBS);
397             dlns_inherit(&ns, &current_ns, ALLOW_ALL_SHARED_LIBS);
398         }
399     } else {
400         dlns_create2(&ns, lib_ld_path, 0);
401         // Performs a namespace check on the full path passed directly or the full path converted after setting rpath.
402         dlns_set_namespace_separated(nsName.c_str(), true);
403         // Allows access to subdirectories of this directory for shared objects (so).
404         dlns_set_namespace_permitted_paths(nsName.c_str(), lib_ld_path);
405         // Non-system app can visit all ndk ns libs and default ns shared libs.
406         if (!sharedLibsSonames_) {
407             CreateSharedLibsSonames();
408         }
409         dlns_inherit(&ns, &current_ns, sharedLibsSonames_);
410         if (strlen(ndk_ns.name) > 0) {
411             dlns_inherit(&ns, &ndk_ns, ALLOW_ALL_SHARED_LIBS);
412             dlns_inherit(&ndk_ns, &current_ns, ALLOW_ALL_SHARED_LIBS);
413             dlns_inherit(&current_ns, &ndk_ns, ALLOW_ALL_SHARED_LIBS);
414         }
415     }
416 
417     nsMap_[moduleName] = ns;
418 
419     HILOG_DEBUG("end. moduleName: %{public}s, path: %{public}s", moduleName.c_str(), lib_ld_path);
420 #endif
421 }
422 
SetAppLibPath(const std::string & moduleName,const std::vector<std::string> & appLibPath,const bool & isSystemApp)423 void NativeModuleManager::SetAppLibPath(const std::string& moduleName, const std::vector<std::string>& appLibPath,
424                                         const bool& isSystemApp)
425 {
426     HILOG_DEBUG("moduleName is %{public}s, isisSystemApp is %{public}d", moduleName.c_str(), isSystemApp);
427 
428     std::string tmpPath = "";
429     for (size_t i = 0; i < appLibPath.size(); i++) {
430         if (appLibPath[i].empty()) {
431             continue;
432         }
433         tmpPath += appLibPath[i];
434         tmpPath += ":";
435     }
436     if (tmpPath.back() == ':') {
437         tmpPath.pop_back();
438     }
439 
440     char *tmp = strdup(tmpPath.c_str());
441     if (tmp == nullptr) {
442         HILOG_ERROR("strdup failed. tmpPath is %{public}s", tmpPath.c_str());
443         return;
444     }
445 
446     if (appLibPathMap_[moduleName] != nullptr) {
447         delete[] appLibPathMap_[moduleName];
448     }
449     appLibPathMap_[moduleName] = tmp;
450     CreateLdNamespace(moduleName, tmp, isSystemApp);
451     HILOG_DEBUG("path: %{public}s", appLibPathMap_[moduleName]);
452 }
453 
CheckModuleRestricted(const std::string & moduleName)454 bool NativeModuleManager::CheckModuleRestricted(const std::string& moduleName)
455 {
456     const std::string whiteList[] = {
457         "worker",
458     };
459 
460     size_t listLen = sizeof(whiteList) / sizeof(whiteList[0]);
461     for (size_t i = 0; i < listLen; ++i) {
462         if (moduleName == whiteList[i]) {
463             HILOG_DEBUG("module %{public}s found in whitelist", moduleName.c_str());
464             return false;
465         }
466     }
467 
468     HILOG_DEBUG("module %{public}s does not found in whitelist", moduleName.c_str());
469     return true;
470 }
471 
MoveApiAllowListCheckerPtr(std::unique_ptr<ApiAllowListChecker> & apiAllowListChecker,NativeModule * nativeModule)472 void NativeModuleManager::MoveApiAllowListCheckerPtr(
473     std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker, NativeModule* nativeModule)
474 {
475     if (apiAllowListChecker != nullptr) {
476         nativeModule->apiAllowListChecker.reset(apiAllowListChecker.release());
477     }
478 }
479 
LoadNativeModule(const char * moduleName,const char * path,bool isAppModule,bool internal,const char * relativePath,bool isModuleRestricted)480 NativeModule* NativeModuleManager::LoadNativeModule(const char* moduleName,
481     const char* path, bool isAppModule, bool internal, const char* relativePath, bool isModuleRestricted)
482 {
483     if (moduleName == nullptr || relativePath == nullptr) {
484         HILOG_ERROR("moduleName or relativePath is nullptr");
485         return nullptr;
486     }
487 
488     HILOG_DEBUG("moduleName is %{public}s, path is %{public}s, relativePath is %{public}s",
489         moduleName, path, relativePath);
490     // we only check system so in restricted runtime.
491     if (isModuleRestricted == true && isAppModule == false) {
492         if (CheckModuleRestricted(moduleName) == true) {
493             HILOG_WARN("module is not allowed to load.");
494             return nullptr;
495         }
496     }
497 
498     std::unique_ptr<ApiAllowListChecker> apiAllowListChecker = nullptr;
499     if (moduleLoadChecker_ && !moduleLoadChecker_->DiskCheckOnly() &&
500         !moduleLoadChecker_->CheckModuleLoadable(moduleName, apiAllowListChecker)) {
501         HILOG_ERROR("Block module name: %{public}s", moduleName);
502         return nullptr;
503     }
504 #ifdef ANDROID_PLATFORM
505     std::string strModule(moduleName);
506     std::string strCutName = strModule;
507     if (path != nullptr) {
508         if (IsExistedPath(path)) {
509             strModule = path;
510         }
511         prefix_ = "default";
512         strModule = prefix_ + '/' + moduleName;
513     } else {
514         path = "default";
515         if (strModule.find(".") != std::string::npos) {
516             char* temp = const_cast<char*>(strCutName.c_str());
517             for (char* p = strchr(temp, '.'); p != nullptr; p = strchr(p + 1, '.')) {
518                 *p = '_';
519             }
520         }
521     }
522 #endif
523 
524     (void)pthread_mutex_lock(&mutex_);
525 
526 #ifdef ANDROID_PLATFORM
527     NativeModule* nativeModule = FindNativeModuleByCache(strModule.c_str());
528 #else
529     std::string key(moduleName);
530     isAppModule_ = isAppModule;
531     if (isAppModule) {
532         prefix_ = "default";
533         if (path && IsExistedPath(path)) {
534             prefix_ = path;
535         }
536         key = prefix_ + '/' + moduleName;
537         HILOG_INFO("key is %{public}s", key.c_str());
538     }
539     NativeModule* nativeModule = FindNativeModuleByCache(key.c_str());
540 #endif
541 
542 #ifndef IOS_PLATFORM
543     if (nativeModule == nullptr) {
544 #ifdef ANDROID_PLATFORM
545         HILOG_DEBUG("module '%{public}s' does not in cache", strCutName.c_str());
546         nativeModule = FindNativeModuleByDisk(strCutName.c_str(), path, relativePath, internal, isAppModule);
547 #else
548         HILOG_DEBUG("module '%{public}s' does not in cache", moduleName);
549         nativeModule = FindNativeModuleByDisk(moduleName, prefix_.c_str(), relativePath, internal, isAppModule);
550 #endif
551     }
552 #endif
553     MoveApiAllowListCheckerPtr(apiAllowListChecker, nativeModule);
554 
555     (void) pthread_mutex_unlock(&mutex_);
556 
557     HILOG_DEBUG("load native module %{public}s", (nativeModule == nullptr) ? "failed" : "success");
558     return nativeModule;
559 }
560 
GetNativeModulePath(const char * moduleName,const char * path,const char * relativePath,bool isAppModule,char nativeModulePath[][NAPI_PATH_MAX],int32_t pathLength)561 bool NativeModuleManager::GetNativeModulePath(const char* moduleName, const char* path,
562     const char* relativePath, bool isAppModule, char nativeModulePath[][NAPI_PATH_MAX], int32_t pathLength)
563 {
564 #ifdef WINDOWS_PLATFORM
565     const char* soPostfix = ".dll";
566     const char* zfix = "";
567     std::string sysPrefix("./module");
568 #elif defined(MAC_PLATFORM)
569     const char* soPostfix = ".dylib";
570     const char* zfix = "";
571     std::string sysPrefix("./module");
572 #elif defined(_ARM64_) || defined(SIMULATOR)
573     const char* soPostfix = ".so";
574     const char* zfix = ".z";
575     std::string sysPrefix("/system/lib64/module");
576 #elif defined(LINUX_PLATFORM)
577     const char* soPostfix = ".so";
578     const char* zfix = "";
579     std::string sysPrefix("./module");
580 #else
581     const char* soPostfix = ".so";
582     const char* zfix = ".z";
583     std::string sysPrefix("/system/lib/module");
584 #endif
585     const char* abcfix = ".abc";
586     std::string sysAbcPrefix("/system/etc/abc");
587 
588 #ifdef ANDROID_PLATFORM
589     isAppModule = true;
590 #endif
591     int32_t lengthOfModuleName = strlen(moduleName);
592     char dupModuleName[NAPI_PATH_MAX] = { 0 };
593     if (strcpy_s(dupModuleName, NAPI_PATH_MAX, moduleName) != 0) {
594         HILOG_ERROR("strcpy_s moduleName '%{public}s' failed", moduleName);
595         return false;
596     }
597 
598     const char* prefix = nullptr;
599     if (isAppModule && IsExistedPath(path)) {
600         prefix = appLibPathMap_[path];
601 #ifdef ANDROID_PLATFORM
602         for (int32_t i = 0; i < lengthOfModuleName; i++) {
603             dupModuleName[i] = tolower(dupModuleName[i]);
604         }
605 #endif
606     } else {
607         if (relativePath[0]) {
608             if (previewSearchPath_.empty()) {
609                 sysPrefix = sysPrefix + "/" + relativePath;
610             } else {
611                 sysPrefix = previewSearchPath_ + "/module";
612             }
613         }
614         prefix = sysPrefix.c_str();
615         for (int32_t i = 0; i < lengthOfModuleName; i++) {
616             dupModuleName[i] = tolower(dupModuleName[i]);
617         }
618     }
619 
620     int32_t lengthOfPostfix = strlen(soPostfix);
621     if ((lengthOfModuleName > lengthOfPostfix) &&
622         (strcmp(dupModuleName + lengthOfModuleName - lengthOfPostfix, soPostfix) == 0)) {
623         if (sprintf_s(nativeModulePath[0], pathLength, "%s/%s", prefix, dupModuleName) == -1) {
624             return false;
625         }
626         return true;
627     }
628 
629     char* lastDot = strrchr(dupModuleName, '.');
630     if (lastDot == nullptr) {
631         if (!isAppModule || !IsExistedPath(path)) {
632 #ifdef ANDROID_PLATFORM
633             if (sprintf_s(nativeModulePath[0], pathLength, "lib%s%s", dupModuleName, soPostfix) == -1) {
634                 return false;
635             }
636 #else
637             if (sprintf_s(nativeModulePath[0], pathLength, "%s/lib%s%s%s",
638                 prefix, dupModuleName, zfix, soPostfix) == -1) {
639                 return false;
640             }
641 #endif
642             if (sprintf_s(nativeModulePath[1], pathLength, "%s/lib%s_napi%s%s",
643                 prefix, dupModuleName, zfix, soPostfix) == -1) {
644                 return false;
645             }
646 
647             if (sprintf_s(nativeModulePath[2], pathLength, "%s/%s%s", // 2 : Element index value
648                 sysAbcPrefix.c_str(), dupModuleName, abcfix) == -1) {
649                 return false;
650             }
651         } else {
652 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__) && !defined(IOS_PLATFORM) && \
653     !defined(LINUX_PLATFORM)
654             if (sprintf_s(nativeModulePath[0], pathLength, "lib%s%s", dupModuleName, soPostfix) == -1) {
655                 return false;
656             }
657 #elif defined(ANDROID_PLATFORM)
658             std::istringstream iss(prefix);
659             std::string libPath;
660             while (std::getline(iss, libPath, ':')) {
661                 std::ifstream dupModuleFile(libPath + "/lib" + dupModuleName + soPostfix);
662                 std::ifstream moduleFile(libPath + "/lib" + moduleName + soPostfix);
663                 if(dupModuleFile.good() || moduleFile.good()) {
664                     break;
665                 }
666             }
667             if (sprintf_s(nativeModulePath[0], pathLength, "%s/lib%s%s", libPath.c_str(),
668                 dupModuleName, soPostfix) == -1) {
669                 return false;
670             }
671 #else
672             if (sprintf_s(nativeModulePath[0], pathLength, "%s/lib%s%s", prefix, dupModuleName, soPostfix) == -1) {
673                 return false;
674             }
675 #endif
676 #ifdef ANDROID_PLATFORM
677             if (sprintf_s(nativeModulePath[1], pathLength, "%s/lib%s%s", libPath.c_str(),
678                 moduleName, soPostfix) == -1) {
679                 return false;
680             }
681 #endif
682         }
683     } else {
684         char* afterDot = lastDot + 1;
685         if (*afterDot == '\0') {
686             return false;
687         }
688         *lastDot = '\0';
689         lengthOfModuleName = strlen(dupModuleName);
690         for (int32_t i = 0; i < lengthOfModuleName; i++) {
691             if (*(dupModuleName + i) == '.') {
692                 *(dupModuleName + i) = '/';
693             }
694         }
695         if (!isAppModule || !IsExistedPath(path)) {
696             if (sprintf_s(nativeModulePath[0], pathLength, "%s/%s/lib%s%s%s",
697                 prefix, dupModuleName, afterDot, zfix, soPostfix) == -1) {
698                 return false;
699             }
700             if (sprintf_s(nativeModulePath[1], pathLength, "%s/%s/lib%s_napi%s%s",
701                 prefix, dupModuleName, afterDot, zfix, soPostfix) == -1) {
702                 return false;
703             }
704             if (sprintf_s(nativeModulePath[2], pathLength, "%s/%s/%s%s", // 2 : Element index value
705                 sysAbcPrefix.c_str(), dupModuleName, afterDot, abcfix) == -1) {
706                 return false;
707             }
708         } else {
709 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__) && !defined(IOS_PLATFORM) && \
710     !defined(LINUX_PLATFORM)
711             if (sprintf_s(nativeModulePath[0], pathLength, "lib%s%s", afterDot, soPostfix) == -1) {
712                 return false;
713             }
714 #else
715             if (sprintf_s(nativeModulePath[0], pathLength, "%s/%s/lib%s%s",
716                 prefix, dupModuleName, afterDot, soPostfix) == -1) {
717                 return false;
718             }
719 #endif
720 #ifdef ANDROID_PLATFORM
721             if (sprintf_s(nativeModulePath[1], pathLength, "%s/%s/lib%s%s",
722                 prefix, moduleName, afterDot, soPostfix) == -1) {
723                 return false;
724             }
725 #endif
726         }
727     }
728     return true;
729 }
730 
LoadModuleLibrary(std::string & moduleKey,const char * path,const char * pathKey,const bool isAppModule)731 LIBHANDLE NativeModuleManager::LoadModuleLibrary(std::string& moduleKey, const char* path,
732                                                  const char* pathKey, const bool isAppModule)
733 {
734     if (strlen(path) == 0) {
735         HILOG_ERROR("primary module path is empty");
736         return nullptr;
737     }
738 
739     LIBHANDLE lib = nullptr;
740     lib = GetNativeModuleHandle(moduleKey);
741     if (lib != nullptr) {
742         HILOG_DEBUG("get native module handle success. moduleKey is %{public}s", moduleKey.c_str());
743         return lib;
744     }
745 
746     HILOG_INFO("path: %{public}s, pathKey: %{public}s, isAppModule: %{public}d", path, pathKey, isAppModule);
747 #ifdef ENABLE_HITRACE
748     StartTrace(HITRACE_TAG_ACE, path);
749 #endif
750 #if defined(WINDOWS_PLATFORM)
751     lib = LoadLibrary(path);
752     if (lib == nullptr) {
753         HILOG_WARN("LoadLibrary failed, error: %{public}d", GetLastError());
754     }
755 #elif defined(MAC_PLATFORM) || defined(__BIONIC__) || defined(LINUX_PLATFORM)
756     lib = dlopen(path, RTLD_LAZY);
757     if (lib == nullptr) {
758         HILOG_WARN("dlopen failed: %{public}s", dlerror());
759     }
760 
761 #elif defined(IOS_PLATFORM)
762     lib = nullptr;
763 #else
764     if (isAppModule && IsExistedPath(pathKey)) {
765         Dl_namespace ns = nsMap_[pathKey];
766         lib = dlopen_ns(&ns, path, RTLD_LAZY);
767     } else {
768         lib = dlopen(path, RTLD_LAZY);
769     }
770     if (lib == nullptr) {
771         HILOG_WARN("dlopen failed: %{public}s", dlerror());
772     }
773 #endif
774 #ifdef ENABLE_HITRACE
775     FinishTrace(HITRACE_TAG_ACE);
776 #endif
777     EmplaceModuleLib(moduleKey, lib);
778 
779     return lib;
780 }
781 
GetFileBuffer(const std::string & filePath,const std::string & moduleKey,size_t & len)782 const uint8_t* NativeModuleManager::GetFileBuffer(const std::string& filePath,
783     const std::string& moduleKey, size_t &len)
784 {
785     const uint8_t* lib = nullptr;
786     std::ifstream inFile(filePath, std::ios::ate | std::ios::binary);
787     if (!inFile.is_open()) {
788         HILOG_ERROR("%{public}s is not existed.", filePath.c_str());
789         return lib;
790     }
791     len = static_cast<size_t>(inFile.tellg());
792     std::string abcModuleKey = moduleKey;
793     lib = GetBufferHandle(abcModuleKey);
794     if (lib != nullptr) {
795         HILOG_DEBUG("get native abc handle success. moduleKey is %{public}s", moduleKey.c_str());
796         inFile.close();
797         return lib;
798     }
799 
800     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(len);
801     inFile.seekg(0);
802     inFile.read(reinterpret_cast<char*>(buffer.get()), len);
803     inFile.close();
804     lib = buffer.release();
805     EmplaceModuleBuffer(abcModuleKey, lib);
806     return lib;
807 }
808 
UnloadModuleLibrary(LIBHANDLE handle)809 bool NativeModuleManager::UnloadModuleLibrary(LIBHANDLE handle)
810 {
811     if (handle == nullptr) {
812         HILOG_WARN("handle is nullptr");
813         return false;
814     }
815 #if !defined(WINDOWS_PLATFORM) && !defined(IOS_PLATFORM)
816     if (!dlclose(handle)) {
817         return true;
818     }
819     HILOG_WARN("dlclose failed: %{public}s", dlerror());
820 #endif
821     return false;
822 }
823 
FindNativeModuleByDisk(const char * moduleName,const char * path,const char * relativePath,bool internal,const bool isAppModule)824 NativeModule* NativeModuleManager::FindNativeModuleByDisk(
825     const char* moduleName, const char* path, const char* relativePath, bool internal, const bool isAppModule)
826 {
827     char nativeModulePath[NATIVE_PATH_NUMBER][NAPI_PATH_MAX];
828     nativeModulePath[0][0] = 0;
829     nativeModulePath[1][0] = 0;
830     nativeModulePath[2][0] = 0; // 2 : Element index value
831     if (!GetNativeModulePath(moduleName, path, relativePath, isAppModule, nativeModulePath, NAPI_PATH_MAX)) {
832         HILOG_WARN("get module '%{public}s' path failed", moduleName);
833         return nullptr;
834     }
835     std::unique_ptr<ApiAllowListChecker> apiAllowListChecker = nullptr;
836     if (moduleLoadChecker_ && !moduleLoadChecker_->CheckModuleLoadable(moduleName, apiAllowListChecker)) {
837         HILOG_ERROR("module '%{public}s' is not allowed to load", moduleName);
838         return nullptr;
839     }
840 
841     std::string moduleKey(moduleName);
842     if (isAppModule) {
843         moduleKey = path;
844         moduleKey = moduleKey + '/' + moduleName;
845     }
846 
847     // load primary module path first
848     char* loadPath = nativeModulePath[0];
849     HILOG_DEBUG("moduleName: %{public}s. get primary module path: %{public}s", moduleName, loadPath);
850     LIBHANDLE lib = LoadModuleLibrary(moduleKey, loadPath, path, isAppModule);
851     if (lib == nullptr) {
852         loadPath = nativeModulePath[1];
853         HILOG_DEBUG("try to load secondary module path: %{public}s", loadPath);
854         lib = LoadModuleLibrary(moduleKey, loadPath, path, isAppModule);
855     }
856 
857     const uint8_t* abcBuffer = nullptr;
858     size_t len = 0;
859     if (lib == nullptr) {
860         loadPath = nativeModulePath[2]; // 2 : Element index value
861         HILOG_DEBUG("try to load abc module path: %{public}s", loadPath);
862         abcBuffer = GetFileBuffer(loadPath, moduleKey, len);
863         if (!abcBuffer) {
864             HILOG_ERROR("all path load module '%{public}s' failed", moduleName);
865             return nullptr;
866         }
867     }
868 
869     std::lock_guard<std::mutex> lock(nativeModuleListMutex_);
870     if (lastNativeModule_ && !abcBuffer && strcmp(lastNativeModule_->name, moduleKey.c_str())) {
871         HILOG_WARN("moduleName '%{public}s' seems not match plugin's name '%{public}s'",
872                    moduleKey.c_str(), lastNativeModule_->name);
873     }
874 
875     if (!internal) {
876         char symbol[NAPI_PATH_MAX] = { 0 };
877         if (sprintf_s(symbol, sizeof(symbol), "NAPI_%s_GetABCCode", moduleKey.c_str()) == -1) {
878             if (lib != nullptr) {
879                 LIBFREE(lib);
880             }
881             HILOG_ERROR("sprintf_s failed. moduleKey is %{public}s", moduleKey.c_str());
882             return nullptr;
883         }
884 
885         // replace '.' and '/' with '_'
886         for (char* p = strchr(symbol, '.'); p != nullptr; p = strchr(p + 1, '.')) {
887             *p = '_';
888         }
889         for (char* p = strchr(symbol, '/'); p != nullptr; p = strchr(p + 1, '/')) {
890             *p = '_';
891         }
892 
893         if (lib != nullptr) {
894             auto getJSCode = reinterpret_cast<GetJSCodeCallback>(LIBSYM(lib, symbol));
895             if (getJSCode == nullptr) {
896                 HILOG_DEBUG("ignore: no %{public}s in %{public}s", symbol, loadPath);
897                 MoveApiAllowListCheckerPtr(apiAllowListChecker, lastNativeModule_);
898                 return lastNativeModule_;
899             }
900             const char* buf = nullptr;
901             int bufLen = 0;
902             getJSCode(&buf, &bufLen);
903             if (lastNativeModule_) {
904                 HILOG_DEBUG("get js code from module: bufLen: %{public}d", bufLen);
905                 lastNativeModule_->jsCode = buf;
906                 lastNativeModule_->jsCodeLen = bufLen;
907             }
908         } else {
909             RegisterByBuffer(moduleKey, abcBuffer, len);
910         }
911     }
912     if (lastNativeModule_) {
913         lastNativeModule_->moduleLoaded = true;
914         HILOG_DEBUG("last native module name is %{public}s", lastNativeModule_->name);
915         MoveApiAllowListCheckerPtr(apiAllowListChecker, lastNativeModule_);
916     }
917     return lastNativeModule_;
918 }
919 
RegisterByBuffer(const std::string & moduleKey,const uint8_t * abcBuffer,size_t len)920 void NativeModuleManager::RegisterByBuffer(const std::string& moduleKey, const uint8_t* abcBuffer, size_t len)
921 {
922     HILOG_DEBUG("native module name is '%{public}s'", moduleKey.c_str());
923     if (!CreateNewNativeModule()) {
924         HILOG_ERROR("create new nativeModule failed");
925         return;
926     }
927 
928     char *moduleName = strdup(moduleKey.c_str());
929     if (moduleName == nullptr) {
930         HILOG_ERROR("strdup failed. tmpName is %{public}s", moduleKey.c_str());
931         return;
932     }
933     lastNativeModule_->name = moduleName;
934     lastNativeModule_->jsABCCode = abcBuffer;
935     lastNativeModule_->jsCodeLen = static_cast<int32_t>(len);
936     lastNativeModule_->next = nullptr;
937 
938     HILOG_INFO("NativeModule Register by buffer success. module name is '%{public}s'", lastNativeModule_->name);
939 }
940 
RemoveNativeModuleByCache(const std::string & moduleKey)941 bool NativeModuleManager::RemoveNativeModuleByCache(const std::string& moduleKey)
942 {
943     std::lock_guard<std::mutex> lock(nativeModuleListMutex_);
944 
945     if (firstNativeModule_ == nullptr) {
946         HILOG_WARN("NativeModule list is empty");
947         return false;
948     }
949 
950     NativeModule* nativeModule = firstNativeModule_;
951     if (!strcasecmp(nativeModule->name, moduleKey.c_str())) {
952         if (firstNativeModule_ == lastNativeModule_) {
953             lastNativeModule_ = nullptr;
954         }
955         firstNativeModule_ = firstNativeModule_->next;
956         delete[] nativeModule->name;
957         if (firstNativeModule_->jsABCCode) {
958             delete[] firstNativeModule_->jsABCCode;
959         }
960         delete nativeModule;
961         HILOG_DEBUG("module %{public}s deleted from cache", moduleKey.c_str());
962         return true;
963     }
964 
965     bool moduleDeleted = false;
966     NativeModule* prev = firstNativeModule_;
967     NativeModule* curr = prev->next;
968     while (curr != nullptr) {
969         if (!strcasecmp(curr->name, moduleKey.c_str())) {
970             if (curr == lastNativeModule_) {
971                 lastNativeModule_ = prev;
972             }
973             prev->next = curr->next;
974             delete[] curr->name;
975             if (firstNativeModule_->jsABCCode) {
976                 delete[] firstNativeModule_->jsABCCode;
977             }
978             delete curr;
979             HILOG_DEBUG("module %{public}s deleted from cache", moduleKey.c_str());
980             moduleDeleted = true;
981             break;
982         }
983         prev = prev->next;
984         curr = prev->next;
985     }
986 
987     return moduleDeleted;
988 }
989 
FindNativeModuleByCache(const char * moduleName)990 NativeModule* NativeModuleManager::FindNativeModuleByCache(const char* moduleName)
991 {
992     NativeModule* result = nullptr;
993     NativeModule* preNativeModule = nullptr;
994 
995     std::lock_guard<std::mutex> lock(nativeModuleListMutex_);
996     for (NativeModule* temp = firstNativeModule_; temp != nullptr; temp = temp->next) {
997         if (!strcasecmp(temp->name, moduleName)) {
998             if (strcmp(temp->name, moduleName)) {
999                 HILOG_WARN("moduleName '%{public}s' seems not match plugin's name '%{public}s'",
1000                            moduleName, temp->name);
1001             }
1002             result = temp;
1003             break;
1004         }
1005         preNativeModule = temp;
1006     }
1007 
1008     if (result && !result->moduleLoaded) {
1009         if (result == lastNativeModule_) {
1010             HILOG_WARN("module '%{public}s' does not load", result->name);
1011             return nullptr;
1012         }
1013         if (preNativeModule) {
1014             preNativeModule->next = result->next;
1015         } else {
1016             firstNativeModule_ = firstNativeModule_->next;
1017         }
1018         result->next = nullptr;
1019         lastNativeModule_->next = result;
1020         lastNativeModule_ = result;
1021         HILOG_WARN("module '%{public}s' does not found", moduleName);
1022         return nullptr;
1023     }
1024     HILOG_DEBUG("module '%{public}s' found in cache", moduleName);
1025     return result;
1026 }
1027 
IsExistedPath(const char * pathKey) const1028 bool NativeModuleManager::IsExistedPath(const char* pathKey) const
1029 {
1030     HILOG_DEBUG("pathKey is '%{public}s'", pathKey);
1031     return pathKey && appLibPathMap_.find(pathKey) != appLibPathMap_.end();
1032 }
1033 
SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate> & moduleCheckerDelegate)1034 void NativeModuleManager::SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate>& moduleCheckerDelegate)
1035 {
1036     HILOG_DEBUG("enter");
1037     if (!moduleLoadChecker_) {
1038         HILOG_ERROR("SetModuleLoadChecker failed, moduleLoadChecker_ is nullptr");
1039         return;
1040     }
1041     moduleLoadChecker_->SetDelegate(moduleCheckerDelegate);
1042 }
1043 
SetPreviewSearchPath(const std::string & previewSearchPath)1044 void NativeModuleManager::SetPreviewSearchPath(const std::string& previewSearchPath)
1045 {
1046     HILOG_DEBUG("previewSearchPath is '%{public}s'", previewSearchPath.c_str());
1047     previewSearchPath_ = previewSearchPath;
1048 }
1049