* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_NAPI_MODULE_MANAGER_NATIVE_MODULE_MANAGER_H
#define FOUNDATION_ACE_NAPI_MODULE_MANAGER_NATIVE_MODULE_MANAGER_H
#include <cstdint>
#include <map>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
#include <pthread.h>
#include "module_load_checker.h"
#include "utils/macros.h"
#include "interfaces/inner_api/napi/native_node_api.h"
#ifdef WINDOWS_PLATFORM
#include <winsock2.h>
#include <windows.h>
using LIBHANDLE = HMODULE;
#define LIBFREE FreeLibrary
#define LIBSYM GetProcAddress
#else
#include <dlfcn.h>
using LIBHANDLE = void*;
#define LIBFREE dlclose
#define LIBSYM dlsym
#endif
#define NAPI_PATH_MAX 4096
class NativeValue;
class NativeEngine;
typedef napi_value (*RegisterCallback)(napi_env, napi_value);
typedef void (*GetJSCodeCallback)(const char** buf, int* bufLen);
typedef void (*NapiOnLoadCallback)();
struct NativeModule {
const char* name = nullptr;
const char* moduleName = nullptr;
const char* fileName = nullptr;
const char* systemFilePath = nullptr;
RegisterCallback registerCallback = nullptr;
GetJSCodeCallback getABCCode = nullptr;
GetJSCodeCallback getJSCode = nullptr;
int32_t version = 0;
uint32_t flags = 0;
uint32_t refCount = 0;
NativeModule* next = nullptr;
const char* jsCode = nullptr;
const uint8_t* jsABCCode = nullptr;
int32_t jsCodeLen = 0;
bool moduleLoaded = false;
bool isAppModule = false;
std::unique_ptr<ApiAllowListChecker> apiAllowListChecker = nullptr;
};
struct NativeModuleHeadTailStruct {
NativeModule* headNativeModule = nullptr;
NativeModule* tailNativeModule = nullptr;
NativeModule* matchLoadingNativeModule = nullptr;
};
class NAPI_EXPORT NativeModuleManager {
public:
static NativeModuleManager* GetInstance();
static uint64_t Release();
void Register(NativeModule* nativeModule);
void InheritNamespaceEachOther(const std::string& src, const std::string& dst);
void SetAppLibPath(const std::string& moduleName, const std::vector<std::string>& appLibPath,
const bool& isSystemApp = false);
void UpdateNamespaceLibPath(const std::string& moduleName, const std::vector<std::string>& appLibPath);
bool GetLdNamespaceName(const std::string &moduleName, std::string &nsName);
NativeModule* LoadNativeModule(const char* moduleName, const char* path, bool isAppModule,
std::string& errInfo, bool internal = false, const char* relativePath = "",
std::string* loadErrInfo = nullptr);
void SetNativeEngine(std::string moduleName, NativeEngine* nativeEngine);
bool UnloadNativeModule(const std::string& moduleKey);
std::string GetModuleFileName(const char* moduleName, bool isAppModule);
* @brief Set the path for searching napi dynamic libraries, only for the previewer.
*
* @param previewSearchPath the path for searching napi dynamic libraries
*/
void SetPreviewSearchPath(const std::string& previewSearchPath);
* @brief Set the Module Load Checker delegate
*
* @param moduleCheckerDelegate The Module Load Checker delegate
*/
void SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate>& moduleCheckerDelegate);
* @brief Set the Ld permitted path for Namespace
*
* @param nsName The namespace
* @param ldPermittedPath The Ld permitted path
*/
void SetLdPermittedPathsForNamespace(const std::string& nsName, const std::string& ldPermittedPath);
inline bool CheckModuleRestricted(const std::string& moduleName)
{
const std::string whiteList[] = {
"worker",
"arkui.uicontext",
"arkui.node",
"arkui.modifier",
"measure",
};
size_t listLen = sizeof(whiteList) / sizeof(whiteList[0]);
for (size_t i = 0; i < listLen; ++i) {
if (moduleName == whiteList[i]) {
return true;
}
}
const std::string arkMatch = "arkui.components.ark";
if (moduleName.find(arkMatch) == 0) {
return true;
}
return false;
}
private:
NativeModuleManager();
virtual ~NativeModuleManager();
bool GetNativeModulePath(const char* moduleName, const char* path, const char* relativePath,
bool isAppModule, char nativeModulePath[][NAPI_PATH_MAX], int32_t pathLength);
NativeModule* FindNativeModuleByDisk(const char* moduleName, const char* path, const char* relativePath,
bool internal, const bool isAppModule, std::string& errInfo, std::string* loadErrInfo,
char nativeModulePath[][NAPI_PATH_MAX], NativeModule* cacheNativeModule);
NativeModule* FindNativeModuleByCache(const char* moduleName,
char nativeModulePath[][NAPI_PATH_MAX],
NativeModule*& cacheNativeModule,
NativeModuleHeadTailStruct& cacheHeadTailStruct,
bool checkLoadingNativeModule = false);
bool CheckModuleExist(const char* modulePath);
LIBHANDLE LoadModuleLibrary(std::string& moduleKey, const char* path, const char* pathKey,
const bool isAppModule, std::string& errInfo, uint32_t& errReason);
const uint8_t* GetFileBuffer(const std::string& filePath, const std::string& moduleKey, size_t &len);
bool UnloadModuleLibrary(LIBHANDLE handle);
bool CloseModuleLibrary(LIBHANDLE handle);
void CreateLdNamespace(const std::string moduleName, const char* lib_ld_path, const bool& isSystemApp);
bool IsExistedPath(const char* pathKey) const;
void EmplaceModuleLib(const std::string moduleKey, LIBHANDLE lib);
bool RemoveModuleLib(const std::string moduleKey);
void EmplaceModuleBuffer(const std::string moduleKey, const uint8_t* lib);
bool RemoveModuleBuffer(const std::string moduleKey);
const uint8_t* GetBufferHandle(const std::string& moduleKey) const;
void RegisterByBuffer(const std::string& moduleKey, const uint8_t* abcBuffer, size_t len);
bool CreateTailNativeModule();
bool CreateHeadNativeModule();
LIBHANDLE GetNativeModuleHandle(const std::string& moduleKey) const;
bool RemoveNativeModuleByCache(const std::string& moduleKey);
bool RemoveNativeModule(const std::string& moduleKey);
bool CheckNativeListChanged(const NativeModule* cacheHeadNativeModule, const NativeModule* cacheTailNativeModule,
const NativeModule* matchLoadingNativeModule);
void MoveApiAllowListCheckerPtr(
std::unique_ptr<ApiAllowListChecker>& apiAllowListChecker, NativeModule* nativeModule);
void Napi_onLoadCallback(LIBHANDLE lib, const char* moduleName);
void SetLoadingNativeModuleKey(const char *moduleName);
std::string GetLoadingNativeModuleKey();
#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(__BIONIC__) && !defined(IOS_PLATFORM) && \
!defined(LINUX_PLATFORM)
void CreateSharedLibsSonames();
bool LoadGreylistConfig(std::vector<std::string>& greylistLibs);
char* sharedLibsSonames_ = nullptr;
std::map<std::string, Dl_namespace> nsMap_;
#endif
std::mutex nativeModuleListMutex_;
NativeModule* headNativeModule_ = nullptr;
NativeModule* tailNativeModule_ = nullptr;
std::string loadingModuleKey_;
static NativeModuleManager *instance_;
pthread_mutex_t mutex_;
std::string prefix_;
bool isAppModule_ = false;
std::string loadingModuleName_;
std::mutex nativeEngineListMutex_;
std::map<std::string, NativeEngine*> nativeEngineList_;
mutable std::mutex moduleLibMutex_;
std::map<std::string, const LIBHANDLE> moduleLibMap_;
mutable std::mutex moduleBufMutex_;
std::map<std::string, const uint8_t*> moduleBufMap_;
mutable std::mutex appLibPathMapMutex_;
std::map<std::string, char*> appLibPathMap_;
std::string previewSearchPath_;
std::unique_ptr<ModuleLoadChecker> moduleLoadChecker_ = nullptr;
};
#endif