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 #ifndef FOUNDATION_ACE_NAPI_MODULE_MANAGER_NATIVE_MODULE_MANAGER_H
17 #define FOUNDATION_ACE_NAPI_MODULE_MANAGER_NATIVE_MODULE_MANAGER_H
18 
19 #include <cstdint>
20 #include <map>
21 #include <mutex>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <vector>
25 #include <string>
26 #include <pthread.h>
27 
28 #include "module_load_checker.h"
29 #include "utils/macros.h"
30 #include "interfaces/inner_api/napi/native_node_api.h"
31 
32 #ifdef WINDOWS_PLATFORM
33 #include <winsock2.h>
34 #include <windows.h>
35 using LIBHANDLE = HMODULE;
36 #define LIBFREE FreeLibrary
37 #define LIBSYM GetProcAddress
38 #else
39 #include <dlfcn.h>
40 using LIBHANDLE = void*;
41 #define LIBFREE dlclose
42 #define LIBSYM dlsym
43 #endif
44 
45 #define NAPI_PATH_MAX 4096
46 
47 class NativeValue;
48 
49 class NativeEngine;
50 
51 typedef napi_value (*RegisterCallback)(napi_env, napi_value);
52 
53 typedef void (*GetJSCodeCallback)(const char** buf, int* bufLen);
54 
55 struct NativeModule {
56     const char* name = nullptr;       /* .nm_modname from native c++ register info */
57     const char* moduleName = nullptr; /* moduleName required or imported */
58     const char* fileName = nullptr;
59     const char* systemFilePath = nullptr;
60     RegisterCallback registerCallback = nullptr;
61     GetJSCodeCallback getABCCode = nullptr;
62     GetJSCodeCallback getJSCode = nullptr;
63     int32_t version = 0;
64     uint32_t flags = 0;
65     uint32_t refCount = 0;
66     NativeModule* next = nullptr;
67     const char* jsCode = nullptr;
68     const uint8_t* jsABCCode = nullptr;
69     int32_t jsCodeLen = 0;
70     bool moduleLoaded = false;
71     bool isAppModule = false;
72     std::unique_ptr<ApiAllowListChecker> apiAllowListChecker = nullptr;
73 };
74 
75 struct NativeModuleHeadTailStruct {
76     NativeModule* headNativeModule = nullptr;
77     NativeModule* tailNativeModule = nullptr;
78 };
79 class NAPI_EXPORT NativeModuleManager {
80 public:
81     static NativeModuleManager* GetInstance();
82     static uint64_t Release();
83 
84     void Register(NativeModule* nativeModule);
85     void SetAppLibPath(const std::string& moduleName, const std::vector<std::string>& appLibPath,
86                        const bool& isSystemApp = false);
87     NativeModule* LoadNativeModule(const char* moduleName, const char* path, bool isAppModule,
88         std::string& errInfo, bool internal = false, const char* relativePath = "");
89     void SetNativeEngine(std::string moduleName, NativeEngine* nativeEngine);
90     bool UnloadNativeModule(const std::string& moduleKey);
91     std::string GetModuleFileName(const char* moduleName, bool isAppModule);
92 
93     /**
94      * @brief Set the path for searching napi dynamic libraries, only for the previewer.
95      *
96      * @param previewSearchPath the path for searching napi dynamic libraries
97      */
98     void SetPreviewSearchPath(const std::string& previewSearchPath);
99 
100     /**
101      * @brief Set the Module Load Checker delegate
102      *
103      * @param moduleCheckerDelegate The Module Load Checker delegate
104      */
105     void SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate>& moduleCheckerDelegate);
106 
CheckModuleRestricted(const std::string & moduleName)107     inline bool CheckModuleRestricted(const std::string& moduleName)
108     {
109         const std::string whiteList[] = {
110             "worker",
111             "arkui.uicontext",
112             "arkui.node",
113             "arkui.modifier",
114             "measure",
115         };
116 
117         size_t listLen = sizeof(whiteList) / sizeof(whiteList[0]);
118         for (size_t i = 0; i < listLen; ++i) {
119             if (moduleName == whiteList[i]) {
120                 return true;
121             }
122         }
123 
124         return false;
125     }
126 
127 private:
128     NativeModuleManager();
129     virtual ~NativeModuleManager();
130 
131     bool GetNativeModulePath(const char* moduleName, const char* path, const char* relativePath,
132         bool isAppModule, char nativeModulePath[][NAPI_PATH_MAX], int32_t pathLength);
133     NativeModule* FindNativeModuleByDisk(const char* moduleName, const char* path, const char* relativePath,
134         bool internal, const bool isAppModule, std::string& errInfo, char nativeModulePath[][NAPI_PATH_MAX],
135         NativeModule* cacheNativeModule);
136     NativeModule* FindNativeModuleByCache(const char* moduleName,
137                                           char nativeModulePath[][NAPI_PATH_MAX],
138                                           NativeModule*& cacheNativeModule,
139                                           NativeModuleHeadTailStruct& cacheHeadTailStruct);
140     bool CheckModuleExist(const char* modulePath);
141     LIBHANDLE LoadModuleLibrary(std::string& moduleKey, const char* path, const char* pathKey,
142         const bool isAppModule, std::string& errInfo, uint32_t& errReason);
143     const uint8_t* GetFileBuffer(const std::string& filePath, const std::string& moduleKey, size_t &len);
144     bool UnloadModuleLibrary(LIBHANDLE handle);
145     bool CloseModuleLibrary(LIBHANDLE handle);
146     void CreateLdNamespace(const std::string moduleName, const char* lib_ld_path, const bool& isSystemApp);
147     bool IsExistedPath(const char* pathKey) const;
148     void EmplaceModuleLib(const std::string moduleKey, LIBHANDLE lib);
149     bool RemoveModuleLib(const std::string moduleKey);
150     void EmplaceModuleBuffer(const std::string moduleKey, const uint8_t* lib);
151     bool RemoveModuleBuffer(const std::string moduleKey);
152     const uint8_t* GetBufferHandle(const std::string& moduleKey) const;
153     void RegisterByBuffer(const std::string& moduleKey, const uint8_t* abcBuffer, size_t len);
154     bool CreateTailNativeModule();
155     bool CreateHeadNativeModule();
156     LIBHANDLE GetNativeModuleHandle(const std::string& moduleKey) const;
157     bool RemoveNativeModuleByCache(const std::string& moduleKey);
158     bool RemoveNativeModule(const std::string& moduleKey);
159     bool CheckNativeListChanged(const NativeModule* cacheHeadNativeModule, const NativeModule* cacheTailNativeModule);
160     void MoveApiAllowListCheckerPtr(
161         std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker, NativeModule* nativeModule);
162 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__) && !defined(IOS_PLATFORM) && \
163     !defined(LINUX_PLATFORM)
164     void CreateSharedLibsSonames();
165 
166     char* sharedLibsSonames_ = nullptr;
167     std::map<std::string, Dl_namespace> nsMap_;
168 #endif
169 
170     std::mutex nativeModuleListMutex_;
171     NativeModule* headNativeModule_ = nullptr;
172     NativeModule* tailNativeModule_ = nullptr;
173 
174     static NativeModuleManager *instance_;
175     pthread_mutex_t mutex_;
176     std::string prefix_;
177     bool isAppModule_ = false;
178     std::string loadingModuleName_;
179 
180     std::mutex nativeEngineListMutex_;
181     std::map<std::string, NativeEngine*> nativeEngineList_;
182 
183     mutable std::mutex moduleLibMutex_;
184     std::map<std::string, const LIBHANDLE> moduleLibMap_;
185 
186     mutable std::mutex moduleBufMutex_;
187     std::map<std::string, const uint8_t*> moduleBufMap_;
188 
189     mutable std::mutex appLibPathMapMutex_;
190     std::map<std::string, char*> appLibPathMap_;
191     std::string previewSearchPath_;
192     std::unique_ptr<ModuleLoadChecker> moduleLoadChecker_ = nullptr;
193 };
194 
195 #endif /* FOUNDATION_ACE_NAPI_MODULE_MANAGER_NATIVE_MODULE_MANAGER_H */
196