Merge pull request !15418 from zhangzezhong/0702_preload
This commit is contained in:
openharmony_ci
2025-07-07 07:39:41 +00:00
committed by Gitee
13 changed files with 173 additions and 64 deletions
@@ -54,6 +54,7 @@ ohos_shared_library("ets_environment") {
"json:nlohmann_json_static",
"napi:ace_napi",
"runtime_core:ani",
"runtime_core:libarkruntime",
]
if (ability_runtime_graphics) {
@@ -24,6 +24,13 @@
#include <thread>
#include <vector>
#include "ets_ani_expo.h"
#ifdef LIKELY
#undef LIKELY
#endif
#ifdef UNLIKELY
#undef UNLIKELY
#endif
#include "dynamic_loader.h"
#include "elf_factory.h"
#include "event_handler.h"
@@ -203,7 +210,7 @@ void ETSEnvironment::InitETSSysNS(const std::string &path)
dlns_inherit(&ns, &ndk, "allow_all_shared_libs");
}
bool ETSEnvironment::Initialize(void *napiEnv, const std::string &aotPath)
bool ETSEnvironment::Initialize()
{
TAG_LOGD(AAFwkTag::ETSRUNTIME, "Initialize called");
if (!LoadRuntimeApis()) {
@@ -217,13 +224,6 @@ bool ETSEnvironment::Initialize(void *napiEnv, const std::string &aotPath)
}
std::vector<ani_option> options;
std::string aotPathString = "";
if (!aotPath.empty()) {
aotPathString = "--ext:--aot-file=" + aotPath;
options.push_back(ani_option { aotPathString.data(), nullptr });
options.push_back(ani_option { "--ext:--enable-an", nullptr });
TAG_LOGD(AAFwkTag::ETSRUNTIME, "aotPathString: %{public}s", aotPathString.c_str());
}
// Create boot-panda-files options
std::string bootString = "--ext:--boot-panda-files=" + bootfiles;
options.push_back(ani_option { bootString.data(), nullptr });
@@ -232,7 +232,6 @@ bool ETSEnvironment::Initialize(void *napiEnv, const std::string &aotPath)
options.push_back(ani_option { "--ext:--log-level=info", nullptr });
options.push_back(ani_option { "--ext:--verification-enabled=true", nullptr });
options.push_back(ani_option { "--ext:--verification-mode=on-the-fly", nullptr });
options.push_back(ani_option { "--ext:interop", napiEnv });
ani_options optionsPtr = { options.size(), options.data() };
ani_status status = ANI_ERROR;
if ((status = lazyApis_.ANI_CreateVM(&optionsPtr, ANI_VERSION_1, &vmEntry_.aniVm_)) != ANI_OK) {
@@ -479,6 +478,36 @@ bool ETSEnvironment::LoadModule(const std::string &modulePath, const std::string
return true;
}
void ETSEnvironment::FinishPreload() {
ani_env *env = GetAniEnv();
if (env == nullptr) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "Failed: ANI env nullptr");
return;
}
ark::ets::ETSAni::Prefork(env);
}
void ETSEnvironment::PostFork(void *napiEnv, const std::string &aotPath)
{
std::vector<ani_option> options;
std::string aotPathString = "";
if (!aotPath.empty()) {
aotPathString = "--ext:--aot-file=" + aotPath;
options.push_back(ani_option { aotPathString.data(), nullptr });
options.push_back(ani_option { "--ext:--enable-an", nullptr });
TAG_LOGD(AAFwkTag::ETSRUNTIME, "aotPathString: %{public}s", aotPathString.c_str());
}
options.push_back(ani_option { "--ext:interop", napiEnv });
ani_env *env = GetAniEnv();
if (env == nullptr) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "Failed: ANI env nullptr");
return;
}
ark::ets::ETSAni::Postfork(env, options);
}
ETSEnvFuncs *ETSEnvironment::RegisterFuncs()
{
static ETSEnvFuncs funcs {
@@ -488,8 +517,8 @@ ETSEnvFuncs *ETSEnvironment::RegisterFuncs()
.InitETSSysNS = [](const std::string &path) {
ETSEnvironment::InitETSSysNS(path);
},
.Initialize = [](void *napiEnv, const std::string &aotPath) {
return ETSEnvironment::GetInstance()->Initialize(napiEnv, aotPath);
.Initialize = []() {
return ETSEnvironment::GetInstance()->Initialize();
},
.RegisterUncaughtExceptionHandler = [](const ETSUncaughtExceptionInfo &exceptionInfo) {
ETSEnvironment::GetInstance()->RegisterUncaughtExceptionHandler(exceptionInfo);
@@ -503,6 +532,12 @@ ETSEnvFuncs *ETSEnvironment::RegisterFuncs()
.LoadModule = [](const std::string &modulePath, const std::string &srcEntrance, void *&cls,
void *&obj, void *&ref) {
return ETSEnvironment::GetInstance()->LoadModule(modulePath, srcEntrance, cls, obj, ref);
},
.FinishPreload = []() {
ETSEnvironment::GetInstance()->FinishPreload();
},
.PostFork = [](void *napiEnv, const std::string &aotPath) {
ETSEnvironment::GetInstance()->PostFork(napiEnv, aotPath);
}
};
return &funcs;
@@ -50,13 +50,15 @@ public:
static void InitETSSysNS(const std::string &path);
static ETSEnvFuncs *RegisterFuncs();
bool Initialize(void *napiEnv, const std::string &aotPath);
bool Initialize();
void RegisterUncaughtExceptionHandler(const ETSUncaughtExceptionInfo &handle);
ani_env *GetAniEnv();
bool HandleUncaughtError();
bool PreloadModule(const std::string &modulePath);
bool LoadModule(const std::string &modulePath, const std::string &srcEntrance, void *&cls,
void *&obj, void *&ref);
void FinishPreload();
void PostFork(void *napiEnv, const std::string &aotPath);
struct VMEntry {
ani_vm *aniVm_;
@@ -26,7 +26,7 @@ struct ETSEnvFuncs {
void (*InitETSSDKNS)(const std::string &path) = nullptr;
void (*InitETSSysNS)(const std::string &path) = nullptr;
bool (*Initialize)(void *napiEnv, const std::string &aotPath) = nullptr;
bool (*Initialize)() = nullptr;
void (*RegisterUncaughtExceptionHandler)(
const OHOS::EtsEnv::ETSUncaughtExceptionInfo &uncaughtExceptionInfo) = nullptr;
ani_env *(*GetAniEnv)() = nullptr;
@@ -34,6 +34,8 @@ struct ETSEnvFuncs {
bool (*PreloadModule)(const std::string &modulePath) = nullptr;
bool (*LoadModule)(const std::string &modulePath, const std::string &srcEntrance, void *&cls,
void *&obj, void *&ref) = nullptr;
void (*FinishPreload)() = nullptr;
void (*PostFork)(void *napiEnv, const std::string &aotPath) = nullptr;
};
}
#endif // OHOS_ABILITY_RUNTIME_ETS_INTERFACE_H
@@ -251,9 +251,7 @@ HWTEST_F(EtsEnvironmentTest, Initialize_0100, TestSize.Level0)
{
auto etsEnv = std::make_shared<ETSEnvironment>();
ASSERT_NE(etsEnv, nullptr);
void *napiEnv = reinterpret_cast<void *>(0x1);
std::string aotStr = "";
bool result = etsEnv->Initialize(napiEnv, aotStr);
bool result = etsEnv->Initialize();
EXPECT_FALSE(result);
}
+100 -38
View File
@@ -200,30 +200,10 @@ bool RegisterETSEnvFuncs()
}
} // namespace
std::unique_ptr<ETSRuntime> ETSRuntime::Create(const Options &options, std::unique_ptr<JsRuntime> &jsRuntime)
std::unique_ptr<ETSRuntime> ETSRuntime::PreFork(const Options &options, std::unique_ptr<JsRuntime> &jsRuntime)
{
TAG_LOGD(AAFwkTag::ETSRUNTIME, "Create called");
if (jsRuntime == nullptr) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "null jsRuntime");
return std::unique_ptr<ETSRuntime>();
}
std::unique_ptr<ETSRuntime> instance;
if (!options.preload) {
auto preloadedInstance = Runtime::GetPreloaded();
#ifdef SUPPORT_SCREEN
// reload ace if compatible mode changes
if (Ace::AceForwardCompatibility::PipelineChanged() && preloadedInstance) {
preloadedInstance.reset();
}
#endif
if (preloadedInstance && preloadedInstance->GetLanguage() == Runtime::Language::ETS) {
instance.reset(static_cast<ETSRuntime *>(preloadedInstance.release()));
} else {
instance = std::make_unique<ETSRuntime>();
}
} else {
instance = std::make_unique<ETSRuntime>();
}
TAG_LOGD(AAFwkTag::ETSRUNTIME, "PreFork begin");
std::unique_ptr<ETSRuntime> instance = std::make_unique<ETSRuntime>();
if (!instance->Initialize(options, jsRuntime)) {
return std::unique_ptr<ETSRuntime>();
@@ -232,6 +212,71 @@ std::unique_ptr<ETSRuntime> ETSRuntime::Create(const Options &options, std::uniq
return instance;
}
void ETSRuntime::PostFork(const Options &options, std::unique_ptr<JsRuntime> &jsRuntime)
{
TAG_LOGD(AAFwkTag::ETSRUNTIME, "PostFork begin");
codePath_ = options.codePath;
if (g_etsEnvFuncs == nullptr ||
g_etsEnvFuncs->PostFork == nullptr) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "null g_etsEnvFuncs or PostFork");
return;
}
if (jsRuntime != nullptr) {
jsRuntime_ = std::move(jsRuntime);
}
if (jsRuntime_ != nullptr) {
auto vm = static_cast<JsRuntime *>(jsRuntime_.get())->GetEcmaVm();
panda::JSNApi::SetHostResolveBufferTrackerForHybridApp(
vm, HybridJsModuleReader(options.bundleName, options.hapPath, options.isUnique));
}
std::string aotFilePath = "";
if (!options.arkNativeFilePath.empty()) {
aotFilePath = SANDBOX_ARK_CACHE_PATH + options.arkNativeFilePath + options.moduleName + ".an";
}
napi_env napiEnv = static_cast<AbilityRuntime::JsRuntime *>(jsRuntime_.get())->GetNapiEnv();
g_etsEnvFuncs->PostFork(reinterpret_cast<void *>(napiEnv), aotFilePath);
}
std::unique_ptr<ETSRuntime> ETSRuntime::Create(const Options &options, std::unique_ptr<JsRuntime> &jsRuntime)
{
TAG_LOGD(AAFwkTag::ETSRUNTIME, "Create called");
if (!RegisterETSEnvFuncs()) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "RegisterETSEnvFuncs failed");
return std::unique_ptr<ETSRuntime>();
}
if (g_etsEnvFuncs == nullptr) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "null g_etsEnvFuncs");
return std::unique_ptr<ETSRuntime>();
}
if (jsRuntime == nullptr) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "null jsRuntime");
return std::unique_ptr<ETSRuntime>();
}
std::unique_ptr<ETSRuntime> instance;
auto preloadedInstance = Runtime::GetPreloaded(Language::ETS);
#ifdef SUPPORT_SCREEN
// reload ace if compatible mode changes
if (Ace::AceForwardCompatibility::PipelineChanged() && preloadedInstance) {
preloadedInstance.reset();
}
#endif
if (preloadedInstance && preloadedInstance->GetLanguage() == Runtime::Language::ETS) {
instance.reset(static_cast<ETSRuntime *>(preloadedInstance.release()));
} else {
instance = PreFork(options, jsRuntime);
}
if (instance != nullptr && !options.preload) {
instance->PostFork(options, jsRuntime);
}
return instance;
}
void ETSRuntime::SetAppLibPath(const AppLibPathMap &appLibPaths)
{
TAG_LOGD(AAFwkTag::ETSRUNTIME, "SetAppLibPath called");
@@ -266,23 +311,33 @@ bool ETSRuntime::Initialize(const Options &options, std::unique_ptr<JsRuntime> &
return false;
}
jsRuntime_ = std::move(jsRuntime);
if (!CreateEtsEnv(options, jsRuntime_.get())) {
if (jsRuntime != nullptr) {
jsRuntime_ = std::move(jsRuntime);
}
if (!CreateEtsEnv(options)) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "CreateEtsEnv failed");
return false;
}
if (jsRuntime_ != nullptr) {
auto vm = static_cast<JsRuntime *>(jsRuntime_.get())->GetEcmaVm();
panda::JSNApi::SetHostResolveBufferTrackerForHybridApp(
vm, HybridJsModuleReader(options.bundleName, options.hapPath, options.isUnique));
}
apiTargetVersion_ = options.apiTargetVersion;
TAG_LOGD(AAFwkTag::ETSRUNTIME, "Initialize: %{public}d", apiTargetVersion_);
return true;
}
void ETSRuntime::FinishPreload()
{
if (jsRuntime_ != nullptr) {
jsRuntime_->FinishPreload();
}
if (g_etsEnvFuncs == nullptr ||
g_etsEnvFuncs->FinishPreload == nullptr) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "null g_etsEnvFuncs or FinishPreload");
return;
}
g_etsEnvFuncs->FinishPreload();
}
void ETSRuntime::RegisterUncaughtExceptionHandler(const EtsEnv::ETSUncaughtExceptionInfo &uncaughtExceptionInfo)
{
if (g_etsEnvFuncs == nullptr ||
@@ -304,7 +359,7 @@ void ETSRuntime::Deinitialize()
TAG_LOGD(AAFwkTag::ETSRUNTIME, "Deinitialize called");
}
bool ETSRuntime::CreateEtsEnv(const Options &options, Runtime *jsRuntime)
bool ETSRuntime::CreateEtsEnv(const Options &options)
{
TAG_LOGD(AAFwkTag::ETSRUNTIME, "CreateEtsEnv called");
if (g_etsEnvFuncs == nullptr ||
@@ -313,12 +368,7 @@ bool ETSRuntime::CreateEtsEnv(const Options &options, Runtime *jsRuntime)
return false;
}
std::string aotFilePath = "";
if (!options.arkNativeFilePath.empty()) {
aotFilePath = SANDBOX_ARK_CACHE_PATH + options.arkNativeFilePath + options.moduleName + ".an";
}
napi_env napiEnv = static_cast<AbilityRuntime::JsRuntime *>(jsRuntime)->GetNapiEnv();
if (!g_etsEnvFuncs->Initialize(reinterpret_cast<void *>(napiEnv), aotFilePath)) {
if (!g_etsEnvFuncs->Initialize()) {
TAG_LOGE(AAFwkTag::ETSRUNTIME, "Initialize failed");
return false;
}
@@ -425,5 +475,17 @@ const std::unique_ptr<AbilityRuntime::Runtime> &ETSRuntime::GetJsRuntime() const
{
return jsRuntime_;
}
std::unique_ptr<AbilityRuntime::Runtime> ETSRuntime::MoveJsRuntime()
{
return std::move(jsRuntime_);
}
void ETSRuntime::PreloadSystemModule(const std::string &moduleName)
{
if (jsRuntime_ != nullptr) {
jsRuntime_->PreloadSystemModule(moduleName);
}
}
} // namespace AbilityRuntime
} // namespace OHOS
+1 -1
View File
@@ -138,7 +138,7 @@ std::unique_ptr<JsRuntime> JsRuntime::Create(const Options& options)
std::unique_ptr<JsRuntime> instance;
JsRuntimeLite::InitJsRuntimeLite(options);
if (!options.preload && options.isStageModel) {
auto preloadedInstance = Runtime::GetPreloaded();
auto preloadedInstance = Runtime::GetPreloaded(Language::JS);
#ifdef SUPPORT_SCREEN
// reload ace if compatible mode changes
if (Ace::AceForwardCompatibility::PipelineChanged() && preloadedInstance) {
+7 -2
View File
@@ -50,7 +50,7 @@ std::unique_ptr<Runtime> Runtime::Create(Runtime::Options &options)
}
}
void Runtime::SavePreloaded(std::unique_ptr<Runtime>&& instance)
void Runtime::SavePreloaded(std::unique_ptr<Runtime> &&instance)
{
if (instance) {
instance->FinishPreload();
@@ -58,8 +58,13 @@ void Runtime::SavePreloaded(std::unique_ptr<Runtime>&& instance)
g_preloadedInstance = std::move(instance);
}
std::unique_ptr<Runtime> Runtime::GetPreloaded()
std::unique_ptr<Runtime> Runtime::GetPreloaded(Language key)
{
if (g_preloadedInstance &&
g_preloadedInstance->GetLanguage() == Language::ETS &&
key == Language::JS) {
return static_cast<ETSRuntime *>(g_preloadedInstance.get())->MoveJsRuntime();
}
return std::move(g_preloadedInstance);
}
} // namespace AbilityRuntime
@@ -58,14 +58,14 @@ public:
void NotifyApplicationState(bool isBackground) override {}
bool SuspendVM(uint32_t tid) override { return false; }
void ResumeVM(uint32_t tid) override {}
void PreloadSystemModule(const std::string &moduleName) override {}
void PreloadSystemModule(const std::string &moduleName) override;
void PreloadMainAbility(const std::string &moduleName, const std::string &srcPath, const std::string &hapPath,
bool isEsMode, const std::string &srcEntrance) override {}
void PreloadModule(const std::string &moduleName, const std::string &srcPath, const std::string &hapPath,
bool isEsMode, bool useCommonTrunk) override {}
void PreloadModule(
const std::string &moduleName, const std::string &hapPath, bool isEsMode, bool useCommonTrunk) override;
void FinishPreload() override {}
void FinishPreload() override;
bool LoadRepairPatch(const std::string &patchFile, const std::string &baseFile) override { return false; }
bool NotifyHotReloadPage() override { return false; }
bool UnLoadRepairPatch(const std::string &patchFile) override { return false; }
@@ -87,13 +87,16 @@ public:
bool useCommonChunk, const std::string &srcEntrance);
bool HandleUncaughtError();
const std::unique_ptr<AbilityRuntime::Runtime> &GetJsRuntime() const;
std::unique_ptr<AbilityRuntime::Runtime> MoveJsRuntime();
static std::unique_ptr<ETSRuntime> PreFork(const Options &options, std::unique_ptr<JsRuntime> &jsRuntime);
private:
bool Initialize(const Options &options, std::unique_ptr<JsRuntime> &jsRuntime);
void Deinitialize();
bool CreateEtsEnv(const Options &options, Runtime *jsRuntime);
bool CreateEtsEnv(const Options &options);
std::unique_ptr<AppExecFwk::ETSNativeReference> LoadEtsModule(const std::string &moduleName,
const std::string &fileName, const std::string &hapPath, const std::string &srcEntrance);
void PostFork(const Options &options, std::unique_ptr<JsRuntime> &jsRuntime);
int32_t apiTargetVersion_ = 0;
std::string codePath_;
std::string moduleName_;
@@ -91,8 +91,8 @@ public:
};
static std::unique_ptr<Runtime> Create(Options &options);
static void SavePreloaded(std::unique_ptr<Runtime>&& instance);
static std::unique_ptr<Runtime> GetPreloaded();
static void SavePreloaded(std::unique_ptr<Runtime> &&instance);
static std::unique_ptr<Runtime> GetPreloaded(Language key);
Runtime() = default;
virtual ~Runtime() = default;
@@ -108,7 +108,7 @@ HWTEST_F(RuntimeTest, GetPreloaded_0100, TestSize.Level2)
std::unique_ptr<Runtime> runtime = std::make_unique<MockRuntime>();
auto instance = std::make_unique<MockRuntime>();
runtime->SavePreloaded(std::move(instance));
EXPECT_TRUE(runtime->GetPreloaded() != nullptr);
EXPECT_TRUE(runtime->GetPreloaded(Runtime::Language::JS) != nullptr);
GTEST_LOG_(INFO) << "RuntimeTest GetPreloaded_0100 end";
}
+1
View File
@@ -300,6 +300,7 @@ ohos_unittest("ets_runtime_test") {
"json:nlohmann_json_static",
"napi:ace_napi",
"runtime_core:ani",
"runtime_core:libarkruntime",
]
if (ability_runtime_graphics) {
@@ -420,7 +420,7 @@ HWTEST_F(JsRuntimeTest, RuntimeSavePreloadedTest_0100, TestSize.Level1)
TAG_LOGI(AAFwkTag::TEST, "SavePreloaded start");
Runtime::SavePreloaded(nullptr);
auto result = Runtime::GetPreloaded();
auto result = Runtime::GetPreloaded(Runtime::Language::JS);
EXPECT_EQ(result, nullptr);
std::this_thread::sleep_for(std::chrono::milliseconds(200));