From 0f85e1d6a9fe02d2aa75cfaff389b8a1f1ca1056 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Sat, 7 Jun 2025 10:21:09 +0800 Subject: [PATCH] add ets runtime & mainthread Signed-off-by: zhangzezhong --- bundle.json | 10 + ets_environment/ets_environment.gni | 14 + .../frameworks/ets_environment/BUILD.gn | 63 +++ .../ets_environment/src/dynamic_loader.cpp | 193 +++++++ .../ets_environment/src/ets_environment.cpp | 356 +++++++++++++ .../interfaces/inner_api/dynamic_loader.h | 31 ++ .../interfaces/inner_api/ets_environment.h | 72 +++ .../inner_api/ets_exception_callback.h | 34 ++ frameworks/cj/ffi/BUILD.gn | 1 + frameworks/native/ability/native/BUILD.gn | 1 + .../native/ability/native/ability_loader.cpp | 10 +- .../native/extension_ability_thread.cpp | 8 +- .../ability/native/ui_ability_thread.cpp | 6 +- frameworks/native/appkit/BUILD.gn | 4 + .../ability_delegator_registry.cpp | 27 +- .../appkit/app/application_data_manager.cpp | 19 + .../native/appkit/app/dump_runtime_helper.cpp | 6 +- frameworks/native/appkit/app/main_thread.cpp | 323 +++++++++--- .../native/appkit/app/ohos_application.cpp | 144 +++++- frameworks/native/runtime/cj_runtime.cpp | 20 +- frameworks/native/runtime/ets_runtime.cpp | 481 ++++++++++++++++++ frameworks/native/runtime/js_runtime.cpp | 6 + frameworks/native/runtime/runtime.cpp | 40 +- .../ability_simulator/src/js_runtime.cpp | 4 + interfaces/inner_api/runtime/BUILD.gn | 5 + .../inner_api/runtime/include/cj_runtime.h | 5 +- .../inner_api/runtime/include/ets_runtime.h | 106 ++++ .../inner_api/runtime/include/js_runtime.h | 3 + .../inner_api/runtime/include/runtime.h | 17 +- .../native/ability/native/ability_loader.h | 9 +- .../ability_delegator_registry.h | 9 +- .../appkit/app/application_data_manager.h | 2 + .../kits/native/appkit/app/main_thread.h | 10 +- .../kits/native/appkit/app/ohos_application.h | 21 +- services/common/include/hilog_tag_wrapper.h | 5 +- .../ability_delegator/BUILD.gn | 1 + .../ability_delegator_registry_test.cpp | 3 +- 37 files changed, 1918 insertions(+), 151 deletions(-) create mode 100644 ets_environment/ets_environment.gni create mode 100644 ets_environment/frameworks/ets_environment/BUILD.gn create mode 100644 ets_environment/frameworks/ets_environment/src/dynamic_loader.cpp create mode 100644 ets_environment/frameworks/ets_environment/src/ets_environment.cpp create mode 100644 ets_environment/interfaces/inner_api/dynamic_loader.h create mode 100644 ets_environment/interfaces/inner_api/ets_environment.h create mode 100644 ets_environment/interfaces/inner_api/ets_exception_callback.h create mode 100644 frameworks/native/runtime/ets_runtime.cpp create mode 100644 interfaces/inner_api/runtime/include/ets_runtime.h diff --git a/bundle.json b/bundle.json index 18fd2773ad7..1159ee0c9be 100644 --- a/bundle.json +++ b/bundle.json @@ -133,6 +133,7 @@ "//foundation/ability/ability_runtime/frameworks/js/napi:napi_packages", "//foundation/ability/ability_runtime/cj_environment/frameworks/cj_environment:cj_environment", "//foundation/ability/ability_runtime/js_environment/frameworks/js_environment:js_environment", + "//foundation/ability/ability_runtime/ets_environment/frameworks/ets_environment:ets_environment", "//foundation/ability/ability_runtime/services/abilitymgr/etc:appfwk_etc", "//foundation/ability/ability_runtime/services/dialog_ui/ams_system_dialog:dialog_hap", "//foundation/ability/ability_runtime/service_router_framework:srms_target", @@ -258,6 +259,15 @@ }, "name": "//foundation/ability/ability_runtime/js_environment/frameworks/js_environment:js_environment" }, + { + "header": { + "header_base": "//foundation/ability/ability_runtime/ets_environment/interfaces/inner_api", + "header_files": [ + "ets_environment.h" + ] + }, + "name": "//foundation/ability/ability_runtime/ets_environment/frameworks/ets_environment:ets_environment" + }, { "header": { "header_base": "//foundation/ability/ability_runtime/cj_environment/interfaces/inner_api", diff --git a/ets_environment/ets_environment.gni b/ets_environment/ets_environment.gni new file mode 100644 index 00000000000..b044edbd9d0 --- /dev/null +++ b/ets_environment/ets_environment.gni @@ -0,0 +1,14 @@ +# Copyright (c) 2025 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. + +base_path = "//foundation/ability/ability_runtime/ets_environment" diff --git a/ets_environment/frameworks/ets_environment/BUILD.gn b/ets_environment/frameworks/ets_environment/BUILD.gn new file mode 100644 index 00000000000..02b22d383fb --- /dev/null +++ b/ets_environment/frameworks/ets_environment/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2025 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. + +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") +import("../../ets_environment.gni") + +config("public_ets_environment_config") { + include_dirs = [ + "include", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", + "${ability_runtime_services_path}/common/include", + "${ability_runtime_path}/interfaces/inner_api", + ] +} + +ohos_shared_library("ets_environment") { + branch_protector_ret = "pac_ret" + + public_configs = [ ":public_ets_environment_config" ] + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + sources = [ + "src/dynamic_loader.cpp", + "src/ets_environment.cpp", + ] + + defines = [] + + external_deps = [ + "c_utils:utils", + "eventhandler:libeventhandler", + "faultloggerd:libunwinder", + "hilog:libhilog", + "json:nlohmann_json_static", + "napi:ace_napi", + "runtime_core:ani", + ] + + if (ability_runtime_graphics) { + defines = [ "SUPPORT_GRAPHICS" ] + external_deps += [ "ace_engine:ace_uicontent" ] + } + + subsystem_name = "ability" + innerapi_tags = [ "platformsdk_indirect" ] + part_name = "ability_runtime" +} diff --git a/ets_environment/frameworks/ets_environment/src/dynamic_loader.cpp b/ets_environment/frameworks/ets_environment/src/dynamic_loader.cpp new file mode 100644 index 00000000000..d3285eb3ca1 --- /dev/null +++ b/ets_environment/frameworks/ets_environment/src/dynamic_loader.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2025 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 "dynamic_loader.h" + +#include +#include +#include +#include +#include +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace EtsEnv { +namespace { +constexpr int32_t ERROR_BUF_SIZE = 255; +static char g_dlError[ERROR_BUF_SIZE]; +static std::unordered_set g_hasInited; +static std::string g_sharedLibsSonames = ""; +constexpr int32_t OUT_OF_MEMORY = 12; +constexpr int32_t FILE_EXISTS = 17; +constexpr int32_t INVALID_ARGUMENT = 22; + +static void ReadDlError() +{ + char* errMsg = dlerror(); + if (!errMsg) { + return; + } + auto ends = sprintf_s(g_dlError, sizeof(g_dlError), "%s", errMsg); + if (ends >= ERROR_BUF_SIZE) { + g_dlError[ERROR_BUF_SIZE - 1] = '\0'; + } else { + g_dlError[ends] = '\0'; + } +} + +static void InitSharedLibsSonames() +{ + if (!g_sharedLibsSonames.empty()) { + return; + } + g_sharedLibsSonames = + // bionic library + "libc.so:" + "libdl.so:" + "libm.so:" + "libz.so:" + "libclang_rt.asan.so:" + "libclang_rt.tsan.so:" + // z library + "libace_napi.z.so:" + "libace_ndk.z.so:" + "libbundle_ndk.z.so:" + "libdeviceinfo_ndk.z.so:" + "libEGL.so:" + "libGLESv3.so:" + "libhiappevent_ndk.z.so:" + "libhuks_ndk.z.so:" + "libhukssdk.z.so:" + "libnative_drawing.so:" + "libnative_window.so:" + "libnative_buffer.so:" + "libnative_vsync.so:" + "libOpenSLES.so:" + "libpixelmap_ndk.z.so:" + "libimage_ndk.z.so:" + "libimage_receiver_ndk.z.so:" + "libimage_source_ndk.z.so:" + "librawfile.z.so:" + "libuv.so:" + "libhilog.so:" + "libnative_image.so:" + "libnative_media_adec.so:" + "libnative_media_aenc.so:" + "libnative_media_codecbase.so:" + "libnative_media_core.so:" + "libnative_media_vdec.so:" + "libnative_media_venc.so:" + "libnative_media_avmuxer.so:" + "libnative_media_avdemuxer.so:" + "libnative_media_avsource.so:" + "libnative_avscreen_capture.so:" + "libavplayer.so:" + // adaptor library + "libohosadaptor.so:" + "libusb_ndk.z.so:" + "libvulkan.so:" + // runtime library + "libarkaotmanager.so:" + "libarktarget_options.so:" + "libhmicui18n.z.so:" + "libes2panda-public.so:" + "libes2panda-lib.so:" + "libhmicuuc.z.so:" + "libarkcompiler.so:" + "libarkassembler.so:" + "libarkfile.so:" + "libarkziparchive.so:" + "libarkbase.so:" + "libc_secshared.so:" + "libhilog_ndk.z.so:" + "libarkplatform.so"; +} +} + +void DynamicInitNamespace(Dl_namespace* ns, void* parent, const char* entries, const char* name) +{ + if (ns == nullptr || entries == nullptr || name == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Invaild args for init namespace."); + return; + } + if (g_hasInited.count(std::string(name))) { + return; + } + dlns_init(ns, name); + auto status = dlns_create2(ns, entries, 0); + std::string errMsg; + if (status != 0) { + switch (status) { + case FILE_EXISTS: + errMsg = "dlns_create failed: File exists"; + break; + case INVALID_ARGUMENT: + errMsg = "dlns_create failed: Invalid argument"; + break; + case OUT_OF_MEMORY: + errMsg = "dlns_create failed: Out of memory"; + break; + default: + errMsg = "dlns_create failed, status: " + std::to_string(status); + } + if (sprintf_s(g_dlError, sizeof(g_dlError), errMsg.c_str()) == -1) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Fail to generate error msg."); + return; + } + return; + } + if (parent) { + dlns_inherit((Dl_namespace*)parent, ns, "allow_all_shared_libs"); + } + Dl_namespace current; + dlns_get(nullptr, ¤t); + if (strcmp(name, "ets_app") != 0) { + dlns_inherit(ns, ¤t, "allow_all_shared_libs"); + } else { + InitSharedLibsSonames(); + dlns_inherit(ns, ¤t, g_sharedLibsSonames.c_str()); + } + g_hasInited.insert(std::string(name)); +} + +void* DynamicLoadLibrary(Dl_namespace *ns, const char* dlPath, uint32_t mode) +{ + if (ns == nullptr) { + dlns_get("ets_app", ns); + } + + auto result = dlopen_ns(ns, dlPath, mode | RTLD_GLOBAL | RTLD_NOW); + if (!result) { + ReadDlError(); + } + return result; +} + +void* DynamicFindSymbol(void* so, const char* symbol) +{ + return dlsym(so, symbol); +} + +void DynamicFreeLibrary(void* so) +{ + (void)dlclose(so); +} + +const char* DynamicGetError() +{ + return g_dlError; +} +} // namespace EtsEnv +} // namespace OHOS \ No newline at end of file diff --git a/ets_environment/frameworks/ets_environment/src/ets_environment.cpp b/ets_environment/frameworks/ets_environment/src/ets_environment.cpp new file mode 100644 index 00000000000..bf0d572a489 --- /dev/null +++ b/ets_environment/frameworks/ets_environment/src/ets_environment.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2025 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 "ets_environment.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dynamic_loader.h" +#include "elf_factory.h" +#include "event_handler.h" +#include "hilog_tag_wrapper.h" +#include "unwinder.h" + +#ifdef SUPPORT_GRAPHICS +#include "ui_content.h" +#endif // SUPPORT_GRAPHICS + +namespace OHOS { +namespace EtsEnv { +namespace { +const char ETS_CREATE_VM[] = "ANI_CreateVM"; +const char ETS_ANI_GET_CREATEDVMS[] = "ANI_GetCreatedVMs"; +const char ETS_LIB_PATH[] = "libets_interop_js_napi.z.so"; +const char BOOT_PATH[] = "/system/framework/bootpath.json"; +const char BACKTRACE[] = "=====================Backtrace========================"; + +using CreateVMETSRuntimeType = ani_status (*)(const ani_options *options, uint32_t version, ani_vm **result); +using ANIGetCreatedVMsType = ani_status (*)(ani_vm **vms_buffer, ani_size vms_buffer_length, ani_size *result); + +const char ETS_SDK_NSNAME[] = "ets_sdk"; +const char ETS_SYS_NSNAME[] = "ets_system"; +} + +ETSRuntimeAPI ETSEnvironment::lazyApis_{}; + +bool ETSEnvironment::LoadBootPathFile(std::string& bootfiles) +{ + std::ifstream inFile; + inFile.open(BOOT_PATH, std::ios::in); + if (!inFile.is_open()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "read json error"); + return false; + } + nlohmann::json jsonObject = nlohmann::json::parse(inFile); + if (jsonObject.is_discarded()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "json discarded error"); + inFile.close(); + return false; + } + + if (jsonObject.is_null() || jsonObject.empty()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "invalid json"); + inFile.close(); + return false; + } + + for (const auto &[key, value] : jsonObject.items()) { + if (!value.is_null() && value.is_string()) { + std::string jsonValue = value.get(); + if (jsonValue.empty()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "json value of %{public}s is empty", key.c_str()); + continue; + } + if (!bootfiles.empty()) { + bootfiles += ":"; + } + bootfiles += jsonValue.c_str(); + } + } + inFile.close(); + return true; +} + +bool ETSEnvironment::LoadRuntimeApis() +{ + static bool isRuntimeApiLoaded{ false }; + if (isRuntimeApiLoaded) { + return true; + } + + Dl_namespace ns; + dlns_get(ETS_SDK_NSNAME, &ns); + auto dso = DynamicLoadLibrary(&ns, ETS_LIB_PATH, 1); + if (!dso) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "load library failed: %{public}s", ETS_LIB_PATH); + return false; + } + + if (!LoadSymbolCreateVM(dso, lazyApis_) || + !LoadSymbolANIGetCreatedVMs(dso, lazyApis_)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "load symbol failed"); + return false; + } + + isRuntimeApiLoaded = true; + return true; +} + +std::string ETSEnvironment::GetBuildId(std::string stack) +{ + std::stringstream ss(stack); + std::string tempStr = ""; + std::string addBuildId = ""; + int i = 0; + while (std::getline(ss, tempStr)) { + auto spitlPos = tempStr.rfind(" "); + if (spitlPos != std::string::npos) { + HiviewDFX::RegularElfFactory elfFactory(tempStr.substr(spitlPos + 1)); + auto elfFile = elfFactory.Create(); + if (elfFile == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null elfFile"); + break; + } + std::string buildId = elfFile->GetBuildId(); + if (i != 0 && !buildId.empty()) { + addBuildId += tempStr + "(" + buildId + ")" + "\n"; + } else { + addBuildId += tempStr + "\n"; + } + } + i++; + } + return addBuildId; +} + +void ETSEnvironment::RegisterUncaughtExceptionHandler(const ETSUncaughtExceptionInfo& handle) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "RegisterUncaughtExceptionHandler called"); + uncaughtExceptionInfo_ = handle; +} + +bool ETSEnvironment::LoadSymbolCreateVM(void* handle, ETSRuntimeAPI& apis) +{ + auto symbol = dlsym(handle, ETS_CREATE_VM); + if (symbol == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "runtime api not found: %{public}s", ETS_CREATE_VM); + return false; + } + apis.ANI_CreateVM = reinterpret_cast(symbol); + + return true; +} + +bool ETSEnvironment::LoadSymbolANIGetCreatedVMs(void* handle, ETSRuntimeAPI& apis) +{ + auto symbol = dlsym(handle, ETS_ANI_GET_CREATEDVMS); + if (symbol == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "runtime api not found: %{public}s", ETS_ANI_GET_CREATEDVMS); + return false; + } + apis.ANI_GetCreatedVMs = reinterpret_cast(symbol); + + return true; +} + +void ETSEnvironment::InitETSSDKNS(const std::string& path) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "InitETSSDKNS: %{public}s", path.c_str()); + Dl_namespace ndk; + Dl_namespace ns; + DynamicInitNamespace(&ns, nullptr, path.c_str(), ETS_SDK_NSNAME); + dlns_get("ndk", &ndk); + dlns_inherit(&ns, &ndk, "allow_all_shared_libs"); +} + +void ETSEnvironment::InitETSSysNS(const std::string& path) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "InitETSSysNS: %{public}s", path.c_str()); + Dl_namespace ets_sdk; + Dl_namespace ndk; + Dl_namespace ns; + dlns_get(ETS_SDK_NSNAME, &ets_sdk); + DynamicInitNamespace(&ns, &ets_sdk, path.c_str(), ETS_SYS_NSNAME); + dlns_get("ndk", &ndk); + dlns_inherit(&ns, &ndk, "allow_all_shared_libs"); +} + +bool ETSEnvironment::Initialize(napi_env napiEnv, std::vector& options) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "StartRuntime called"); + if (!LoadRuntimeApis()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "LoadRuntimeApis failed"); + return false; + } + std::string bootfiles; + if (!LoadBootPathFile(bootfiles)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "LoadBootPathFile failed"); + return false; + } + const std::string optionPrefix = "--ext:"; + // Create boot-panda-files options + std::string bootString = optionPrefix + "--boot-panda-files=" + bootfiles; + TAG_LOGI(AAFwkTag::ETSRUNTIME, "bootString %{public}s", bootString.c_str()); + options.push_back(ani_option{bootString.c_str(), nullptr}); + std::string schedulingExternal = optionPrefix + "--coroutine-enable-external-scheduling=true"; + ani_option schedulingExternalOption = {schedulingExternal.data(), nullptr}; + options.push_back(schedulingExternalOption); + + std::string forbiddenJIT = optionPrefix + "--compiler-enable-jit=false"; + ani_option forbiddenJITOption = {forbiddenJIT.data(), nullptr}; + options.push_back(forbiddenJITOption); + options.push_back(ani_option{"--ext:--log-level=info", nullptr}); + std::string enableVerfication = optionPrefix + "--verification-enabled=true"; + ani_option enableVerficationOption = {enableVerfication.data(), nullptr}; + options.push_back(enableVerficationOption); + + std::string verificationMode = optionPrefix + "--verification-mode=on-the-fly"; + ani_option verificationModeOption = {verificationMode.data(), nullptr}; + options.push_back(verificationModeOption); + + std::string interop = optionPrefix + "interop"; + ani_option interopOption = {interop.data(), (void*)napiEnv}; + options.push_back(interopOption); + 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) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "ANI_CreateVM failed %{public}d", status); + return false; + } + if ((status = vmEntry_.aniVm_->GetEnv(ANI_VERSION_1, &vmEntry_.aniEnv_)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "GetEnv failed %{public}d", status); + return false; + } + return true; +} + +ani_env* ETSEnvironment::GetAniEnv() +{ + return vmEntry_.aniEnv_; +} + +void ETSEnvironment::HandleUncaughtError() +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "HandleUncaughtError called"); + const EtsEnv::ETSErrorObject errorObj = GetETSErrorObject(); + std::string errorStack = errorObj.stack; + if (errorStack.empty()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "errorStack is empty"); + return; + } + TAG_LOGE(AAFwkTag::ETSRUNTIME, "errorObj.name:%{public}s, errorObj.message:%{public}s,errorObj.stack:%{public}s", + errorObj.name.c_str(), errorObj.message.c_str(), errorObj.stack.c_str()); + std::string summary = "Error name:" + errorObj.name + "\n"; + summary += "Error message:" + errorObj.message + "\n"; + if (errorStack.find(BACKTRACE) != std::string::npos) { + summary += "Stacktrace:\n" + GetBuildId(errorStack); + } else { + summary += "Stacktrace:\n" + errorStack; + } +#ifdef SUPPORT_GRAPHICS + std::string str = Ace::UIContent::GetCurrentUIStackInfo(); + if (!str.empty()) { + summary.append(str); + } +#endif // SUPPORT_GRAPHICS + if (uncaughtExceptionInfo_.uncaughtTask) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "uncaughtTask called"); + uncaughtExceptionInfo_.uncaughtTask(summary, errorObj); + } +} + +EtsEnv::ETSErrorObject ETSEnvironment::GetETSErrorObject() +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "GetETSErrorObject called"); + ani_boolean errorExists = ANI_FALSE; + ani_status status = ANI_ERROR; + auto aniEnv = GetAniEnv(); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null env"); + return EtsEnv::ETSErrorObject(); + } + if ((status = aniEnv->ExistUnhandledError(&errorExists)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "ExistUnhandledError failed, status : %{public}d", status); + return EtsEnv::ETSErrorObject(); + } + if (errorExists == ANI_FALSE) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "not exist error"); + return EtsEnv::ETSErrorObject(); + } + ani_error aniError = nullptr; + if ((status = aniEnv->GetUnhandledError(&aniError)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "GetUnhandledError failed, status : %{public}d", status); + return EtsEnv::ETSErrorObject(); + } + if ((status = aniEnv->ResetError()) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "ResetError failed, status : %{public}d", status); + return EtsEnv::ETSErrorObject(); + } + std::string errorMsg = GetErrorProperty(aniError, "message"); + std::string errorName = GetErrorProperty(aniError, "name"); + std::string errorStack = GetErrorProperty(aniError, "stack"); + const EtsEnv::ETSErrorObject errorObj = { + .name = errorName, + .message = errorMsg, + .stack = errorStack + }; + return errorObj; +} + +std::string ETSEnvironment::GetErrorProperty(ani_error aniError, const char* property) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "GetErrorProperty called"); + auto aniEnv = GetAniEnv(); + std::string propertyValue; + ani_status status = ANI_ERROR; + ani_type errorType = nullptr; + if ((status = aniEnv->Object_GetType(aniError, &errorType)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Object_GetType failed, status : %{public}d", status); + return propertyValue; + } + ani_method getterMethod = nullptr; + if ((status = aniEnv->Class_FindGetter(static_cast(errorType), property, &getterMethod)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Class_FindGetter failed, status : %{public}d", status); + return propertyValue; + } + ani_ref aniRef = nullptr; + if ((status = aniEnv->Object_CallMethod_Ref(aniError, getterMethod, &aniRef)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Object_CallMethod_Ref failed, status : %{public}d", status); + return propertyValue; + } + ani_string aniString = reinterpret_cast(aniRef); + ani_size sz {}; + if ((status = aniEnv->String_GetUTF8Size(aniString, &sz)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "String_GetUTF8Size failed, status : %{public}d", status); + return propertyValue; + } + propertyValue.resize(sz + 1); + if ((status = aniEnv->String_GetUTF8SubString( + aniString, 0, sz, propertyValue.data(), propertyValue.size(), &sz))!= ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "String_GetUTF8SubString failed, status : %{public}d", status); + return propertyValue; + } + propertyValue.resize(sz); + return propertyValue; +} +} // namespace EtsEnv +} // namespace OHOS diff --git a/ets_environment/interfaces/inner_api/dynamic_loader.h b/ets_environment/interfaces/inner_api/dynamic_loader.h new file mode 100644 index 00000000000..86c2052bacf --- /dev/null +++ b/ets_environment/interfaces/inner_api/dynamic_loader.h @@ -0,0 +1,31 @@ +/* +* Copyright (c) 2025 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 OHOS_ABILITY_RUNTIME_DYNAMIC_LOADER_H +#define OHOS_ABILITY_RUNTIME_DYNAMIC_LOADER_H + +#include +#include + +namespace OHOS { +namespace EtsEnv { +void* DynamicLoadLibrary(Dl_namespace *ns, const char* dlPath, uint32_t mode); +void* DynamicFindSymbol(void* so, const char* symbol); +const char* DynamicGetError(); +void DynamicFreeLibrary(void* so); +void DynamicInitNamespace(Dl_namespace* ns, void* parent, const char* entries, const char* name); +} // namespace EtsEnv +} // namespace OHOS +#endif //OHOS_ABILITY_RUNTIME_DYNAMIC_LOADER_H diff --git a/ets_environment/interfaces/inner_api/ets_environment.h b/ets_environment/interfaces/inner_api/ets_environment.h new file mode 100644 index 00000000000..415f2832b8a --- /dev/null +++ b/ets_environment/interfaces/inner_api/ets_environment.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 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 OHOS_ABILITY_RUNTIME_ETS_ENVIRONMENT_H +#define OHOS_ABILITY_RUNTIME_ETS_ENVIRONMENT_H + +#include +#include +#include +#include + +#include "ani.h" +#include "event_handler.h" +#include "ets_exception_callback.h" +#include "napi/native_api.h" + +namespace OHOS { +namespace EtsEnv { +struct ETSRuntimeAPI { + ani_status (*ANI_GetCreatedVMs)(ani_vm **vms_buffer, ani_size vms_buffer_length, ani_size *result); + ani_status (*ANI_CreateVM)(const ani_options *options, uint32_t version, ani_vm **result); +}; + +class ETSEnvironment final : public std::enable_shared_from_this { +public: + ETSEnvironment() {}; + + static void InitETSSDKNS(const std::string& path); + static void InitETSSysNS(const std::string& path); + + bool Initialize(napi_env napiEnv, std::vector& options); + void RegisterUncaughtExceptionHandler(const ETSUncaughtExceptionInfo& handle); + ani_env* GetAniEnv(); + void HandleUncaughtError(); + + struct VMEntry { + ani_vm *aniVm_; + ani_env *aniEnv_; + VMEntry() + { + aniVm_ = nullptr; + aniEnv_ = nullptr; + } + }; + +private: + bool LoadRuntimeApis(); + bool LoadSymbolCreateVM(void* handle, ETSRuntimeAPI& apis); + bool LoadSymbolANIGetCreatedVMs(void* handle, ETSRuntimeAPI& apis); + bool LoadBootPathFile(std::string& bootfiles); + std::string GetBuildId(std::string stack); + EtsEnv::ETSErrorObject GetETSErrorObject(); + std::string GetErrorProperty(ani_error aniError, const char* property); + static ETSRuntimeAPI lazyApis_; + VMEntry vmEntry_; + ETSUncaughtExceptionInfo uncaughtExceptionInfo_; +}; +} // namespace EtsEnv +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_ENVIRONMENT_H diff --git a/ets_environment/interfaces/inner_api/ets_exception_callback.h b/ets_environment/interfaces/inner_api/ets_exception_callback.h new file mode 100644 index 00000000000..2d935af7f1f --- /dev/null +++ b/ets_environment/interfaces/inner_api/ets_exception_callback.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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 OHOS_ABILITY_RUNTIME_ETS_EXCEPTION_CALLBACK_H +#define OHOS_ABILITY_RUNTIME_ETS_EXCEPTION_CALLBACK_H + +#include + +namespace OHOS { +namespace EtsEnv { +struct ETSErrorObject { + std::string name; + std::string message; + std::string stack; +}; + +struct ETSUncaughtExceptionInfo { + std::function uncaughtTask; +}; +} // namespace EtsEnv +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_EXCEPTION_CALLBACK_H diff --git a/frameworks/cj/ffi/BUILD.gn b/frameworks/cj/ffi/BUILD.gn index 03df8fc4f90..b9797aa4792 100644 --- a/frameworks/cj/ffi/BUILD.gn +++ b/frameworks/cj/ffi/BUILD.gn @@ -69,6 +69,7 @@ ohos_shared_library("cj_ability_ffi") { "napi:ace_napi", "napi:cj_bind_ffi", "napi:cj_bind_native", + "runtime_core:ani", ] sources = [ diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index 831a39ff221..c06d5a98c59 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -155,6 +155,7 @@ ohos_shared_library("abilitykit_utils") { "${ability_runtime_path}/interfaces/kits/native/ability/native", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/app", "${ability_runtime_innerkits_path}/ability_manager/include", + "${ability_runtime_innerkits_path}/runtime/include", "${ability_runtime_innerkits_path}/wantagent/include", "${ability_runtime_services_path}/abilitymgr/include/utils", "${ability_runtime_services_path}/abilitymgr/include", diff --git a/frameworks/native/ability/native/ability_loader.cpp b/frameworks/native/ability/native/ability_loader.cpp index 1c26bd9c57a..1a8f740a1c2 100644 --- a/frameworks/native/ability/native/ability_loader.cpp +++ b/frameworks/native/ability/native/ability_loader.cpp @@ -52,21 +52,23 @@ Ability *AbilityLoader::GetAbilityByName(const std::string &abilityName) return nullptr; } -AbilityRuntime::Extension *AbilityLoader::GetExtensionByName(const std::string &abilityName) +AbilityRuntime::Extension *AbilityLoader::GetExtensionByName(const std::string &abilityName, + const std::string &language) { auto it = extensions_.find(abilityName); if (it != extensions_.end()) { - return it->second(); + return it->second(language); } TAG_LOGE(AAFwkTag::ABILITY, "failed:%{public}s", abilityName.c_str()); return nullptr; } -AbilityRuntime::UIAbility *AbilityLoader::GetUIAbilityByName(const std::string &abilityName) +AbilityRuntime::UIAbility *AbilityLoader::GetUIAbilityByName(const std::string &abilityName, + const std::string &language) { auto it = uiAbilities_.find(abilityName); if (it != uiAbilities_.end()) { - return it->second(); + return it->second(language); } TAG_LOGE(AAFwkTag::ABILITY, "failed:%{public}s", abilityName.c_str()); return nullptr; diff --git a/frameworks/native/ability/native/extension_ability_thread.cpp b/frameworks/native/ability/native/extension_ability_thread.cpp index f72fa0f4c2a..6a7633b3519 100644 --- a/frameworks/native/ability/native/extension_ability_thread.cpp +++ b/frameworks/native/ability/native/extension_ability_thread.cpp @@ -242,7 +242,13 @@ void ExtensionAbilityThread::HandleAttach(const std::shared_ptr abilityInfo = abilityRecord->GetAbilityInfo(); + if (abilityInfo == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "null abilityInfo"); + return; + } + auto extension = AppExecFwk::AbilityLoader::GetInstance().GetExtensionByName(abilityName, + abilityInfo->codeLanguage); if (extension == nullptr) { TAG_LOGE(AAFwkTag::EXT, "null extension"); return; diff --git a/frameworks/native/ability/native/ui_ability_thread.cpp b/frameworks/native/ability/native/ui_ability_thread.cpp index 18d97dee4d6..e20643c4440 100644 --- a/frameworks/native/ability/native/ui_ability_thread.cpp +++ b/frameworks/native/ability/native/ui_ability_thread.cpp @@ -131,7 +131,8 @@ void UIAbilityThread::Attach(const std::shared_ptr } // 2.new ability - auto ability = AppExecFwk::AbilityLoader::GetInstance().GetUIAbilityByName(abilityName); + auto ability = AppExecFwk::AbilityLoader::GetInstance().GetUIAbilityByName( + abilityName, abilityRecord->GetAbilityInfo()->codeLanguage); if (ability == nullptr) { TAG_LOGE(AAFwkTag::UIABILITY, "null ability"); return; @@ -203,7 +204,8 @@ void UIAbilityThread::Attach(const std::shared_ptr } // 2.new ability - auto ability = AppExecFwk::AbilityLoader::GetInstance().GetUIAbilityByName(abilityName); + auto ability = AppExecFwk::AbilityLoader::GetInstance().GetUIAbilityByName( + abilityName, abilityRecord->GetAbilityInfo()->codeLanguage); if (ability == nullptr) { TAG_LOGE(AAFwkTag::UIABILITY, "null ability"); return; diff --git a/frameworks/native/appkit/BUILD.gn b/frameworks/native/appkit/BUILD.gn index cc0227d2feb..65fc38a185d 100644 --- a/frameworks/native/appkit/BUILD.gn +++ b/frameworks/native/appkit/BUILD.gn @@ -60,6 +60,7 @@ config("appkit_public_config") { "${ability_runtime_path}/interfaces/kits/native/appkit/app", "${ability_runtime_path}/interfaces/kits/native/appkit/dfr", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_bundle_manager_helper", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", ] if (ability_runtime_graphics) { @@ -83,6 +84,7 @@ ohos_shared_library("appkit_native") { "${ability_runtime_path}/interfaces/kits/native/appkit/dfr", "${ability_runtime_path}/interfaces/kits/native/appkit/app/task", "${ability_runtime_path}/interfaces/kits/native/appkit/app_startup", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", "${ability_runtime_innerkits_path}/deps_wrapper/include", "${ability_runtime_services_path}/common/include", "${ability_runtime_path}/interfaces/kits/native/ability/native", @@ -166,6 +168,7 @@ ohos_shared_library("appkit_native") { "${ability_runtime_native_path}/appkit:app_context", "${ability_runtime_native_path}/appkit:app_context_utils", "${ability_runtime_native_path}/appkit:appkit_manager_helper", + "${ability_runtime_path}/ets_environment/frameworks/ets_environment:ets_environment", "${ability_runtime_path}/js_environment/frameworks/js_environment:js_environment", "${ability_runtime_path}/utils/global/freeze:freeze_util", "${ability_runtime_services_path}/common:app_util", @@ -208,6 +211,7 @@ ohos_shared_library("appkit_native") { "napi:ace_napi", "preferences:native_preferences", "resource_management:global_resmgr", + "runtime_core:ani", "safwk:system_ability_fwk", "samgr:samgr_proxy", "storage_service:storage_manager_acl", diff --git a/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp b/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp index 7187c88382e..c11700597ff 100644 --- a/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp +++ b/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp @@ -17,20 +17,30 @@ namespace OHOS { namespace AppExecFwk { -std::shared_ptr AbilityDelegatorRegistry::abilityDelegator_ {}; +std::map> AbilityDelegatorRegistry::abilityDelegator_ {}; std::shared_ptr AbilityDelegatorRegistry::abilityDelegatorArgs_ {}; -std::shared_ptr AbilityDelegatorRegistry::GetAbilityDelegator() +std::shared_ptr AbilityDelegatorRegistry::GetAbilityDelegator( + const AbilityRuntime::Runtime::Language &language) { - auto p = reinterpret_cast(abilityDelegator_.get()); - return std::shared_ptr(abilityDelegator_, p); + auto it = abilityDelegator_.find(language); + if (it != abilityDelegator_.end()) { + auto p = reinterpret_cast(it->second.get()); + return std::shared_ptr(it->second, p); + } + return nullptr; } #ifdef CJ_FRONTEND std::shared_ptr AbilityDelegatorRegistry::GetCJAbilityDelegator() { - auto p = reinterpret_cast(abilityDelegator_.get()); - return std::shared_ptr(abilityDelegator_, p); + auto it = abilityDelegator_.find(AbilityRuntime::Runtime::Language::CJ); + if (it != abilityDelegator_.end()) { + auto p = reinterpret_cast(it->second.get()); + return std::shared_ptr(it->second, p); + } + return nullptr; } #endif @@ -40,10 +50,11 @@ std::shared_ptr AbilityDelegatorRegistry::GetArguments() } void AbilityDelegatorRegistry::RegisterInstance( - const std::shared_ptr& delegator, const std::shared_ptr& args) + const std::shared_ptr &delegator, const std::shared_ptr &args, + const AbilityRuntime::Runtime::Language &language) { - abilityDelegator_ = delegator; abilityDelegatorArgs_ = args; + abilityDelegator_.emplace(language, delegator); } } // namespace AppExecFwk } // namespace OHOS diff --git a/frameworks/native/appkit/app/application_data_manager.cpp b/frameworks/native/appkit/app/application_data_manager.cpp index 6dfd3a4493e..79c2449ccbf 100644 --- a/frameworks/native/appkit/app/application_data_manager.cpp +++ b/frameworks/native/appkit/app/application_data_manager.cpp @@ -59,6 +59,15 @@ bool ApplicationDataManager::NotifyCJUnhandledException(const std::string &errMs return AppRecovery::GetInstance().TryRecoverApp(StateReason::CJ_ERROR); } +bool ApplicationDataManager::NotifyETSUnhandledException(const std::string &errMsg) +{ + if (errorObserver_) { + errorObserver_->OnUnhandledException(errMsg); + return true; + } + return AppRecovery::GetInstance().TryRecoverApp(StateReason::JS_ERROR); +} + void ApplicationDataManager::RemoveErrorObserver() { errorObserver_ = nullptr; @@ -88,5 +97,15 @@ bool ApplicationDataManager::NotifyCJExceptionObject(const AppExecFwk::ErrorObje // and restart as developer wants return AppRecovery::GetInstance().TryRecoverApp(StateReason::CJ_ERROR); } + +bool ApplicationDataManager::NotifyETSExceptionObject(const AppExecFwk::ErrorObject &errorObj) +{ + TAG_LOGD(AAFwkTag::APPKIT, "Notify Exception error observer come"); + if (errorObserver_) { + errorObserver_->OnExceptionObject(errorObj); + return true; + } + return AppRecovery::GetInstance().TryRecoverApp(StateReason::JS_ERROR); +} } // namespace AppExecFwk } // namespace OHOS diff --git a/frameworks/native/appkit/app/dump_runtime_helper.cpp b/frameworks/native/appkit/app/dump_runtime_helper.cpp index 15fe19517b3..2a3dbb8833f 100644 --- a/frameworks/native/appkit/app/dump_runtime_helper.cpp +++ b/frameworks/native/appkit/app/dump_runtime_helper.cpp @@ -87,7 +87,7 @@ void DumpRuntimeHelper::SetAppFreezeFilterCallback() TAG_LOGE(AAFwkTag::APPKIT, "null application"); return; } - auto& runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; @@ -205,7 +205,7 @@ void DumpRuntimeHelper::DumpJsHeap(const OHOS::AppExecFwk::JsHeapDumpInfo &info) TAG_LOGE(AAFwkTag::APPKIT, "null application"); return; } - auto& runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; @@ -235,7 +235,7 @@ void DumpRuntimeHelper::DumpCjHeap(const OHOS::AppExecFwk::CjHeapDumpInfo &info) TAG_LOGE(AAFwkTag::APPKIT, "null application"); return; } - auto& runtime = application_->GetRuntime(); + auto& runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; diff --git a/frameworks/native/appkit/app/main_thread.cpp b/frameworks/native/appkit/app/main_thread.cpp index c80d3ea85cc..e6583a9724b 100644 --- a/frameworks/native/appkit/app/main_thread.cpp +++ b/frameworks/native/appkit/app/main_thread.cpp @@ -75,6 +75,7 @@ #include "if_system_ability_manager.h" #include "iservice_registry.h" #include "js_runtime.h" +#include "ets_runtime.h" #ifdef CJ_FRONTEND #include "cj_runtime.h" #endif @@ -183,6 +184,7 @@ const char* PC_LIBRARY_PATH = "/system/lib64/liblayered_parameters_manager.z.so" const char* PC_FUNC_INFO = "DetermineResourceType"; const int32_t TYPE_RESERVE = 1; const int32_t TYPE_OTHERS = 2; +std::unique_ptr RUNTIME_NULL = nullptr; #if defined(NWEB) constexpr int32_t PRELOAD_DELAY_TIME = 2000; //millisecond @@ -1375,6 +1377,59 @@ CJUncaughtExceptionInfo MainThread::CreateCjExceptionInfo(const std::string &bun return uncaughtExceptionInfo; } #endif + +EtsEnv::ETSUncaughtExceptionInfo MainThread::CreateEtsExceptionInfo(const std::string& bundleName, uint32_t versionCode, + const std::string& hapPath, std::string& appRunningId, int32_t pid, std::string& processName) +{ + EtsEnv::ETSUncaughtExceptionInfo uncaughtExceptionInfo; + wptr weak = this; + uncaughtExceptionInfo.uncaughtTask = [weak, bundleName, versionCode, appRunningId = std::move(appRunningId), pid, + processName](std::string summary, const EtsEnv::ETSErrorObject errorObj) { + auto appThread = weak.promote(); + if (appThread == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null appThread"); + return; + } + time_t timet; + time(&timet); + HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::AAFWK, "JS_ERROR", + OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, EVENT_KEY_PACKAGE_NAME, bundleName, EVENT_KEY_VERSION, + std::to_string(versionCode), EVENT_KEY_TYPE, JSCRASH_TYPE, EVENT_KEY_HAPPEN_TIME, timet, EVENT_KEY_REASON, + errorObj.name, EVENT_KEY_JSVM, JSVM_TYPE, EVENT_KEY_SUMMARY, summary, EVENT_KEY_PNAME, processName, + EVENT_KEY_APP_RUNING_UNIQUE_ID, appRunningId); + ErrorObject appExecErrorObj = { .name = errorObj.name, .message = errorObj.message, .stack = errorObj.stack }; + FaultData faultData; + faultData.faultType = FaultDataType::JS_ERROR; + faultData.errorObject = appExecErrorObj; + DelayedSingleton::GetInstance()->NotifyAppFault(faultData); + if (ApplicationDataManager::GetInstance().NotifyETSUnhandledException(summary) && + ApplicationDataManager::GetInstance().NotifyETSExceptionObject(appExecErrorObj)) { + return; + } + TAG_LOGE(AAFwkTag::APPKIT, + "\n%{public}s is about to exit due to RuntimeError\nError " + "type:%{public}s\n%{public}s", + bundleName.c_str(), errorObj.name.c_str(), summary.c_str()); + bool foreground = false; + if (appThread->applicationImpl_ && + appThread->applicationImpl_->GetState() == ApplicationImpl::APP_STATE_FOREGROUND) { + foreground = true; + } + int result = HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::FRAMEWORK, "PROCESS_KILL", + HiviewDFX::HiSysEvent::EventType::FAULT, "PID", pid, "PROCESS_NAME", processName, "MSG", KILL_REASON, + "FOREGROUND", foreground); + TAG_LOGW(AAFwkTag::APPKIT, + "hisysevent write result=%{public}d, send event " + "[FRAMEWORK,PROCESS_KILL]," + " pid=%{public}d, processName=%{public}s, msg=%{public}s, " + "foreground=%{public}d", + result, pid, processName.c_str(), KILL_REASON, foreground); + AAFwk::ExitReason exitReason = { REASON_JS_ERROR, errorObj.name }; + AbilityManagerClient::GetInstance()->RecordAppExitReason(exitReason); + _exit(JS_ERROR_EXIT); + }; + return uncaughtExceptionInfo; +} /** * * @brief Launch the application. @@ -1562,6 +1617,9 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con } else { #endif AbilityRuntime::JsRuntime::SetAppLibPath(appLibPaths, isSystemApp); + if (IsNeedEtsInit(appInfo)) { + AbilityRuntime::ETSRuntime::SetAppLibPath(appLibPaths); + } #ifdef CJ_FRONTEND } #endif @@ -1588,7 +1646,14 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con options.pkgContextInfoJsonStringMap = pkgContextInfoJsonStringMap; options.allowArkTsLargeHeap = appInfo.allowArkTsLargeHeap; #ifdef CJ_FRONTEND - options.lang = isCJApp ? AbilityRuntime::Runtime::Language::CJ : AbilityRuntime::Runtime::Language::JS; + if (isCJApp) { + options.langs.emplace(AbilityRuntime::Runtime::Language::CJ, true); + application_->SetCJApplication(true); + } else { + AddRuntimeLang(appInfo, options); + } +#else + AddRuntimeLang(appInfo, options); #endif if (applicationInfo_->appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG) { TAG_LOGD(AAFwkTag::APPKIT, "multi-thread mode: %{public}d", appLaunchData.GetMultiThread()); @@ -1622,12 +1687,12 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con static_cast(hapModuleInfo.aotCompileStatus); } } - auto runtime = AbilityRuntime::Runtime::Create(options); - if (!runtime) { - TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); + std::vector> runtimes = AbilityRuntime::Runtime::CreateRuntimes(options); + if (runtimes.empty()) { + TAG_LOGE(AAFwkTag::APPKIT, "runtimes empty"); return; } - + auto& runtimeVerOne = GetVerOneRuntime(appInfo, runtimes); if (appInfo.debug && appLaunchData.GetDebugApp()) { wptr weak = this; auto cb = [weak]() { @@ -1638,7 +1703,9 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con } return appThread->NotifyDeviceDisConnect(); }; - runtime->SetDeviceDisconnectCallback(cb); + if (runtimeVerOne != nullptr) { + runtimeVerOne->SetDeviceDisconnectCallback(cb); + } } auto perfCmd = appLaunchData.GetPerfCmd(); @@ -1649,11 +1716,13 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con processName = processInfo_->GetProcessName(); TAG_LOGD(AAFwkTag::APPKIT, "pid is %{public}d, processName is %{public}s", pid, processName.c_str()); } - runtime->SetStopPreloadSoCallback([uid = bundleInfo.applicationInfo.uid, currentPid = pid, - bundleName = appInfo.bundleName]()-> void { - TAG_LOGD(AAFwkTag::APPKIT, "runtime callback and report load abc completed info to rss."); - ResHelper::ReportLoadAbcCompletedInfoToRss(uid, currentPid, bundleName); - }); + if (runtimeVerOne != nullptr) { + runtimeVerOne->SetStopPreloadSoCallback([uid = bundleInfo.applicationInfo.uid, currentPid = pid, + bundleName = appInfo.bundleName]()-> void { + TAG_LOGD(AAFwkTag::APPKIT, "runtime callback and report load abc completed info to rss."); + ResHelper::ReportLoadAbcCompletedInfoToRss(uid, currentPid, bundleName); + }); + } AbilityRuntime::Runtime::DebugOption debugOption; debugOption.isStartWithDebug = appLaunchData.GetDebugApp(); debugOption.processName = processName; @@ -1663,13 +1732,19 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con debugOption.isDebugFromLocal = appLaunchData.GetDebugFromLocal(); debugOption.perfCmd = perfCmd; debugOption.isDeveloperMode = isDeveloperMode_; - runtime->SetDebugOption(debugOption); + if (runtimeVerOne != nullptr) { + runtimeVerOne->SetDebugOption(debugOption); + } if (perfCmd.find(PERFCMD_PROFILE) != std::string::npos || perfCmd.find(PERFCMD_DUMPHEAP) != std::string::npos) { TAG_LOGD(AAFwkTag::APPKIT, "perfCmd is %{public}s", perfCmd.c_str()); - runtime->StartProfiler(debugOption); + if (runtimeVerOne != nullptr) { + runtimeVerOne->StartProfiler(debugOption); + } } else { - runtime->StartDebugMode(debugOption); + if (runtimeVerOne != nullptr) { + runtimeVerOne->StartDebugMode(debugOption); + } } std::vector hqfInfos = appInfo.appQuickFix.deployedAppqfInfo.hqfInfos; @@ -1680,7 +1755,9 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con it->moduleName.c_str(), it->hqfFilePath.c_str()); modulePaths.insert(std::make_pair(it->moduleName, it->hqfFilePath)); } - runtime->RegisterQuickFixQueryFunc(modulePaths); + if (runtimeVerOne != nullptr) { + runtimeVerOne->RegisterQuickFixQueryFunc(modulePaths); + } } auto bundleName = appInfo.bundleName; @@ -1688,18 +1765,37 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con #ifdef CJ_FRONTEND if (!isCJApp) { #endif - JsEnv::UncaughtExceptionInfo uncaughtExceptionInfo; - uncaughtExceptionInfo.hapPath = hapPath; - UncatchableTaskInfo uncatchableTaskInfo = {bundleName, versionCode, appRunningId, pid, processName}; - InitUncatchableTask(uncaughtExceptionInfo.uncaughtTask, uncatchableTaskInfo); - (static_cast(*runtime)).RegisterUncaughtExceptionHandler(uncaughtExceptionInfo); - JsEnv::UncatchableTask uncatchableTask; - InitUncatchableTask(uncatchableTask, uncatchableTaskInfo, true); - (static_cast(*runtime)).RegisterUncatchableExceptionHandler(uncatchableTask); + for (const auto &runtime : runtimes) { + if (appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0 && + runtime->GetLanguage() == AbilityRuntime::Runtime::Language::JS) { + JsEnv::UncaughtExceptionInfo uncaughtExceptionInfo; + uncaughtExceptionInfo.hapPath = hapPath; + UncatchableTaskInfo uncatchableTaskInfo = {bundleName, versionCode, appRunningId, pid, processName}; + InitUncatchableTask(uncaughtExceptionInfo.uncaughtTask, uncatchableTaskInfo); + (static_cast(*runtime)).RegisterUncaughtExceptionHandler( + uncaughtExceptionInfo); + JsEnv::UncatchableTask uncatchableTask; + InitUncatchableTask(uncatchableTask, uncatchableTaskInfo, true); + (static_cast(*runtime)).RegisterUncatchableExceptionHandler( + uncatchableTask); + } + if ((appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2 || + appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_HYBRID) && + runtime->GetLanguage() == AbilityRuntime::Runtime::Language::ETS) { + auto expectionInfo = + CreateEtsExceptionInfo(bundleName, versionCode, hapPath, appRunningId, pid, processName); + runtime->RegisterUncaughtExceptionHandler((void*)&expectionInfo); + } + } #ifdef CJ_FRONTEND } else { - auto expectionInfo = CreateCjExceptionInfo(bundleName, versionCode, hapPath); - (static_cast(*runtime)).RegisterUncaughtExceptionHandler(expectionInfo); + for (const auto &runtime : runtimes) { + if (appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0 && + runtime->GetLanguage() == AbilityRuntime::Runtime::Language::CJ) { + auto expectionInfo = CreateCjExceptionInfo(bundleName, versionCode, hapPath); + runtime->RegisterUncaughtExceptionHandler((void*)&expectionInfo); + } + } } #endif wptr weak = this; @@ -1713,14 +1809,21 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con }; applicationContext->RegisterProcessSecurityExit(callback); - application_->SetRuntime(std::move(runtime)); - + for (auto &runtime : runtimes) { + application_->AddRuntime(std::move(runtime)); + } std::weak_ptr wpApplication = application_; AbilityLoader::GetInstance().RegisterUIAbility("UIAbility", - [wpApplication]() -> AbilityRuntime::UIAbility* { + [wpApplication](const std::string &language) -> AbilityRuntime::UIAbility* { auto app = wpApplication.lock(); if (app != nullptr) { - return AbilityRuntime::UIAbility::Create(app->GetRuntime()); + if (language == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2) { + return AbilityRuntime::UIAbility::Create(app->GetRuntime( + AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2)); + } else { + return AbilityRuntime::UIAbility::Create(app->GetRuntime( + AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0)); + } } TAG_LOGE(AAFwkTag::APPKIT, "failed"); return nullptr; @@ -1728,33 +1831,40 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con #ifdef CJ_FRONTEND if (!isCJApp) { #endif - auto& jsEngine = (static_cast(*application_->GetRuntime())).GetNativeEngine(); if (application_ != nullptr) { - LoadAllExtensions(jsEngine); + TAG_LOGD(AAFwkTag::APPKIT, "LoadAllExtensions lan:%{public}s", appInfo.codeLanguage.c_str()); + LoadAllExtensions(); } - - IdleTimeCallback callback = [wpApplication](int32_t idleTime) { - auto app = wpApplication.lock(); - if (app == nullptr) { - TAG_LOGE(AAFwkTag::APPKIT, "null app"); - return; - } - auto &runtime = app->GetRuntime(); + if (appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0) { + auto &runtime = application_->GetRuntime(appInfo.codeLanguage); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; } - auto& nativeEngine = (static_cast(*runtime)).GetNativeEngine(); - nativeEngine.NotifyIdleTime(idleTime); - }; - idleTime_ = std::make_shared(mainHandler_, callback); - idleTime_->Start(); - - IdleNotifyStatusCallback cb = idleTime_->GetIdleNotifyFunc(); - jsEngine.NotifyIdleStatusControl(cb); - - auto helper = std::make_shared(application_); - helper->SetAppFreezeFilterCallback(); + auto &jsEngine = (static_cast(*runtime)).GetNativeEngine(); + IdleTimeCallback callback = [wpApplication](int32_t idleTime) { + auto app = wpApplication.lock(); + if (app == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null app"); + return; + } + auto &runtime = app->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); + if (runtime == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); + return; + } + auto& nativeEngine = (static_cast(*runtime)).GetNativeEngine(); + nativeEngine.NotifyIdleTime(idleTime); + }; + idleTime_ = std::make_shared(mainHandler_, callback); + idleTime_->Start(); + + IdleNotifyStatusCallback cb = idleTime_->GetIdleNotifyFunc(); + jsEngine.NotifyIdleStatusControl(cb); + + auto helper = std::make_shared(application_); + helper->SetAppFreezeFilterCallback(); + } #ifdef CJ_FRONTEND } else { LoadAllExtensions(); @@ -1764,7 +1874,8 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con auto usertestInfo = appLaunchData.GetUserTestInfo(); if (usertestInfo) { - if (!PrepareAbilityDelegator(usertestInfo, isStageBased, entryHapModuleInfo, bundleInfo.targetVersion)) { + if (!PrepareAbilityDelegator(usertestInfo, isStageBased, entryHapModuleInfo, bundleInfo.targetVersion, + appInfo.codeLanguage)) { TAG_LOGE(AAFwkTag::APPKIT, "PrepareAbilityDelegator failed"); return; } @@ -1856,7 +1967,9 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con } #endif if (appLaunchData.IsNeedPreloadModule()) { - PreloadModule(entryHapModuleInfo, application_->GetRuntime()); + for (auto &runtime : application_->GetRuntime()) { + PreloadModule(entryHapModuleInfo, runtime); + } } } @@ -1891,7 +2004,8 @@ void MainThread::InitUncatchableTask(JsEnv::UncatchableTask &uncatchableTask, co EVENT_KEY_PROCESS_RSS_MEMINFO, std::to_string(DumpProcessHelper::GetProcRssMemInfo())); ErrorObject appExecErrorObj = { errorObject.name, errorObject.message, errorObject.stack}; - auto napiEnv = (static_cast(*appThread->application_->GetRuntime())).GetNapiEnv(); + auto napiEnv = (static_cast( + *appThread->application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0))).GetNapiEnv(); if (!isUncatchable && NapiErrorManager::GetInstance()->NotifyUncaughtException(napiEnv, summary, appExecErrorObj.name, appExecErrorObj.message, appExecErrorObj.stack)) { return; @@ -2184,7 +2298,7 @@ void MainThread::HandleUpdatePluginInfoInstalled(const ApplicationInfo &pluginAp TAG_LOGE(AAFwkTag::APPKIT, "null application_"); return; } - auto& runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; @@ -2234,7 +2348,7 @@ void MainThread::HandleUpdateApplicationInfoInstalled(const ApplicationInfo& app } application_->UpdateApplicationInfoInstalled(appInfo); - auto& runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; @@ -2322,10 +2436,11 @@ void MainThread::LoadAllExtensions() std::string file = item.extensionLibFile; std::weak_ptr wApp = application_; AbilityLoader::GetInstance().RegisterExtension(item.extensionName, - [wApp, file]() -> AbilityRuntime::Extension* { + [wApp, file](const std::string& language) -> AbilityRuntime::Extension* { auto app = wApp.lock(); if (app != nullptr) { - return AbilityRuntime::ExtensionModuleLoader::GetLoader(file.c_str()).Create(app->GetRuntime()); + return AbilityRuntime::ExtensionModuleLoader::GetLoader(file.c_str()) + .Create(app->GetRuntime(language)); } TAG_LOGE(AAFwkTag::APPKIT, "failed"); return nullptr; @@ -2335,7 +2450,8 @@ void MainThread::LoadAllExtensions() } bool MainThread::PrepareAbilityDelegator(const std::shared_ptr &record, bool isStageBased, - const AppExecFwk::HapModuleInfo &entryHapModuleInfo, uint32_t targetVersion) + const AppExecFwk::HapModuleInfo &entryHapModuleInfo, uint32_t targetVersion, + const std::string &applicationCodeLanguage) { TAG_LOGD(AAFwkTag::APPKIT, "enter, isStageBased = %{public}d", isStageBased); if (!record) { @@ -2345,12 +2461,27 @@ bool MainThread::PrepareAbilityDelegator(const std::shared_ptr & auto args = std::make_shared(record->want); if (isStageBased) { // Stage model TAG_LOGD(AAFwkTag::APPKIT, "Stage model"); - auto testRunner = TestRunner::Create(application_->GetRuntime(), args, false); - auto delegator = IAbilityDelegator::Create(application_->GetRuntime(), application_->GetAppContext(), - std::move(testRunner), record->observer); - AbilityDelegatorRegistry::RegisterInstance(delegator, args); - delegator->SetApiTargetVersion(targetVersion); - delegator->Prepare(); + if (applicationCodeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0) { + TAG_LOGI(AAFwkTag::DELEGATOR, "create 1.0 testrunner"); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); + auto testRunner = TestRunner::Create(runtime, args, false); + auto delegator = IAbilityDelegator::Create(runtime, application_->GetAppContext(), + std::move(testRunner), record->observer); + AbilityDelegatorRegistry::RegisterInstance(delegator, args, runtime->GetLanguage()); + delegator->SetApiTargetVersion(targetVersion); + delegator->Prepare(); + } + + if (applicationCodeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2) { + TAG_LOGI(AAFwkTag::DELEGATOR, "create 1.2 testrunner"); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2); + auto testRunner = TestRunner::Create(runtime, args, false); + auto delegator = IAbilityDelegator::Create(runtime, application_->GetAppContext(), + std::move(testRunner), record->observer); + AbilityDelegatorRegistry::RegisterInstance(delegator, args, runtime->GetLanguage()); + delegator->SetApiTargetVersion(targetVersion); + delegator->Prepare(); + } } else { // FA model TAG_LOGD(AAFwkTag::APPKIT, "FA model"); AbilityRuntime::Runtime::Options options; @@ -2380,7 +2511,7 @@ bool MainThread::PrepareAbilityDelegator(const std::shared_ptr & } auto delegator = std::make_shared( application_->GetAppContext(), std::move(testRunner), record->observer); - AbilityDelegatorRegistry::RegisterInstance(delegator, args); + AbilityDelegatorRegistry::RegisterInstance(delegator, args, AbilityRuntime::Runtime::Language::JS); delegator->SetApiTargetVersion(targetVersion); delegator->Prepare(); } @@ -2441,7 +2572,11 @@ void MainThread::HandleLaunchAbility(const std::shared_ptr & TAG_LOGE(AAFwkTag::APPKIT, "null application"); return; } - auto& runtime = application->GetRuntime(); + auto &runtime = application->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); + if (runtime == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); + return; + } appThread->UpdateRuntimeModuleChecker(runtime); #ifdef APP_ABILITY_USE_TWO_RUNNER AbilityThread::AbilityThreadMain(application, abilityRecord, stageContext); @@ -2468,7 +2603,11 @@ void MainThread::HandleLaunchAbility(const std::shared_ptr & return; } SetProcessExtensionType(abilityRecord); - auto& runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); + if (runtime == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); + return; + } UpdateRuntimeModuleChecker(runtime); #ifdef APP_ABILITY_USE_TWO_RUNNER AbilityThread::AbilityThreadMain(application_, abilityRecord, stageContext); @@ -2831,7 +2970,7 @@ void MainThread::HandleDumpHeapPrepare() TAG_LOGE(AAFwkTag::APPKIT, "null app"); return; } - auto &runtime = app->GetRuntime(); + auto &runtime = app->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; @@ -2851,7 +2990,7 @@ void MainThread::HandleDumpHeap(bool isPrivate) TAG_LOGE(AAFwkTag::APPKIT, "null app"); return; } - auto &runtime = app->GetRuntime(); + auto &runtime = app->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; @@ -2904,11 +3043,11 @@ void MainThread::DestroyHeapProfiler() auto task = [] { auto app = applicationForDump_.lock(); - if (app == nullptr || app->GetRuntime() == nullptr) { + if (app == nullptr || app->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0) == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; } - app->GetRuntime()->DestroyHeapProfiler(); + app->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0)->DestroyHeapProfiler(); }; mainHandler_->PostTask(task, "MainThread:DestroyHeapProfiler"); } @@ -2923,11 +3062,11 @@ void MainThread::ForceFullGC() auto task = [] { auto app = applicationForDump_.lock(); - if (app == nullptr || app->GetRuntime() == nullptr) { + if (app == nullptr || app->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0) == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; } - app->GetRuntime()->ForceFullGC(); + app->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0)->ForceFullGC(); }; mainHandler_->PostTask(task, "MainThread:ForceFullGC"); } @@ -3655,7 +3794,7 @@ int32_t MainThread::ChangeAppGcState(int32_t state, uint64_t tid) TAG_LOGE(AAFwkTag::APPKIT, "null application_"); return ERR_INVALID_VALUE; } - auto &runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return ERR_INVALID_VALUE; @@ -3707,7 +3846,7 @@ int32_t MainThread::OnAttachLocalDebug(bool isDebugFromLocal) TAG_LOGE(AAFwkTag::APPKIT, "null application_"); return ERR_INVALID_VALUE; } - auto &runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return ERR_INVALID_VALUE; @@ -3929,7 +4068,7 @@ void MainThread::HandleCacheProcess() // force gc if (application_ != nullptr) { - auto &runtime = application_->GetRuntime(); + auto &runtime = application_->GetRuntime(AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; @@ -3938,6 +4077,38 @@ void MainThread::HandleCacheProcess() } } +void MainThread::AddRuntimeLang(ApplicationInfo& appInfo, AbilityRuntime::Runtime::Options& options) +{ + if (appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2) { + options.langs.emplace(AbilityRuntime::Runtime::Language::ETS, true); + } else if (appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_HYBRID) { + options.langs.emplace(AbilityRuntime::Runtime::Language::ETS, true); + } else { + options.langs.emplace(AbilityRuntime::Runtime::Language::JS, true); + } +} + +bool MainThread::IsNeedEtsInit(const ApplicationInfo& appInfo) +{ + return appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2 || + appInfo.codeLanguage == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_HYBRID; +} + +const std::unique_ptr& MainThread::GetVerOneRuntime(const ApplicationInfo& appInfo, + const std::vector>& runtimes) +{ + if (appInfo.codeLanguage != AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0) { + return RUNTIME_NULL; + } + for (auto& runtime : runtimes) { + if (runtime->GetLanguage() == AbilityRuntime::Runtime::Language::JS || + runtime->GetLanguage() == AbilityRuntime::Runtime::Language::CJ) { + return runtime; + } + } + return RUNTIME_NULL; +} + void MainThread::HandleConfigByPlugin(Configuration &config, BundleInfo &bundleInfo) { if (PC_LIBRARY_PATH == nullptr) { diff --git a/frameworks/native/appkit/app/ohos_application.cpp b/frameworks/native/appkit/app/ohos_application.cpp index 45831ff8001..7f9fba228f3 100644 --- a/frameworks/native/appkit/app/ohos_application.cpp +++ b/frameworks/native/appkit/app/ohos_application.cpp @@ -37,6 +37,7 @@ #include "iservice_registry.h" #include "runtime.h" #include "js_runtime.h" +#include "ets_runtime.h" #include "startup_manager.h" #include "system_ability_definition.h" #include "syspara/parameter.h" @@ -51,6 +52,7 @@ namespace OHOS { namespace AppExecFwk { namespace { constexpr const char* PERSIST_DARKMODE_KEY = "persist.ace.darkmode"; + std::unique_ptr RUNTIME_NULL = nullptr; } REGISTER_APPLICATION(OHOSApplication, OHOSApplication) constexpr int32_t APP_ENVIRONMENT_OVERWRITE = 1; @@ -77,11 +79,14 @@ void OHOSApplication::OnForeground() abilityRuntimeContext_->NotifyApplicationForeground(); } - if (runtime_ == nullptr) { - TAG_LOGD(AAFwkTag::APPKIT, "NotifyApplicationState, runtime_ is nullptr"); - return; + for (const auto& runtime : runtimes_) { + if (runtime == nullptr) { + TAG_LOGD(AAFwkTag::APPKIT, "NotifyApplicationState, runtime is nullptr"); + continue; + } + runtime->NotifyApplicationState(false); } - runtime_->NotifyApplicationState(false); + TAG_LOGD(AAFwkTag::APPKIT, "NotifyApplicationState::OnForeground end"); } @@ -97,11 +102,13 @@ void OHOSApplication::OnBackground() abilityRuntimeContext_->NotifyApplicationBackground(); } - if (runtime_ == nullptr) { - TAG_LOGD(AAFwkTag::APPKIT, "runtime_ is nullptr"); - return; + for (const auto& runtime : runtimes_) { + if (runtime == nullptr) { + TAG_LOGD(AAFwkTag::APPKIT, "runtime is nullptr"); + continue; + } + runtime->NotifyApplicationState(true); } - runtime_->NotifyApplicationState(true); } void OHOSApplication::DumpApplication() @@ -149,18 +156,18 @@ void OHOSApplication::DumpApplication() } /** - * @brief Set Runtime + * @brief Add Runtime * * @param runtime Runtime instance. */ -void OHOSApplication::SetRuntime(std::unique_ptr&& runtime) +void OHOSApplication::AddRuntime(std::unique_ptr&& runtime) { TAG_LOGD(AAFwkTag::APPKIT, "begin"); if (runtime == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null runtime"); return; } - runtime_ = std::move(runtime); + runtimes_.push_back(std::move(runtime)); } /** @@ -369,6 +376,25 @@ void OHOSApplication::SetAppEnv(const std::vector& appEnvironmen return; } +void OHOSApplication::PreloadHybridModule(const HapModuleInfo &hapModuleInfo) const +{ + if (hapModuleInfo.codeLanguage != Constants::CODE_LANGUAGE_HYBRID) { + TAG_LOGD(AAFwkTag::APPKIT, "not hybrid runtime"); + return; + } + for (const auto& runtime : runtimes_) { + bool isEsmode = hapModuleInfo.compileMode == CompileMode::ES_MODULE; + bool useCommonTrunk = false; + for (const auto& md : hapModuleInfo.metadata) { + if (md.name == "USE_COMMON_CHUNK") { + useCommonTrunk = md.value == "true"; + break; + } + } + runtime->PreloadModule(hapModuleInfo.moduleName, hapModuleInfo.hapPath, isEsmode, useCommonTrunk); + } +} + std::shared_ptr OHOSApplication::AddAbilityStage( const std::shared_ptr &abilityRecord, const std::function &)> &callback, bool &isAsyncCallback) @@ -413,8 +439,10 @@ std::shared_ptr OHOSApplication::AddAbilityStage( TAG_LOGE(AAFwkTag::APPKIT, "null hapModuleInfo"); return nullptr; } - if (runtime_ && (runtime_->GetLanguage() == AbilityRuntime::Runtime::Language::JS)) { - static_cast(*runtime_).SetPkgContextInfoJson( + PreloadHybridModule(*hapModuleInfo); + auto& runtime = GetRuntime(abilityInfo->codeLanguage); + if (runtime && (runtime->GetLanguage() == AbilityRuntime::Runtime::Language::JS)) { + static_cast(*runtime).SetPkgContextInfoJson( hapModuleInfo->moduleName, hapModuleInfo->hapPath, hapModuleInfo->packageName); } SetAppEnv(hapModuleInfo->appEnvironments); @@ -425,7 +453,8 @@ std::shared_ptr OHOSApplication::AddAbilityStage( stageContext->SetResourceManager(rm); } - abilityStage = AbilityRuntime::AbilityStage::Create(runtime_, *hapModuleInfo); + auto& runtimeStage = GetRuntime(hapModuleInfo->codeLanguage); + abilityStage = AbilityRuntime::AbilityStage::Create(runtimeStage, *hapModuleInfo); if (abilityStage == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null abilityStage"); return nullptr; @@ -608,8 +637,8 @@ bool OHOSApplication::AddAbilityStage( return false; } - if (runtime_ == nullptr) { - TAG_LOGE(AAFwkTag::APPKIT, "null runtime_"); + if (runtimes_.empty()) { + TAG_LOGE(AAFwkTag::APPKIT, "runtimes empty"); return false; } @@ -633,7 +662,8 @@ bool OHOSApplication::AddAbilityStage( stageContext->SetResourceManager(rm); } - auto abilityStage = AbilityRuntime::AbilityStage::Create(runtime_, *moduleInfo); + auto& runtime = GetRuntime(moduleInfo->codeLanguage); + auto abilityStage = AbilityRuntime::AbilityStage::Create(runtime, *moduleInfo); if (abilityStage == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null abilityStage"); return false; @@ -688,9 +718,9 @@ std::shared_ptr OHOSApplication::GetAppContext() const return abilityRuntimeContext_; } -const std::unique_ptr& OHOSApplication::GetRuntime() const +const std::vector>& OHOSApplication::GetRuntime() const { - return runtime_; + return runtimes_; } void OHOSApplication::SetConfiguration(const Configuration &config) @@ -815,32 +845,60 @@ void OHOSApplication::SetExtensionTypeMap(std::map map) bool OHOSApplication::NotifyLoadRepairPatch(const std::string &hqfFile, const std::string &hapPath) { - if (runtime_ == nullptr) { - TAG_LOGD(AAFwkTag::APPKIT, "null runtime"); + if (runtimes_.empty()) { + TAG_LOGD(AAFwkTag::APPKIT, "runtimes empty"); return true; } - return runtime_->LoadRepairPatch(hqfFile, hapPath); + for (const auto& runtime : runtimes_) { + if (runtime == nullptr) { + TAG_LOGD(AAFwkTag::APPKIT, "null runtime"); + continue; + } + if (!runtime->LoadRepairPatch(hqfFile, hapPath)) { + return false; + } + } + return true; } bool OHOSApplication::NotifyHotReloadPage() { - if (runtime_ == nullptr) { - TAG_LOGD(AAFwkTag::APPKIT, "null runtime"); + if (runtimes_.empty()) { + TAG_LOGD(AAFwkTag::APPKIT, "runtimes empty"); return true; } - return runtime_->NotifyHotReloadPage(); + for (const auto& runtime : runtimes_) { + if (runtime == nullptr) { + TAG_LOGD(AAFwkTag::APPKIT, "null runtime"); + continue; + } + if (!runtime->NotifyHotReloadPage()) { + return false; + } + } + return true; } bool OHOSApplication::NotifyUnLoadRepairPatch(const std::string &hqfFile) { - if (runtime_ == nullptr) { - TAG_LOGD(AAFwkTag::APPKIT, "null runtime"); + if (runtimes_.empty()) { + TAG_LOGD(AAFwkTag::APPKIT, "runtimes empty"); return true; } - return runtime_->UnLoadRepairPatch(hqfFile); + for (const auto& runtime : runtimes_) { + if (runtime == nullptr) { + TAG_LOGD(AAFwkTag::APPKIT, "null runtime"); + continue; + } + if (!runtime->UnLoadRepairPatch(hqfFile)) { + return false; + } + } + + return true; } void OHOSApplication::CleanAppTempData(bool isLastProcess) @@ -1080,5 +1138,35 @@ bool OHOSApplication::GetDisplayConfig(uint64_t displayId, float &density, std:: return true; } #endif + +const std::unique_ptr& OHOSApplication::GetRuntime(const std::string& language) const +{ + for (auto& runtime : runtimes_) { + if (runtime->GetLanguage() == ConvertLangToCode(language)) { + return runtime; + } + } + return RUNTIME_NULL; +} + +void OHOSApplication::SetCJApplication(bool isCJApplication) +{ + isCJApplication_ = isCJApplication; +} + +AbilityRuntime::Runtime::Language OHOSApplication::ConvertLangToCode(const std::string& language) const +{ + if (language == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0) { + if (isCJApplication_) { + return AbilityRuntime::Runtime::Language::CJ; + } else { + return AbilityRuntime::Runtime::Language::JS; + } + } else if (language == AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_2) { + return AbilityRuntime::Runtime::Language::ETS; + } else { + return AbilityRuntime::Runtime::Language::UNKNOWN; + } +} } // namespace AppExecFwk } // namespace OHOS diff --git a/frameworks/native/runtime/cj_runtime.cpp b/frameworks/native/runtime/cj_runtime.cpp index ecf1697834d..ef9e96be62f 100644 --- a/frameworks/native/runtime/cj_runtime.cpp +++ b/frameworks/native/runtime/cj_runtime.cpp @@ -118,16 +118,6 @@ bool CJRuntime::Initialize(const Options& options) return true; } -void CJRuntime::RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo& uncaughtExceptionInfo) -{ - auto cjEnv = OHOS::CJEnv::LoadInstance(); - if (cjEnv == nullptr) { - TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv"); - return; - } - cjEnv->registerCJUncaughtExceptionHandler(uncaughtExceptionInfo); -} - bool CJRuntime::IsCJAbility(const std::string& info) { // in cj application, the srcEntry format should be packageName.AbilityClassName. @@ -368,4 +358,14 @@ void CJRuntime::ForceFullGC(uint32_t tid) return; } cjEnv->forceFullGC(); +} + +void CJRuntime::RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) +{ + auto cjEnv = OHOS::CJEnv::LoadInstance(); + if (cjEnv == nullptr) { + TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv"); + return; + } + cjEnv->registerCJUncaughtExceptionHandler(*static_cast(uncaughtExceptionInfo)); } \ No newline at end of file diff --git a/frameworks/native/runtime/ets_runtime.cpp b/frameworks/native/runtime/ets_runtime.cpp new file mode 100644 index 00000000000..6142154efb7 --- /dev/null +++ b/frameworks/native/runtime/ets_runtime.cpp @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2025 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 "ets_runtime.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "accesstoken_kit.h" +#include "config_policy_utils.h" +#include "connect_server_manager.h" +#include "constants.h" +#include "extract_resource_manager.h" +#include "extractor.h" +#include "file_ex.h" +#include "file_mapper.h" +#include "file_path_utils.h" +#include "hdc_register.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "module_checker_delegate.h" +#include "parameters.h" +#include "source_map.h" +#include "source_map_operator.h" +#include "ets_environment.h" +#include "syscap_ts.h" +#include "system_ability_definition.h" + +#ifdef SUPPORT_SCREEN +#include "ace_forward_compatibility.h" +#include "declarative_module_preloader.h" +#include "hot_reloader.h" +#endif //SUPPORT_SCREEN + +using namespace OHOS::AbilityBase; +using Extractor = OHOS::AbilityBase::Extractor; + +namespace OHOS { +namespace AbilityRuntime { +namespace { +#ifdef APP_USE_ARM64 +const std::string SANDBOX_LIB_PATH = "/system/lib64"; +const std::string ETS_RT_PATH = SANDBOX_LIB_PATH; +const std::string ETS_SYSLIB_PATH = + "/system/lib64:/system/lib64/platformsdk:/system/lib64/module:/system/lib64/ndk"; +#else +const std::string SANDBOX_LIB_PATH = "/system/lib"; +const std::string ETS_RT_PATH = SANDBOX_LIB_PATH; +const std::string ETS_SYSLIB_PATH = + "/system/lib:/system/lib/platformsdk:/system/lib/module:/system/lib/ndk"; +#endif +constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/"; +constexpr char SANDBOX_ARK_CACHE_PATH[] = "/data/storage/ark-cache/"; +constexpr char MERGE_ABC_PATH[] = "/ets/modules_static.abc"; +constexpr char ENTRY_PATH_MAP_FILE[] = "/system/framework/entrypath.json"; // will deprecated +constexpr char ENTRY_PATH_MAP_KEY[] = "entryPath"; // will deprecated +constexpr char DEFAULT_ENTRY_ABILITY_CLASS[] = "entry/src/main/ets/entryability/EntryAbility/EntryAbility"; +constexpr int32_t DOT_START_LEN = 2; + +class EntryPathManager { +public: + static EntryPathManager &GetInstance() + { + static EntryPathManager instance; + return instance; + } + + bool Init() + { + std::ifstream inFile; + inFile.open(ENTRY_PATH_MAP_FILE, std::ios::in); + if (!inFile.is_open()) { + TAG_LOGD(AAFwkTag::ETSRUNTIME, "no entrypath file"); + return false; + } + nlohmann::json filePathsJson; + inFile >> filePathsJson; + if (filePathsJson.is_discarded()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "json discarded error"); + inFile.close(); + return false; + } + + if (filePathsJson.is_null() || filePathsJson.empty()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "invalid json"); + inFile.close(); + return false; + } + + if (!filePathsJson.contains(ENTRY_PATH_MAP_KEY)) { + TAG_LOGD(AAFwkTag::ETSRUNTIME, "no entrypath key"); + return false; + } + const auto &entryPathMap = filePathsJson[ENTRY_PATH_MAP_KEY]; + if (!entryPathMap.is_object()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "entrypath is not object"); + return false; + } + + for (const auto &entryPath : entryPathMap.items()) { + std::string key = entryPath.key(); + if (!entryPath.value().is_string()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "val is not string, key: %{public}s", key.c_str()); + continue; + } + std::string val = entryPath.value(); + TAG_LOGD(AAFwkTag::ETSRUNTIME, "key: %{public}s, value: %{public}s", key.c_str(), val.c_str()); + entryPathMap_.emplace(key, val); + } + inFile.close(); + return true; + } + + std::string GetEntryPath(const std::string &srcEntry) + { + auto const &iter = entryPathMap_.find(srcEntry); + if (iter == entryPathMap_.end()) { + if (StartsWithDotSlash(srcEntry)) { + TAG_LOGD(AAFwkTag::ETSRUNTIME, "not found srcEntry: %{public}s", srcEntry.c_str()); + return DEFAULT_ENTRY_ABILITY_CLASS; + } + TAG_LOGD(AAFwkTag::ETSRUNTIME, "srcEntry as class: %{public}s", srcEntry.c_str()); + return HandleOhmUrlSrcEntry(srcEntry); + } + TAG_LOGD(AAFwkTag::ETSRUNTIME, "found srcEntry: %{public}s, output: %{public}s", + srcEntry.c_str(), iter->second.c_str()); + return iter->second; + } + +private: + EntryPathManager() = default; + + ~EntryPathManager() = default; + + static bool StartsWithDotSlash(const std::string &str) + { + if (str.length() < DOT_START_LEN) { + return false; + } + std::string prefix = str.substr(0, DOT_START_LEN); + return prefix == "./"; + } + + static std::string HandleOhmUrlSrcEntry(const std::string &srcEntry) + { + size_t lastSlashPos = srcEntry.rfind('/'); + if (lastSlashPos == std::string::npos) { + std::string fileName = srcEntry; + // If there is no slash, the entire string is processed directly. + HandleOhmUrlFileName(fileName); + return fileName; + } + std::string base = srcEntry.substr(0, lastSlashPos + 1); + std::string fileName = srcEntry.substr(lastSlashPos + 1); + HandleOhmUrlFileName(fileName); + return base + fileName; + } + + static void HandleOhmUrlFileName(std::string &fileName) + { + size_t colonPos = fileName.rfind(':'); + if (colonPos != std::string::npos) { + // : => / + fileName.replace(colonPos, 1, "/"); + } else { + // => / + fileName = fileName + "/" + fileName; + } + } + + std::map entryPathMap_{}; +}; +} // namespace + +AppLibPathVec ETSRuntime::appLibPaths_; + +std::unique_ptr ETSRuntime::Create(const Options& options, Runtime* jsRuntime) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Create called"); + if (jsRuntime == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null jsRuntime"); + return std::unique_ptr(); + } + std::unique_ptr 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(preloadedInstance.release())); + } else { + instance = std::make_unique(); + } + } else { + instance = std::make_unique(); + } + + if (!instance->Initialize(options, jsRuntime)) { + return std::unique_ptr(); + } + EntryPathManager::GetInstance().Init(); + + return instance; +} + +void ETSRuntime::SetAppLibPath(const AppLibPathMap& appLibPaths) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "SetAppLibPath called"); + EtsEnv::ETSEnvironment::InitETSSDKNS(ETS_RT_PATH); + EtsEnv::ETSEnvironment::InitETSSysNS(ETS_SYSLIB_PATH); +} + +bool ETSRuntime::Initialize(const Options& options, Runtime* jsRuntime) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Initialize called"); + if (options.lang != GetLanguage()) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "language mismatch"); + return false; + } + + if (!CreateEtsEnv(options, jsRuntime)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Create etsEnv failed"); + return false; + } + + apiTargetVersion_ = options.apiTargetVersion; + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Initialize: %{public}d", apiTargetVersion_); + + return true; +} + +void ETSRuntime::RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) +{ + if (etsEnv_ == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null etsEnv_"); + return; + } + + if (uncaughtExceptionInfo == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null uncaughtExceptionInfo"); + return; + } + + auto handle = static_cast(uncaughtExceptionInfo); + if (handle != nullptr) { + etsEnv_->RegisterUncaughtExceptionHandler(*handle); + } +} + +ETSRuntime::~ETSRuntime() +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "~ETSRuntime called"); + Deinitialize(); +} + +void ETSRuntime::Deinitialize() +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Deinitialize called"); +} + +bool ETSRuntime::CreateEtsEnv(const Options& options, Runtime* jsRuntime) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "CreateEtsEnv called"); + etsEnv_ = std::make_shared(); + std::vector aniOptions; + std::string aotFileString = ""; + if (!options.arkNativeFilePath.empty()) { + std::string aotFilePath = SANDBOX_ARK_CACHE_PATH + options.arkNativeFilePath + options.moduleName + ".an"; + aotFileString = "--ext:--aot-file=" + aotFilePath; + aniOptions.push_back(ani_option{aotFileString.c_str(), nullptr}); + TAG_LOGI(AAFwkTag::ETSRUNTIME, "aotFileString: %{public}s", aotFileString.c_str()); + aniOptions.push_back(ani_option{"--ext:--enable-an", nullptr}); + } + + if (!etsEnv_->Initialize(static_cast(jsRuntime)->GetNapiEnv(), aniOptions)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Init EtsEnv failed"); + return false; + } + + return true; +} + +ani_env* ETSRuntime::GetAniEnv() +{ + if (etsEnv_ == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null etsEnv_"); + return nullptr; + } + return etsEnv_->GetAniEnv(); +} + +void ETSRuntime::PreloadModule(const std::string& moduleName, const std::string& hapPath, + bool isEsMode, bool useCommonTrunk) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "moduleName: %{public}s", moduleName.c_str()); + ani_env* aniEnv = GetAniEnv(); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "GetAniEnv failed"); + return; + } + + ani_class cls = nullptr; + ani_object object = nullptr; + if (!LoadAbcLinker(aniEnv, moduleName, cls, object)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "LoadAbcLinker failed"); + return; + } + return; +} + +std::unique_ptr ETSRuntime::LoadModule(const std::string& moduleName, + const std::string& modulePath, const std::string& hapPath, bool esmodule, bool useCommonChunk, + const std::string& srcEntrance) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Load module(%{public}s, %{public}s, %{public}s, %{public}s)", + moduleName.c_str(), modulePath.c_str(), hapPath.c_str(), srcEntrance.c_str()); + + std::string path = moduleName; + auto pos = path.find("::"); + if (pos != std::string::npos) { + path.erase(pos, path.size() - pos); + moduleName_ = path; + } + TAG_LOGD(AAFwkTag::ETSRUNTIME, "moduleName_(%{public}s, path %{public}s", + moduleName_.c_str(), path.c_str()); + + std::string fileName; + if (!hapPath.empty()) { + fileName.append(codePath_).append(Constants::FILE_SEPARATOR).append(modulePath); + std::regex pattern(std::string(Constants::FILE_DOT) + std::string(Constants::FILE_SEPARATOR)); + fileName = std::regex_replace(fileName, pattern, ""); + } else { + if (!MakeFilePath(codePath_, modulePath, fileName)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "make module file path: %{public}s failed", modulePath.c_str()); + return nullptr; + } + } + std::unique_ptr etsNativeReference = LoadEtsModule(moduleName, fileName, hapPath, srcEntrance); + return etsNativeReference; +} + +bool ETSRuntime::LoadAbcLinker(ani_env* env, const std::string& moduleName, ani_class& abcCls, ani_object& abcObj) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null env"); + return false; + } + ani_class stringCls = nullptr; + if (env->FindClass("Lstd/core/String;", &stringCls) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "FindClass Lstd/core/String Failed"); + return false; + } + std::string modulePath = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_PATH; + ani_string aniStr; + if (env->String_NewUTF8(modulePath.c_str(), modulePath.size(), &aniStr) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "String_NewUTF8 modulePath Failed"); + return false; + } + ani_ref undefinedRef; + if (env->GetUndefined(&undefinedRef) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "GetUndefined failed"); + return false; + } + ani_array_ref refArray; + if (env->Array_New_Ref(stringCls, 1, undefinedRef, &refArray) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Array_New_Ref Failed"); + return false; + } + if (env->Array_Set_Ref(refArray, 0, aniStr) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Array_Set_Ref Failed"); + return false; + } + if (env->FindClass("Lstd/core/AbcRuntimeLinker;", &abcCls) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "FindClass AbcRuntimeLinker failed"); + return false; + } + ani_method method = nullptr; + if (env->Class_FindMethod(abcCls, "", "Lstd/core/RuntimeLinker;[Lstd/core/String;:V", &method) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Class_FindMethod ctor failed"); + return false; + } + env->ResetError(); + if (env->Object_New(abcCls, method, &abcObj, undefinedRef, refArray) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Object_New AbcRuntimeLinker failed"); + HandleUncaughtError(); + return false; + } + return true; +} + +std::unique_ptr ETSRuntime::LoadEtsModule(const std::string& moduleName, + const std::string& fileName, const std::string& hapPath, const std::string& srcEntrance) +{ + auto etsNativeReference = std::make_unique(); + ani_env* aniEnv = GetAniEnv(); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "GetAniEnv failed"); + return std::make_unique(); + } + ani_class cls = nullptr; + ani_object object = nullptr; + if (!LoadAbcLinker(aniEnv, moduleName_, cls, object)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "LoadAbcLinker failed"); + return std::make_unique(); + } + ani_method loadClassMethod = nullptr; + if (aniEnv->Class_FindMethod(cls, "loadClass", "Lstd/core/String;Z:Lstd/core/Class;", &loadClassMethod) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Class_FindMethod loadClass failed"); + return std::make_unique(); + } + std::string entryPath = EntryPathManager::GetInstance().GetEntryPath(srcEntrance); + ani_string entryClassStr; + aniEnv->String_NewUTF8(entryPath.c_str(), entryPath.length(), &entryClassStr); + ani_class entryClass = nullptr; + ani_ref entryClassRef = nullptr; + if (aniEnv->Object_CallMethod_Ref(object, loadClassMethod, &entryClassRef, entryClassStr, false) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Object_CallMethod_Ref loadClassMethod failed"); + return std::make_unique(); + } else { + entryClass = static_cast(entryClassRef); + } + ani_method entryMethod = nullptr; + if (aniEnv->Class_FindMethod(entryClass, "", ":V", &entryMethod) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Class_FindMethod ctor failed"); + return std::make_unique(); + } + ani_object entryObject = nullptr; + if (aniEnv->Object_New(entryClass, entryMethod, &entryObject) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Object_New AbcRuntimeLinker failed"); + return std::make_unique(); + } + ani_ref entryObjectRef = nullptr; + if (aniEnv->GlobalReference_Create(entryObject, &entryObjectRef) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "GlobalReference_Create failed"); + return std::make_unique(); + } + etsNativeReference->aniCls = entryClass; + etsNativeReference->aniObj = entryObject; + etsNativeReference->aniRef = entryObjectRef; + return etsNativeReference; +} + +void ETSRuntime::HandleUncaughtError() +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "HandleUncaughtError called"); + if (etsEnv_ == nullptr) { + return; + } + etsEnv_->HandleUncaughtError(); +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/runtime/js_runtime.cpp b/frameworks/native/runtime/js_runtime.cpp index 4b04f031c12..c318ad34b7a 100644 --- a/frameworks/native/runtime/js_runtime.cpp +++ b/frameworks/native/runtime/js_runtime.cpp @@ -1765,5 +1765,11 @@ void JsRuntime::StartLocalDebugMode(bool isDebugFromLocal) debugOption_.isDebugFromLocal = isDebugFromLocal; StartDebugMode(debugOption_); } +void JsRuntime::RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) +{ + HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__); + CHECK_POINTER(jsEnv_); + jsEnv_->RegisterUncaughtExceptionHandler(*static_cast(uncaughtExceptionInfo)); +} } // namespace AbilityRuntime } // namespace OHOS diff --git a/frameworks/native/runtime/runtime.cpp b/frameworks/native/runtime/runtime.cpp index 26362dd0dbb..d995917a8de 100644 --- a/frameworks/native/runtime/runtime.cpp +++ b/frameworks/native/runtime/runtime.cpp @@ -19,6 +19,7 @@ #include "cj_runtime.h" #endif #include "js_runtime.h" +#include "ets_runtime.h" namespace OHOS { namespace AbilityRuntime { @@ -26,8 +27,43 @@ namespace { std::unique_ptr g_preloadedInstance; } -std::unique_ptr Runtime::Create(const Runtime::Options& options) +std::vector> Runtime::CreateRuntimes(Runtime::Options& options) { + std::vector> runtimes; + for (auto lang : options.langs) { + switch (lang.first) { + case Runtime::Language::JS: + options.lang = Runtime::Language::JS; + runtimes.push_back(JsRuntime::Create(options)); + break; +#ifdef CJ_FRONTEND + case Runtime::Language::CJ: + options.lang = Runtime::Language::CJ; + runtimes.push_back(CJRuntime::Create(options)); + break; +#endif + case Runtime::Language::ETS: + options.lang = Runtime::Language::JS; + runtimes.push_back(JsRuntime::Create(options)); + options.lang = Runtime::Language::ETS; + runtimes.push_back(ETSRuntime::Create(options, &static_cast(*runtimes[0]))); + break; + default: + runtimes.push_back(std::unique_ptr()); + break; + } + } + return runtimes; +} + +std::unique_ptr Runtime::Create(Runtime::Options& options) +{ + std::unique_ptr jsRuntime; + if (options.lang == Runtime::Language::ETS) { + options.lang = Runtime::Language::JS; + jsRuntime = JsRuntime::Create(options); + options.lang = Runtime::Language::ETS; + } switch (options.lang) { case Runtime::Language::JS: return JsRuntime::Create(options); @@ -35,6 +71,8 @@ std::unique_ptr Runtime::Create(const Runtime::Options& options) case Runtime::Language::CJ: return CJRuntime::Create(options); #endif + case Runtime::Language::ETS: + return ETSRuntime::Create(options, jsRuntime.get()); default: return std::unique_ptr(); } diff --git a/frameworks/simulator/ability_simulator/src/js_runtime.cpp b/frameworks/simulator/ability_simulator/src/js_runtime.cpp index 7e173d8a07c..07449b13df9 100644 --- a/frameworks/simulator/ability_simulator/src/js_runtime.cpp +++ b/frameworks/simulator/ability_simulator/src/js_runtime.cpp @@ -158,5 +158,9 @@ std::unique_ptr JsRuntime::LoadSystemModuleByEngine( napi_create_reference(env, instanceValue, 1, &result); return std::unique_ptr(reinterpret_cast(result)); } + +void JsRuntime::RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) +{ +} } // namespace AbilityRuntime } // namespace OHOS diff --git a/interfaces/inner_api/runtime/BUILD.gn b/interfaces/inner_api/runtime/BUILD.gn index 92cb0dda4fa..78bb133df7c 100644 --- a/interfaces/inner_api/runtime/BUILD.gn +++ b/interfaces/inner_api/runtime/BUILD.gn @@ -40,6 +40,7 @@ config("runtime_public_config") { visibility += [ "${ability_runtime_napi_path}/inner/napi_common:napi_common" ] include_dirs = [ "${ability_runtime_path}/interfaces/kits/native/ability/native/ability_business_error", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", "include", ] } @@ -54,6 +55,7 @@ ohos_shared_library("runtime") { include_dirs = [ "${ability_runtime_path}/services/abilitymgr/include", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_bundle_manager_helper", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", "${ability_runtime_utils_path}/global/constant", ] @@ -75,6 +77,7 @@ ohos_shared_library("runtime") { "${ability_runtime_native_path}/runtime/ohos_js_environment_impl.cpp", "${ability_runtime_native_path}/runtime/ohos_loop_handler.cpp", "${ability_runtime_native_path}/runtime/runtime.cpp", + "${ability_runtime_native_path}/runtime/ets_runtime.cpp", ] configs = [ ":runtime_config" ] @@ -90,6 +93,7 @@ ohos_shared_library("runtime") { "${ability_runtime_native_path}/ability/native:ability_business_error", "${ability_runtime_native_path}/appkit:appkit_manager_helper", "${ability_runtime_path}/js_environment/frameworks/js_environment:js_environment", + "${ability_runtime_path}/ets_environment/frameworks/ets_environment:ets_environment", "${ability_runtime_services_path}/common:app_util", "${ability_runtime_services_path}/common:record_cost_time_util", ] @@ -121,6 +125,7 @@ ohos_shared_library("runtime") { "jsoncpp:jsoncpp", "napi:ace_napi", "resource_management:global_resmgr", + "runtime_core:ani", "samgr:samgr_proxy", "zlib:shared_libz", "faultloggerd:libfaultloggerd", diff --git a/interfaces/inner_api/runtime/include/cj_runtime.h b/interfaces/inner_api/runtime/include/cj_runtime.h index 0d406dc6f33..8ef12110238 100644 --- a/interfaces/inner_api/runtime/include/cj_runtime.h +++ b/interfaces/inner_api/runtime/include/cj_runtime.h @@ -55,6 +55,8 @@ public: 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 {} bool LoadRepairPatch(const std::string& patchFile, const std::string& baseFile) override { return false; } bool NotifyHotReloadPage() override { return false; } @@ -72,9 +74,8 @@ public: void DumpCpuProfile() override {}; void AllowCrossThreadExecution() override {}; void GetHeapPrepare() override {}; - void RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo& uncaughtExceptionInfo); static bool RegisterCangjieCallback(); - + void RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) override; private: bool StartDebugger(); bool LoadCJAppLibrary(const AppLibPathVec& appLibPaths); diff --git a/interfaces/inner_api/runtime/include/ets_runtime.h b/interfaces/inner_api/runtime/include/ets_runtime.h new file mode 100644 index 00000000000..0ff9e3859f3 --- /dev/null +++ b/interfaces/inner_api/runtime/include/ets_runtime.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025 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 OHOS_ABILITY_RUNTIME_ETS_RUNTIME_H +#define OHOS_ABILITY_RUNTIME_ETS_RUNTIME_H + +#include +#include +#include +#include +#include +#include +#include + +#include "runtime.h" +#include "js_runtime.h" +#include "ets_exception_callback.h" +#include "ani.h" + +using AppLibPathMap = std::map>; +using AppLibPathVec = std::vector; + +namespace OHOS { +namespace EtsEnv { +class ETSEnvironment; +} // namespace EtsEnv + +namespace AbilityRuntime { + +struct ETSNativeReference { + ani_class aniCls = nullptr; + ani_object aniObj = nullptr; + ani_ref aniRef = nullptr; +}; + +class ETSRuntime : public Runtime { +public: + static std::unique_ptr Create(const Options& options, Runtime* jsRuntime); + static void SetAppLibPath(const AppLibPathMap& appLibPaths); + ~ETSRuntime() override; + Language GetLanguage() const override + { + return Language::ETS; + } + + void StartDebugMode(const DebugOption debugOption) override {} + void DumpHeapSnapshot(bool isPrivate) override {} + 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 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 {} + 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; } + void RegisterQuickFixQueryFunc(const std::map& moduleAndPath) override {}; + void StartProfiler(const DebugOption debugOption) override {}; + void SetModuleLoadChecker(const std::shared_ptr moduleCheckerDelegate) const override {} + void SetDeviceDisconnectCallback(const std::function &cb) override {}; + void DestroyHeapProfiler() override {}; + void ForceFullGC() override {}; + void ForceFullGC(uint32_t tid) override {}; + void DumpHeapSnapshot(uint32_t tid, bool isFullGC, bool isBinary = false) override {}; + void DumpCpuProfile() override {}; + void AllowCrossThreadExecution() override {}; + void GetHeapPrepare() override {}; + void RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) override; + ani_env* GetAniEnv(); + std::unique_ptr LoadModule(const std::string& moduleName, const std::string& modulePath, + const std::string& hapPath, bool esmodule, bool useCommonChunk, const std::string& srcEntrance); + std::unique_ptr LoadEtsModule(const std::string& moduleName, const std::string& fileName, + const std::string& hapPath, const std::string& srcEntrance); + void HandleUncaughtError(); +private: + bool Initialize(const Options& options, Runtime* jsRuntime); + void Deinitialize(); + bool CreateEtsEnv(const Options& options, Runtime* jsRuntime); + bool LoadAbcLinker(ani_env* env, const std::string& moduleName, ani_class& abcCls, ani_object& abcObj); + std::shared_ptr etsEnv_; + int32_t apiTargetVersion_ = 0; + std::string codePath_; + static AppLibPathVec appLibPaths_; + std::string moduleName_; +}; +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_ETS_RUNTIME_H diff --git a/interfaces/inner_api/runtime/include/js_runtime.h b/interfaces/inner_api/runtime/include/js_runtime.h index d573886e3c6..da32e0c49b7 100644 --- a/interfaces/inner_api/runtime/include/js_runtime.h +++ b/interfaces/inner_api/runtime/include/js_runtime.h @@ -103,6 +103,8 @@ public: 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 {} bool PopPreloadObj(const std::string& key, std::unique_ptr& obj); void StartDebugMode(const DebugOption debugOption) override; void SetDebugOption(const DebugOption debugOption) override; @@ -156,6 +158,7 @@ public: void SetPkgContextInfoJson(std::string moduleName, std::string hapPath, std::string packageName); void UpdatePkgContextInfoJson(const std::string& moduleName, const std::string& hapPath, const std::string& packageName); + void RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) override; private: void FinishPreload() override; diff --git a/interfaces/inner_api/runtime/include/runtime.h b/interfaces/inner_api/runtime/include/runtime.h index 5b3312752f1..4c6196717a1 100644 --- a/interfaces/inner_api/runtime/include/runtime.h +++ b/interfaces/inner_api/runtime/include/runtime.h @@ -27,14 +27,23 @@ namespace AppExecFwk { class EventRunner; } // namespace AppExecFwk namespace AbilityRuntime { +namespace { +const std::string APPLICAITON_CODE_LANGUAGE_ARKTS_1_0 = "1.1"; +const std::string APPLICAITON_CODE_LANGUAGE_ARKTS_1_2 = "1.2"; +const std::string APPLICAITON_CODE_LANGUAGE_ARKTS_HYBRID = "hybrid"; +} // namespace + class Runtime { public: enum class Language { JS = 0, - CJ + CJ, + ETS, + UNKNOWN, }; struct Options { + std::map langs; Language lang = Language::JS; std::string bundleName; std::string moduleName; @@ -80,7 +89,8 @@ public: bool isDeveloperMode; }; - static std::unique_ptr Create(const Options& options); + static std::vector> CreateRuntimes(Options& options); + static std::unique_ptr Create(Options& options); static void SavePreloaded(std::unique_ptr&& instance); static std::unique_ptr GetPreloaded(); @@ -108,6 +118,8 @@ public: const std::string& hapPath, bool isEsMode, const std::string& srcEntrance) = 0; virtual void PreloadModule(const std::string& moduleName, const std::string& srcPath, const std::string& hapPath, bool isEsMode, bool useCommonTrunk) = 0; + virtual void PreloadModule(const std::string& moduleName, const std::string& hapPath, + bool isEsMode, bool useCommonTrunk) {} virtual void FinishPreload() = 0; virtual bool LoadRepairPatch(const std::string& patchFile, const std::string& baseFile) = 0; virtual bool NotifyHotReloadPage() = 0; @@ -122,6 +134,7 @@ public: Runtime(Runtime&&) = delete; Runtime& operator=(const Runtime&) = delete; Runtime& operator=(Runtime&&) = delete; + virtual void RegisterUncaughtExceptionHandler(void* uncaughtExceptionInfo) {} }; } // namespace AbilityRuntime } // namespace OHOS diff --git a/interfaces/kits/native/ability/native/ability_loader.h b/interfaces/kits/native/ability/native/ability_loader.h index 23947ec898c..247ae652370 100644 --- a/interfaces/kits/native/ability/native/ability_loader.h +++ b/interfaces/kits/native/ability/native/ability_loader.h @@ -28,9 +28,9 @@ namespace OHOS { namespace AppExecFwk { -using CreateExtension = std::function; +using CreateExtension = std::function; using CreateAblity = std::function; -using CreateUIAbility = std::function; +using CreateUIAbility = std::function; #ifdef ABILITY_WINDOW_SUPPORT using CreateSlice = std::function; #endif @@ -90,14 +90,15 @@ public: * * @return return Ability address */ - AbilityRuntime::Extension *GetExtensionByName(const std::string &abilityName); + AbilityRuntime::Extension *GetExtensionByName(const std::string &abilityName, + const std::string &language = AbilityRuntime::APPLICAITON_CODE_LANGUAGE_ARKTS_1_0); /** * @brief Get UIAbility address * @param abilityName UIAbility classname * @return return UIAbility address */ - AbilityRuntime::UIAbility *GetUIAbilityByName(const std::string &abilityName); + AbilityRuntime::UIAbility *GetUIAbilityByName(const std::string &abilityName, const std::string &language); #ifdef ABILITY_WINDOW_SUPPORT void RegisterAbilitySlice(const std::string &sliceName, const CreateSlice &createFunc); diff --git a/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h b/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h index 1fd257b8231..57f9c383be7 100644 --- a/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h +++ b/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h @@ -24,6 +24,7 @@ #include "cj_ability_delegator_impl.h" #endif #include "iability_delegator.h" +#include "runtime.h" namespace OHOS { namespace AppExecFwk { @@ -34,7 +35,8 @@ public: * * @return the AbilityDelegator object initialized when the application is started. */ - static std::shared_ptr GetAbilityDelegator(); + static std::shared_ptr GetAbilityDelegator( + const AbilityRuntime::Runtime::Language &language = AbilityRuntime::Runtime::Language::JS); #ifdef CJ_FRONTEND /** @@ -60,10 +62,11 @@ public: * @param args, Indicates the AbilityDelegatorArgs object. */ static void RegisterInstance( - const std::shared_ptr& delegator, const std::shared_ptr& args); + const std::shared_ptr &delegator, const std::shared_ptr &args, + const AbilityRuntime::Runtime::Language &language); private: - static std::shared_ptr abilityDelegator_; + static std::map> abilityDelegator_; static std::shared_ptr abilityDelegatorArgs_; }; } // namespace AppExecFwk diff --git a/interfaces/kits/native/appkit/app/application_data_manager.h b/interfaces/kits/native/appkit/app/application_data_manager.h index 3f8bb01b4e7..08ddb478a74 100644 --- a/interfaces/kits/native/appkit/app/application_data_manager.h +++ b/interfaces/kits/native/appkit/app/application_data_manager.h @@ -29,9 +29,11 @@ public: void AddErrorObserver(const std::shared_ptr &observer); bool NotifyUnhandledException(const std::string &errMsg); bool NotifyCJUnhandledException(const std::string &errMsg); + bool NotifyETSUnhandledException(const std::string &errMsg); void RemoveErrorObserver(); bool NotifyExceptionObject(const AppExecFwk::ErrorObject &errorObj); bool NotifyCJExceptionObject(const AppExecFwk::ErrorObject &errorObj); + bool NotifyETSExceptionObject(const AppExecFwk::ErrorObject &errorObj); private: ApplicationDataManager(); diff --git a/interfaces/kits/native/appkit/app/main_thread.h b/interfaces/kits/native/appkit/app/main_thread.h index cd5a86a89c5..148d2126bba 100644 --- a/interfaces/kits/native/appkit/app/main_thread.h +++ b/interfaces/kits/native/appkit/app/main_thread.h @@ -40,6 +40,7 @@ #include "resource_manager.h" #include "runtime.h" #include "watchdog.h" +#include "ets_runtime.h" #ifdef CJ_FRONTEND #include "cj_envsetup.h" @@ -323,6 +324,8 @@ public: CJUncaughtExceptionInfo CreateCjExceptionInfo(const std::string &bundleName, uint32_t versionCode, const std::string &hapPath); #endif + EtsEnv::ETSUncaughtExceptionInfo CreateEtsExceptionInfo(const std::string& bundleName, uint32_t versionCode, + const std::string& hapPath, std::string& appRunningId, int32_t pid, std::string& processName); /** * @brief Notify NativeEngine GC of status change. * @@ -622,7 +625,8 @@ private: * */ bool PrepareAbilityDelegator(const std::shared_ptr &record, bool isStageBased, - const AppExecFwk::HapModuleInfo &entryHapModuleInfo, uint32_t targetVersion); + const AppExecFwk::HapModuleInfo &entryHapModuleInfo, uint32_t targetVersion, + const std::string &applicationCodeLanguage); /** * @brief Set current process extension type @@ -797,6 +801,10 @@ private: void SetAppDebug(uint32_t modeFlag, bool isDebug); void GetPluginNativeLibPath(std::vector &pluginBundleInfos, AppLibPathMap &appLibPaths); + void AddRuntimeLang(ApplicationInfo& appInfo, AbilityRuntime::Runtime::Options& options); + bool IsNeedEtsInit(const ApplicationInfo& appInfo); + const std::unique_ptr& GetVerOneRuntime(const ApplicationInfo& appInfo, + const std::vector>& runtimes); std::vector fileEntries_; std::vector nativeFileEntries_; diff --git a/interfaces/kits/native/appkit/app/ohos_application.h b/interfaces/kits/native/appkit/app/ohos_application.h index 783bd601495..b9b286dd228 100644 --- a/interfaces/kits/native/appkit/app/ohos_application.h +++ b/interfaces/kits/native/appkit/app/ohos_application.h @@ -27,6 +27,7 @@ #include "ability_stage_context.h" #include "application_configuration_manager.h" #include "app_launch_data.h" +#include "runtime.h" namespace OHOS { namespace AbilityRuntime { @@ -49,11 +50,11 @@ public: void DumpApplication(); /** - * @brief Set Runtime + * @brief Add Runtime * * @param runtime Runtime instance. */ - void SetRuntime(std::unique_ptr&& runtime); + void AddRuntime(std::unique_ptr&& runtime); /** * @brief Set ApplicationContext @@ -168,12 +169,19 @@ public: */ std::shared_ptr GetAppContext() const; + /** + * @brief return the application runtimes + * + * @param runtime + */ + const std::vector>& GetRuntime() const; + /** * @brief return the application runtime * * @param runtime */ - const std::unique_ptr& GetRuntime() const; + const std::unique_ptr& GetRuntime(const std::string& language) const; /* * @@ -236,6 +244,8 @@ public: void PreloadAppStartup(const BundleInfo &bundleInfo, const std::string &preloadModuleName, std::shared_ptr startupTaskData); + void SetCJApplication(bool isCJApplication = false); + private: void UpdateAppContextResMgr(const Configuration &config); bool IsUpdateColorNeeded(Configuration &config, AbilityRuntime::SetLevel level); @@ -251,14 +261,17 @@ private: const AppExecFwk::HapModuleInfo &hapModuleInfo, const std::function& callback); bool IsMainProcess(const std::string &bundleName, const std::string &process); + AbilityRuntime::Runtime::Language ConvertLangToCode(const std::string &language) const; + void PreloadHybridModule(const HapModuleInfo &hapModuleInfo) const; private: std::shared_ptr abilityRecordMgr_ = nullptr; std::shared_ptr abilityRuntimeContext_ = nullptr; std::unordered_map> abilityStages_; - std::unique_ptr runtime_; + std::vector> runtimes_; std::shared_ptr configuration_ = nullptr; std::map extensionTypeMap_; + bool isCJApplication_ = false; }; } // namespace AppExecFwk } // namespace OHOS diff --git a/services/common/include/hilog_tag_wrapper.h b/services/common/include/hilog_tag_wrapper.h index b451ca0902f..475e33d324d 100644 --- a/services/common/include/hilog_tag_wrapper.h +++ b/services/common/include/hilog_tag_wrapper.h @@ -58,6 +58,8 @@ enum class AAFwkLogTag : uint32_t { INTENT, JSNAPI, CJRUNTIME, + ETSRUNTIME, + ANI, DELEGATOR = DEFAULT + 0x30, // 0xD001330 CONTEXT, @@ -129,7 +131,8 @@ inline const char* GetDomainName1(AAFwkLogTag tag) inline const char* GetDomainName2(AAFwkLogTag tag) { - const char* tagNames[] = { "JsEnv", "JsRuntime", "FA", "Intent", "JsNapi" }; + const char* tagNames[] = { "JsEnv", "JsRuntime", "FA", "Intent", "JsNapi", + "CjRuntime", "EtsRuntime", "Ani"}; uint32_t offset = GetOffset(tag, AAFwkLogTag::JSENV); if (offset >= sizeof(tagNames) / sizeof(const char*)) { return "UN"; diff --git a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn index d23b04bbb7d..93ebc7c8779 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn +++ b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn @@ -210,6 +210,7 @@ ohos_unittest("ability_delegator_registry_unittest") { "init:libbegetutil", "ipc:ipc_core", "napi:ace_napi", + "runtime_core:ani", ] } diff --git a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_registry_test.cpp b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_registry_test.cpp index 46e6d35f182..251bca4a328 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_registry_test.cpp +++ b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_registry_test.cpp @@ -96,7 +96,8 @@ HWTEST_F(AbilityDelegatorRegistryTest, Ability_Delegator_Registry_Test_0100, Fun std::unique_ptr testRunner = TestRunner::Create(nullptr, abilityArgs, true); std::shared_ptr abilityDelegator = std::make_shared(nullptr, std::move(testRunner), nullptr); - AbilityDelegatorRegistry::RegisterInstance(abilityDelegator, abilityArgs); + AbilityDelegatorRegistry::RegisterInstance(abilityDelegator, abilityArgs, + AbilityRuntime::Runtime::Language::JS); EXPECT_EQ(AbilityDelegatorRegistry::GetAbilityDelegator(), abilityDelegator); EXPECT_EQ(AbilityDelegatorRegistry::GetArguments(), abilityArgs); -- Gitee