* Copyright (c) 2025-2026 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.
*/
#include "core/common/dynamic_module_helper.h"
#include <memory>
#include "compatible/components/component_loader.h"
#include "interfaces/inner_api/ace/utils.h"
#include "base/utils/utils.h"
#include "core/common/dynamic_module.h"
#include "base/log/log.h"
namespace OHOS::Ace {
namespace {
#ifdef WINDOWS_PLATFORM
#ifdef UNICODE
const std::wstring COMPATIABLE_LIB = L"libace_compatible_components.dll";
const std::wstring DYNAMIC_MODULE_LIB_PREFIX = L"libarkui_";
const std::wstring DYNAMIC_MODULE_LIB_POSTFIX = L".dll";
#else
const std::string COMPATIABLE_LIB = "libace_compatible_components.dll";
const std::string DYNAMIC_MODULE_LIB_PREFIX = "libarkui_";
const std::string DYNAMIC_MODULE_LIB_POSTFIX = ".dll";
#endif
#elif MAC_PLATFORM
const std::string COMPATIABLE_LIB = "libace_compatible_components.dylib";
const std::string DYNAMIC_MODULE_LIB_PREFIX = "libarkui_";
const std::string DYNAMIC_MODULE_LIB_POSTFIX = ".dylib";
#else
const std::string COMPATIABLE_LIB = "libace_compatible_components.z.so";
const std::string DYNAMIC_MODULE_LIB_PREFIX = "libarkui_";
const std::string DYNAMIC_MODULE_LIB_POSTFIX = ".z.so";
#endif
}
DynamicModuleHelper& DynamicModuleHelper::GetInstance()
{
static DynamicModuleHelper instance;
return instance;
}
std::unique_ptr<ComponentLoader> DynamicModuleHelper::GetLoaderByName(const char* name)
{
if (compatibleLoaderFunc_) {
return std::unique_ptr<ComponentLoader>(compatibleLoaderFunc_(name));
}
LIBHANDLE handle = LOADLIB(COMPATIABLE_LIB.c_str());
#if defined(WINDOWS_PLATFORM) && defined(UNICODE)
LOGI("Load compatible lib %{public}ls", COMPATIABLE_LIB.c_str());
#else
LOGI("Load compatible lib %{public}s", COMPATIABLE_LIB.c_str());
#endif
auto* createSym = reinterpret_cast<ComponentLoaderFunc>(LOADSYM(handle, COMPATIABLE_COMPONENT_LOADER));
CHECK_NULL_RETURN(createSym, nullptr);
compatibleLoaderFunc_ = createSym;
return std::unique_ptr<ComponentLoader>(compatibleLoaderFunc_(name));
}
DynamicModule* DynamicModuleHelper::GetDynamicModule(const std::string& name)
{
{
std::lock_guard<std::mutex> lock(moduleMapMutex_);
auto iter = moduleMap_.find(name);
if (iter != moduleMap_.end()) {
return iter->second.get();
}
}
static const std::unordered_map<std::string, std::string> soMap = {
{"DynamicLayout", "dynamiclayout"},
{ "ContainerReader", "containerreader" },
{"Counter", "counter"},
{ "DataPanel", "datapanel" },
{"Checkbox", "checkbox"},
{"CheckboxGroup", "checkbox"},
{"Gauge", "gauge"},
{"Sidebar", "sidebar"},
{"QRCode", "qrcode"},
{"PatternLock", "patternlock"},
{"TextClock", "textclock"},
{"Rating", "rating"},
{ "FlowItem", "waterflow" },
{ "WaterFlow", "waterflow" },
{ "LazyVWaterFlowLayout", "lazywaterflowlayout" },
{ "ColumnSplit", "linearsplit" },
{ "RowSplit", "linearsplit" },
{"Marquee", "marquee"},
{ "Progress", "progress" },
{ "TextTimer", "texttimer" },
{ "Stepper", "stepper" },
{ "StepperItem", "stepper" },
{"Radio", "radio"},
{ "Slider", "slider" },
{ "FolderStack", "folderstack" },
{ "Search", "search" },
{ "TimePicker", "timepicker" },
{ "ImageSpan", "span" },
{ "SymbolSpan", "span" },
{ "TimePickerDialog", "timepicker" },
{"CalendarPicker", "calendarpicker"},
{"CalendarPickerDialog", "calendarpicker"},
{"Indexer", "indexer"},
{ "Badge", "badge" },
{ "Hyperlink", "hyperlink" },
{"SymbolGlyph", "symbol"},
{"Richeditor", "richeditor"},
{ "LoadingProgress", "loadingprogress" },
{ "Menu", "menu" },
{ "MenuItem", "menu" },
{ "MenuItemGroup", "menu" },
{ "LazyColumnLayout", "lazycolumnlayout" },
{ "Toggle", "toggle" },
{ "ImageAnimator", "imageanimator" },
{ "DatePicker", "datepicker" },
{ "DatePickerDialog", "datepicker" },
{ "LazyVGridLayout", "lazygridlayout" },
{ "Refresh", "refresh" },
{ "TextPicker", "textpicker" },
{ "TextPickerDialog", "textpicker" },
};
auto it = soMap.find(name);
if (it == soMap.end()) {
LOGI("No shared library mapping found for nativeModule: %{public}s", name.c_str());
return nullptr;
}
#ifdef WINDOWS_PLATFORM
std::wstring nameW = std::wstring(it->second.begin(), it->second.end());
auto libName = DYNAMIC_MODULE_LIB_PREFIX + nameW + DYNAMIC_MODULE_LIB_POSTFIX;
#else
auto libName = DYNAMIC_MODULE_LIB_PREFIX + it->second + DYNAMIC_MODULE_LIB_POSTFIX;
#endif
LIBHANDLE handle = LOADLIB(libName.c_str());
CHECK_NULL_RETURN(handle, nullptr);
auto* createSym =
reinterpret_cast<DynamicModuleCreateFunc>(LOADSYM(handle, (DYNAMIC_MODULE_CREATE + name).c_str()));
CHECK_NULL_RETURN(createSym, nullptr);
DynamicModule* module = createSym();
CHECK_NULL_RETURN(module, nullptr);
LOGI("First load %{public}s nativeModule finish", name.c_str());
{
std::lock_guard<std::mutex> lock(moduleMapMutex_);
auto iter = moduleMap_.find(name);
if (iter != moduleMap_.end()) {
delete module;
return iter->second.get();
}
moduleMap_.emplace(name, std::unique_ptr<DynamicModule>(module));
return module;
}
}
bool DynamicModuleHelper::IsDynamicModuleLoaded(const std::string& name)
{
std::lock_guard<std::mutex> lock(moduleMapMutex_);
auto iter = moduleMap_.find(name);
if (iter != moduleMap_.end()) {
return true;
}
return false;
}
#ifdef ENABLE_PRELOAD_DYNAMIC_MODULE
void DynamicModuleHelper::TriggerPageFaultForPreLoad() {}
#endif
}