From dd346604ca34866dce32e4c4fde147ee975f0fc2 Mon Sep 17 00:00:00 2001 From: "zhangyafei.echo" Date: Tue, 17 Jun 2025 23:34:56 +0800 Subject: [PATCH] Description:add abilitystagecontext applicationcontext context transfter Sig:SIG_ApplicationFramework Feature or BugFix: Feature Binary Source: No Signed-off-by: zhangyafei.echo Change-Id: I03ae6b16d51395b372752cf5ab5a8738faa726d9 Description:add context transfer dynamic Sig:SIG_ApplicationFramework Feature or BugFix: Feature Binary Source: No Signed-off-by: zhangyafei.echo Change-Id: I60311120b492a947ab91a7035e304e55669c7988 Description:context transfer bugfix. Sig:SIG_ApplicationFramework Feature or BugFix: Feature Binary Source: No Signed-off-by: zhangyafei.echo Change-Id: Iff2ffa198547d51805ca09dbf977ecaa31d92d38 --- frameworks/ets/ani/BUILD.gn | 3 + .../ani/app/ability_stage_context/BUILD.gn | 68 +++ .../ets_ability_stage_context_module.h | 53 +++ .../src/ets_ability_stage_context_module.cpp | 396 +++++++++++++++++ .../ets/ani/app/application_context/BUILD.gn | 68 +++ .../include/ets_application_context_module.h | 54 +++ .../src/ets_application_context_module.cpp | 414 +++++++++++++++++ frameworks/ets/ani/app/context/BUILD.gn | 70 +++ .../app/context/include/ets_context_module.h | 52 +++ .../app/context/src/ets_context_module.cpp | 417 ++++++++++++++++++ .../ets/application/AbilityStageContext.ets | 26 +- .../ets/application/ApplicationContext.ets | 25 +- frameworks/ets/ets/application/Context.ets | 21 + 13 files changed, 1663 insertions(+), 4 deletions(-) create mode 100644 frameworks/ets/ani/app/ability_stage_context/BUILD.gn create mode 100644 frameworks/ets/ani/app/ability_stage_context/include/ets_ability_stage_context_module.h create mode 100644 frameworks/ets/ani/app/ability_stage_context/src/ets_ability_stage_context_module.cpp create mode 100644 frameworks/ets/ani/app/application_context/BUILD.gn create mode 100644 frameworks/ets/ani/app/application_context/include/ets_application_context_module.h create mode 100644 frameworks/ets/ani/app/application_context/src/ets_application_context_module.cpp create mode 100644 frameworks/ets/ani/app/context/BUILD.gn create mode 100644 frameworks/ets/ani/app/context/include/ets_context_module.h create mode 100644 frameworks/ets/ani/app/context/src/ets_context_module.cpp diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index 41e6ae0915..99b67dea56 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -22,6 +22,9 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/ani_mission_manager:missionmanager_ani", "${ability_runtime_path}/frameworks/ets/ani/ani_wantagent_common:ani_wantagent_common", "${ability_runtime_path}/frameworks/ets/ani/app/ability_context:ability_context_ani_kit", + "${ability_runtime_path}/frameworks/ets/ani/app/ability_stage_context:ability_stage_context_ani_kit", + "${ability_runtime_path}/frameworks/ets/ani/app/application_context:application_context_ani_kit", + "${ability_runtime_path}/frameworks/ets/ani/app/context:context_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/app_manager:app_manager_ani", "${ability_runtime_path}/frameworks/ets/ani/application:application_ani", "${ability_runtime_path}/frameworks/ets/ani/apprecovery:appRecovery_ani", diff --git a/frameworks/ets/ani/app/ability_stage_context/BUILD.gn b/frameworks/ets/ani/app/ability_stage_context/BUILD.gn new file mode 100644 index 0000000000..238e2bca63 --- /dev/null +++ b/frameworks/ets/ani/app/ability_stage_context/BUILD.gn @@ -0,0 +1,68 @@ +# 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/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("ability_stage_context_ani_kit") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ + "./include", + "${ability_runtime_path}/interfaces/inner_api", + "${ability_runtime_path}/interfaces/kits/native/appkit", + "${ability_runtime_services_path}/common/include", + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", + ] + + configs = [] + + public_configs = [] + + sources = [ "./src/ets_ability_stage_context_module.cpp" ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + deps = [ + "${ability_runtime_innerkits_path}/ani_base_context:ani_base_context", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/appkit:ability_stage_ani", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:app_context_utils", + "${ability_runtime_native_path}/appkit:appkit_native", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hitrace:hitrace_meter", + "napi:ace_napi", + "runtime_core:ani", + "runtime_core:ani_helpers", + ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/ets/ani/app/ability_stage_context/include/ets_ability_stage_context_module.h b/frameworks/ets/ani/app/ability_stage_context/include/ets_ability_stage_context_module.h new file mode 100644 index 0000000000..be39cb7c5f --- /dev/null +++ b/frameworks/ets/ani/app/ability_stage_context/include/ets_ability_stage_context_module.h @@ -0,0 +1,53 @@ +/* +* 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_ABILITY_STAGE_CONTEXT_MODULE_H +#define OHOS_ABILITY_RUNTIME_ETS_ABILITY_STAGE_CONTEXT_MODULE_H + +#include + +#include "ability_stage_context.h" +#include "ani.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsAbilityStageContextModule { +public: + EtsAbilityStageContextModule() = default; + ~EtsAbilityStageContextModule() = default; + + EtsAbilityStageContextModule(const EtsAbilityStageContextModule&) = delete; + EtsAbilityStageContextModule(EtsAbilityStageContextModule&&) = delete; + EtsAbilityStageContextModule& operator=(const EtsAbilityStageContextModule&) = delete; + EtsAbilityStageContextModule& operator=(EtsAbilityStageContextModule&&) = delete; + + static ani_object NativeTransferStatic(ani_env *aniEnv, ani_object aniObj, ani_object input, ani_object type); + static ani_object NativeTransferDynamic(ani_env *aniEnv, ani_class aniCls, ani_object input); + static napi_value GetOrCreateDynamicObject(napi_env napiEnv, + std::shared_ptr abilityStageContext); + +private: + static bool IsInstanceOf(ani_env *aniEnv, ani_object aniObj); + static std::unique_ptr CreateNativeReference(napi_env napiEnv, + std::shared_ptr abilityStageContext); + static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, + std::shared_ptr abilityStageContext); +}; + +void EtsAbilityStageContextModuleInit(ani_env *aniEnv); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_ABILITY_STAGE_CONTEXT_MODULE_H diff --git a/frameworks/ets/ani/app/ability_stage_context/src/ets_ability_stage_context_module.cpp b/frameworks/ets/ani/app/ability_stage_context/src/ets_ability_stage_context_module.cpp new file mode 100644 index 0000000000..cb0d663bde --- /dev/null +++ b/frameworks/ets/ani/app/ability_stage_context/src/ets_ability_stage_context_module.cpp @@ -0,0 +1,396 @@ +/* + * 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_ability_stage_context_module.h" + +#include +#include +#include + +#include "ability_stage_context.h" +#include "ani_base_context.h" +#include "ani_common_util.h" +#include "context_transfer.h" +#include "ets_ability_stage_context.h" +#include "ets_error_utils.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "interop_js/arkts_esvalue.h" +#include "interop_js/arkts_interop_js_api.h" +#include "interop_js/hybridgref_ani.h" +#include "interop_js/hybridgref_napi.h" +#include "js_ability_stage_context.h" +#include "js_runtime_utils.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +ani_object EtsAbilityStageContextModule::NativeTransferStatic(ani_env *aniEnv, ani_object, ani_object input, + ani_object type) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "transfer static AbilityStageContext"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null aniEnv"); + return nullptr; + } + + void *unwrapResult = nullptr; + bool success = arkts_esvalue_unwrap(aniEnv, input, &unwrapResult); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "failed to unwrap"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + if (unwrapResult == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null unwrapResult"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto context = reinterpret_cast *>(unwrapResult)->lock(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null AbilityStageContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto abilityStageContext = Context::ConvertTo(context); + if (abilityStageContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid abilityStageContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto &bindingObj = abilityStageContext->GetBindingObject(); + if (bindingObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null bindingObj"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto staticContext = bindingObj->Get(); + if (staticContext != nullptr) { + TAG_LOGI(AAFwkTag::CONTEXT, "there exist a staticContext"); + return reinterpret_cast(*staticContext); + } + + // if not exist, create a new one + std::string contextType; + if (!AppExecFwk::GetStdString(aniEnv, reinterpret_cast(type), contextType)) { + TAG_LOGE(AAFwkTag::JSNAPI, "GetStdString failed"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + TAG_LOGD(AAFwkTag::CONTEXT, "contextType %{public}s", contextType.c_str()); + + auto newContext = ContextTransfer::GetInstance().GetStaticObject(contextType, aniEnv, context); + if (newContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "create abilityStageContext failed"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return newContext; +} + +std::unique_ptr EtsAbilityStageContextModule::CreateNativeReference(napi_env napiEnv, + std::shared_ptr abilityStageContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || abilityStageContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + auto value = CreateJsAbilityStageContext(napiEnv, abilityStageContext); + auto systemModule = JsRuntime::LoadSystemModuleByEngine(napiEnv, "application.AbilityStageContext", &value, 1); + if (systemModule == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null systemModule"); + return nullptr; + } + + napi_value object = systemModule->GetNapiValue(); + if (!CheckTypeForNapiValue(napiEnv, object, napi_object)) { + TAG_LOGE(AAFwkTag::CONTEXT, "check type failed"); + return nullptr; + } + + auto workContext = new (std::nothrow) std::weak_ptr(abilityStageContext); + if (workContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null workContext"); + return nullptr; + } + auto status = napi_coerce_to_native_binding_object(napiEnv, object, DetachCallbackFunc, AttachAbilityStageContext, + workContext, nullptr); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CONTEXT, "coerce AbilityStageContext failed: %{public}d", status); + delete workContext; + return nullptr; + } + + status = napi_wrap(napiEnv, object, workContext, + [](napi_env, void *data, void *) { + TAG_LOGD(AAFwkTag::CONTEXT, "finalizer for weak_ptr AbilityStageContext"); + delete static_cast *>(data); + }, nullptr, nullptr); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CONTEXT, "wrap failed: %{public}d", status); + delete workContext; + return nullptr; + } + + return systemModule; +} + +napi_value EtsAbilityStageContextModule::GetOrCreateDynamicObject(napi_env napiEnv, + std::shared_ptr abilityStageContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || abilityStageContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + // if sub-thread, create a new abilityStageContext and return + if (getpid() != syscall(SYS_gettid)) { + auto subThreadObj = static_cast( + abilityStageContext->GetSubThreadObject(static_cast(napiEnv))); + if (subThreadObj != nullptr) { + return subThreadObj->Get(); + } + auto subThreadRef = CreateNativeReference(napiEnv, abilityStageContext); + if (subThreadRef == nullptr) { + return nullptr; + } + auto newObject = subThreadRef->Get(); + abilityStageContext->BindSubThreadObject( + static_cast(napiEnv), static_cast(subThreadRef.release())); + return newObject; + } + + // if main-thread, get bindingObj firstly + auto &bindingObj = abilityStageContext->GetBindingObject(); + if (bindingObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null bindingObj"); + return nullptr; + } + + // if main-thread bindingObj exist, return it directly + auto dynamicContext = bindingObj->Get(); + if (dynamicContext != nullptr) { + TAG_LOGI(AAFwkTag::UIABILITY, "there exist a dynamicContext"); + return dynamicContext->Get(); + } + + // if main-thread bindingObj didn't exist, create and bind + auto nativeRef = CreateNativeReference(napiEnv, abilityStageContext); + if (nativeRef == nullptr) { + return nullptr; + } + + auto object = nativeRef->Get(); + abilityStageContext->Bind(nativeRef.release()); + return object; +} + +ani_object EtsAbilityStageContextModule::NativeTransferDynamic(ani_env *aniEnv, ani_class aniCls, ani_object input) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "transfer dynamic AbilityStageContext"); + if (!IsInstanceOf(aniEnv, input)) { + TAG_LOGE(AAFwkTag::CONTEXT, "not AbilityStageContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto context = AbilityRuntime::GetStageModeContext(aniEnv, input); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null context"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + std::shared_ptr abilityStageContext = Context::ConvertTo(context); + if (abilityStageContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid abilityStageContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + ani_object object = CreateDynamicObject(aniEnv, aniCls, abilityStageContext); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid object"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return object; +} + +ani_object EtsAbilityStageContextModule::CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, + std::shared_ptr abilityStageContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + std::string contextType; + if (!AppExecFwk::GetStaticFieldString(aniEnv, aniCls, "contextType", contextType)) { + TAG_LOGE(AAFwkTag::CONTEXT, "get context type failed"); + return nullptr; + } + TAG_LOGD(AAFwkTag::CONTEXT, "contextType %{public}s", contextType.c_str()); + + // get napiEnv from aniEnv + napi_env napiEnv = {}; + if (!arkts_napi_scope_open(aniEnv, &napiEnv)) { + TAG_LOGE(AAFwkTag::CONTEXT, "arkts_napi_scope_open failed"); + return nullptr; + } + + // create normal abilitystage context + auto contextObj = ContextTransfer::GetInstance().GetDynamicObject(contextType, napiEnv, abilityStageContext); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "create AbilityStageContext failed"); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + hybridgref ref = nullptr; + bool success = hybridgref_create_from_napi(napiEnv, contextObj, &ref); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "hybridgref_create_from_napi failed"); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + ani_object result = nullptr; + success = hybridgref_get_esvalue(aniEnv, ref, &result); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "hybridgref_get_esvalue failed"); + hybridgref_delete_from_napi(napiEnv, ref); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + hybridgref_delete_from_napi(napiEnv, ref); + + if (!arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr)) { + TAG_LOGE(AAFwkTag::CONTEXT, "arkts_napi_scope_close_n failed"); + return nullptr; + } + + return result; +} + +bool EtsAbilityStageContextModule::IsInstanceOf(ani_env *aniEnv, ani_object aniObj) +{ + ani_class cls {}; + ani_status status = ANI_ERROR; + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null aniEnv"); + return false; + } + if ((status = aniEnv->FindClass(ETS_ABILITY_STAGE_CONTEXT_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass status: %{public}d", status); + return false; + } + ani_boolean isInstanceOf = false; + if ((status = aniEnv->Object_InstanceOf(aniObj, cls, &isInstanceOf)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Object_InstanceOf status: %{public}d", status); + return false; + } + return isInstanceOf; +} + +void EtsAbilityStageContextModuleInit(ani_env *aniEnv) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "Init AbilityStageContext kit"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null ani env"); + return; + } + + ani_class abilityStageContextCls = nullptr; + auto status = aniEnv->FindClass(ETS_ABILITY_STAGE_CONTEXT_CLASS_NAME, &abilityStageContextCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "FindClass AbilityStageContext failed status: %{public}d", status); + return; + } + + std::array nativeFuncs = { + ani_native_function { "nativeTransferStatic", "Lstd/interop/ESValue;Lstd/core/String;:Lstd/core/Object;", + reinterpret_cast(EtsAbilityStageContextModule::NativeTransferStatic) }, + ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;", + reinterpret_cast(EtsAbilityStageContextModule::NativeTransferDynamic) }, + }; + status = aniEnv->Class_BindNativeMethods(abilityStageContextCls, nativeFuncs.data(), nativeFuncs.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "Class_BindNativeMethods failed status: %{public}d", status); + return; + } + + ContextTransfer::GetInstance().RegisterStaticObjectCreator("AbilityStageContext", + [](ani_env *aniEnv, std::shared_ptr context) -> ani_object { + auto newContext = ETSAbilityStageContext::CreateEtsAbilityStageContext(aniEnv, context); + if (newContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "create abilityStageContext failed"); + return nullptr; + } + + return newContext; + }); + + ContextTransfer::GetInstance().RegisterDynamicObjectCreator("AbilityStageContext", + [](napi_env napiEnv, std::shared_ptr context) -> napi_value { + auto abilityStageContext = Context::ConvertTo(context); + if (abilityStageContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid abilityStageContext"); + return nullptr; + } + + auto object = EtsAbilityStageContextModule::GetOrCreateDynamicObject(napiEnv, abilityStageContext); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "get or create object failed"); + return nullptr; + } + return object; + }); + + TAG_LOGD(AAFwkTag::CONTEXT, "Init AbilityStageContext kit end"); +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "ANI_Constructor"); + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null vm"); + return ANI_ERROR; + } + + ani_env *aniEnv = nullptr; + ani_status status = vm->GetEnv(ANI_VERSION_1, &aniEnv); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "GetEnv failed status: %{public}d", status); + return ANI_NOT_FOUND; + } + + EtsAbilityStageContextModuleInit(aniEnv); + *result = ANI_VERSION_1; + TAG_LOGD(AAFwkTag::CONTEXT, "ANI_Constructor finish"); + return ANI_OK; +} +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/ets/ani/app/application_context/BUILD.gn b/frameworks/ets/ani/app/application_context/BUILD.gn new file mode 100644 index 0000000000..34a117c9e1 --- /dev/null +++ b/frameworks/ets/ani/app/application_context/BUILD.gn @@ -0,0 +1,68 @@ +# 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/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("application_context_ani_kit") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ + "./include", + "${ability_runtime_napi_path}/ability_auto_startup_callback", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/app", + ] + + configs = [] + + public_configs = [] + + sources = [ "./src/ets_application_context_module.cpp" ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + deps = [ + "${ability_runtime_innerkits_path}/ani_base_context:ani_base_context", + "${ability_runtime_innerkits_path}/error_utils:ability_runtime_error_util", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_napi_path}/inner/napi_common:napi_common", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:app_context_utils", + "${ability_runtime_native_path}/appkit:application_context_manager", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hitrace:hitrace_meter", + "napi:ace_napi", + "runtime_core:ani", + "runtime_core:ani_helpers", + ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/ets/ani/app/application_context/include/ets_application_context_module.h b/frameworks/ets/ani/app/application_context/include/ets_application_context_module.h new file mode 100644 index 0000000000..bfd3117b4b --- /dev/null +++ b/frameworks/ets/ani/app/application_context/include/ets_application_context_module.h @@ -0,0 +1,54 @@ +/* +* 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_APPLICATION_CONTEXT_MODULE_H +#define OHOS_ABILITY_RUNTIME_ETS_APPLICATION_CONTEXT_MODULE_H + +#include + +#include "ani.h" +#include "application_context.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsApplicationContextModule { +public: + EtsApplicationContextModule() = default; + ~EtsApplicationContextModule() = default; + + EtsApplicationContextModule(const EtsApplicationContextModule&) = delete; + EtsApplicationContextModule(EtsApplicationContextModule&&) = delete; + EtsApplicationContextModule& operator=(const EtsApplicationContextModule&) = delete; + EtsApplicationContextModule& operator=(EtsApplicationContextModule&&) = delete; + + static ani_object NativeTransferStatic(ani_env *aniEnv, ani_object aniObj, ani_object input, ani_object type); + static ani_object NativeTransferDynamic(ani_env *aniEnv, ani_class aniCls, ani_object input); + static napi_value GetOrCreateDynamicObject(napi_env napiEnv, + std::shared_ptr applicationContext); + static void RegisterContextObjectCreator(); + +private: + static bool IsInstanceOf(ani_env *aniEnv, ani_object aniObj); + static std::unique_ptr CreateNativeReference(napi_env napiEnv, + std::shared_ptr applicationContext); + static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, + std::shared_ptr applicationContext); +}; + +void EtsApplicationContextModuleInit(ani_env *aniEnv); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_APPLICATION_CONTEXT_MODULE_H diff --git a/frameworks/ets/ani/app/application_context/src/ets_application_context_module.cpp b/frameworks/ets/ani/app/application_context/src/ets_application_context_module.cpp new file mode 100644 index 0000000000..758d122e74 --- /dev/null +++ b/frameworks/ets/ani/app/application_context/src/ets_application_context_module.cpp @@ -0,0 +1,414 @@ +/* + * 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_application_context_module.h" + +#include +#include +#include + +#include "ani_base_context.h" +#include "ani_common_util.h" +#include "application_context_manager.h" +#include "bindable_sub_thread.h" +#include "context_transfer.h" +#include "ets_application_context_utils.h" +#include "ets_error_utils.h" +#include "ets_native_reference.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "interop_js/arkts_esvalue.h" +#include "interop_js/arkts_interop_js_api.h" +#include "interop_js/hybridgref_ani.h" +#include "interop_js/hybridgref_napi.h" +#include "js_application_context_utils.h" +#include "js_context_utils.h" +#include "js_runtime_utils.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *ETS_APPLICATION_CONTEXT_CLASS_NAME = "Lapplication/ApplicationContext/ApplicationContext;"; +} // namespace + +ani_object EtsApplicationContextModule::NativeTransferStatic(ani_env *aniEnv, ani_object self, ani_object input, + ani_object type) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "transfer static ApplicationContext"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null aniEnv"); + return nullptr; + } + + void *unwrapResult = nullptr; + bool success = arkts_esvalue_unwrap(aniEnv, input, &unwrapResult); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "failed to unwrap"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + if (unwrapResult == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null unwrapResult"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + auto context = reinterpret_cast *>(unwrapResult)->lock(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null application context"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto applicationContext = Context::ConvertTo(context); + if (applicationContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null ApplicationContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto &bindingObj = applicationContext->GetBindingObject(); + if (bindingObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null bindingObj"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + // get binding obj + auto staticContext = bindingObj->Get(); + if (staticContext != nullptr) { + TAG_LOGI(AAFwkTag::CONTEXT, "got an exist staticContext"); + return reinterpret_cast(*staticContext); + } + + // create a new one + std::string contextType; + if (!AppExecFwk::GetStdString(aniEnv, reinterpret_cast(type), contextType)) { + TAG_LOGE(AAFwkTag::JSNAPI, "GetStdString failed"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + TAG_LOGD(AAFwkTag::CONTEXT, "contextType %{public}s", contextType.c_str()); + + auto contextObj = ContextTransfer::GetInstance().GetStaticObject(contextType, aniEnv, context); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "create object failed"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return contextObj; +} + +std::unique_ptr EtsApplicationContextModule::CreateNativeReference(napi_env napiEnv, + std::shared_ptr applicationContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || applicationContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + auto value = JsApplicationContextUtils::CreateJsApplicationContext(napiEnv); + auto systemModule = JsRuntime::LoadSystemModuleByEngine(napiEnv, "application.ApplicationContext", &value, 1); + if (systemModule == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null system module"); + return nullptr; + } + + napi_value object = systemModule->GetNapiValue(); + if (!CheckTypeForNapiValue(napiEnv, object, napi_object)) { + TAG_LOGE(AAFwkTag::CONTEXT, "check type failed"); + return nullptr; + } + + auto workContext = new (std::nothrow) std::weak_ptr(applicationContext); + if (workContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null workContext"); + return nullptr; + } + auto status = napi_coerce_to_native_binding_object(napiEnv, object, DetachCallbackFunc, AttachApplicationContext, + workContext, nullptr); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CONTEXT, "coerce applicationContext failed: %{public}d", status); + delete workContext; + return nullptr; + } + + status = napi_wrap(napiEnv, object, workContext, + [](napi_env, void *data, void *) { + TAG_LOGD(AAFwkTag::CONTEXT, "finalizer for weak_ptr applicationContext"); + delete static_cast *>(data); + }, nullptr, nullptr); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CONTEXT, "wrap failed: %{public}d", status); + delete workContext; + return nullptr; + } + + return systemModule; +} + +napi_value EtsApplicationContextModule::GetOrCreateDynamicObject(napi_env napiEnv, + std::shared_ptr applicationContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || applicationContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + // if sub-thread, create a new applicationContext and return + if (getpid() != syscall(SYS_gettid)) { + auto subThreadObj = static_cast( + applicationContext->GetSubThreadObject(static_cast(napiEnv))); + if (subThreadObj != nullptr) { + return subThreadObj->Get(); + } + auto subThreadRef = CreateNativeReference(napiEnv, applicationContext); + if (subThreadRef == nullptr) { + return nullptr; + } + auto newObject = subThreadRef->Get(); + applicationContext->BindSubThreadObject( + static_cast(napiEnv), static_cast(subThreadRef.release())); + return newObject; + } + + // if main-thread, get bindingObj firstly + auto &bindingObj = applicationContext->GetBindingObject(); + if (bindingObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null bindingObj"); + return nullptr; + } + + // if main-thread bindingObj exist, return it directly + auto dynamicContext = bindingObj->Get(); + if (dynamicContext != nullptr) { + TAG_LOGI(AAFwkTag::UIABILITY, "there exist a dynamicContext"); + return dynamicContext->Get(); + } + + // if main-thread bindingObj didn't exist, create and bind + auto nativeRef = CreateNativeReference(napiEnv, applicationContext); + if (nativeRef == nullptr) { + return nullptr; + } + + auto object = nativeRef->Get(); + applicationContext->Bind(nativeRef.release()); + return object; +} + +ani_object EtsApplicationContextModule::NativeTransferDynamic(ani_env *aniEnv, ani_class aniCls, ani_object input) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "transfer dynamic ApplicationContext"); + if (!IsInstanceOf(aniEnv, input)) { + TAG_LOGE(AAFwkTag::CONTEXT, "not ApplicationContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto context = AbilityRuntime::GetStageModeContext(aniEnv, input); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null context"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + std::shared_ptr applicationContext = Context::ConvertTo(context); + if (applicationContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid applicationContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + ani_object object = CreateDynamicObject(aniEnv, aniCls, applicationContext); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid object"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return object; +} + +ani_object EtsApplicationContextModule::CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, + std::shared_ptr applicationContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + std::string contextType; + if (!AppExecFwk::GetStaticFieldString(aniEnv, aniCls, "contextType", contextType)) { + TAG_LOGE(AAFwkTag::CONTEXT, "get context type failed"); + return nullptr; + } + TAG_LOGD(AAFwkTag::CONTEXT, "contextType %{public}s", contextType.c_str()); + + // get napiEnv from aniEnv + napi_env napiEnv = {}; + if (!arkts_napi_scope_open(aniEnv, &napiEnv)) { + TAG_LOGE(AAFwkTag::CONTEXT, "arkts_napi_scope_open failed"); + return nullptr; + } + + // create normal application context + auto contextObj = ContextTransfer::GetInstance().GetDynamicObject(contextType, napiEnv, applicationContext); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "create ApplicationContext failed"); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + hybridgref ref = nullptr; + bool success = hybridgref_create_from_napi(napiEnv, contextObj, &ref); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "hybridgref_create_from_napi failed"); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + ani_object result = nullptr; + success = hybridgref_get_esvalue(aniEnv, ref, &result); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "hybridgref_get_esvalue failed"); + hybridgref_delete_from_napi(napiEnv, ref); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + hybridgref_delete_from_napi(napiEnv, ref); + + if (!arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr)) { + TAG_LOGE(AAFwkTag::CONTEXT, "arkts_napi_scope_close_n failed"); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + return result; +} + +bool EtsApplicationContextModule::IsInstanceOf(ani_env *aniEnv, ani_object aniObj) +{ + ani_class cls {}; + ani_status status = ANI_ERROR; + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null aniEnv"); + return false; + } + if ((status = aniEnv->FindClass(ETS_APPLICATION_CONTEXT_CLASS_NAME, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass status: %{public}d", status); + return false; + } + ani_boolean isInstanceOf = false; + if ((status = aniEnv->Object_InstanceOf(aniObj, cls, &isInstanceOf)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Object_InstanceOf status: %{public}d", status); + return false; + } + return isInstanceOf; +} + +void EtsApplicationContextModule::RegisterContextObjectCreator() +{ + ContextTransfer::GetInstance().RegisterStaticObjectCreator("ApplicationContext", + [](ani_env *aniEnv, std::shared_ptr context) -> ani_object { + auto applicationContext = Context::ConvertTo(context); + if (applicationContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid applicationContext"); + return nullptr; + } + EtsApplicationContextUtils::CreateEtsApplicationContext(aniEnv, applicationContext); + auto appContextObj = ApplicationContextManager::GetApplicationContextManager().GetEtsGlobalObject(); + if (appContextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "appContextObj is nullptr"); + return nullptr; + } + + return appContextObj->aniObj; + }); + + ContextTransfer::GetInstance().RegisterDynamicObjectCreator("ApplicationContext", + [](napi_env napiEnv, std::shared_ptr context) -> napi_value { + auto applicationContext = Context::ConvertTo(context); + if (applicationContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid applicationContext"); + return nullptr; + } + + auto object = EtsApplicationContextModule::GetOrCreateDynamicObject(napiEnv, applicationContext); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "get or create object failed"); + return nullptr; + } + return object; + }); +} + +void EtsApplicationContextModuleInit(ani_env *aniEnv) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "Init application context kit"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null ani env"); + return; + } + + ani_class applicationContextCls = nullptr; + auto status = aniEnv->FindClass(ETS_APPLICATION_CONTEXT_CLASS_NAME, &applicationContextCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass ApplicationContext failed status: %{public}d", status); + return; + } + + std::array nativeFuncs = { + ani_native_function { "nativeTransferStatic", "Lstd/interop/ESValue;Lstd/core/String;:Lstd/core/Object;", + reinterpret_cast(EtsApplicationContextModule::NativeTransferStatic) }, + ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;", + reinterpret_cast(EtsApplicationContextModule::NativeTransferDynamic) }, + }; + status = aniEnv->Class_BindNativeMethods(applicationContextCls, nativeFuncs.data(), nativeFuncs.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Class_BindNativeMethods failed status: %{public}d", status); + return; + } + + EtsApplicationContextModule::RegisterContextObjectCreator(); + TAG_LOGD(AAFwkTag::CONTEXT, "Init application context kit end"); +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "ANI_Constructor"); + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null vm"); + return ANI_ERROR; + } + + ani_env *aniEnv = nullptr; + ani_status status = vm->GetEnv(ANI_VERSION_1, &aniEnv); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "GetEnv failed status: %{public}d", status); + return ANI_NOT_FOUND; + } + + EtsApplicationContextModuleInit(aniEnv); + *result = ANI_VERSION_1; + TAG_LOGD(AAFwkTag::CONTEXT, "ANI_Constructor finish"); + return ANI_OK; +} +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/ets/ani/app/context/BUILD.gn b/frameworks/ets/ani/app/context/BUILD.gn new file mode 100644 index 0000000000..81a953ec41 --- /dev/null +++ b/frameworks/ets/ani/app/context/BUILD.gn @@ -0,0 +1,70 @@ +# 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/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("context_ani_kit") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ + "./include", + "${ability_runtime_napi_path}/ability_auto_startup_callback", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/app", + ] + + configs = [] + + public_configs = [] + + sources = [ "./src/ets_context_module.cpp" ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + deps = [ + "${ability_runtime_innerkits_path}/ani_base_context:ani_base_context", + "${ability_runtime_innerkits_path}/error_utils:ability_runtime_error_util", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_napi_path}/inner/napi_common:napi_common", + "${ability_runtime_native_path}/ability/native:ability_business_error", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:app_context_utils", + "${ability_runtime_native_path}/appkit:appkit_native", + "${ability_runtime_native_path}/appkit:application_context_manager", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hitrace:hitrace_meter", + "napi:ace_napi", + "runtime_core:ani", + "runtime_core:ani_helpers", + ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/ets/ani/app/context/include/ets_context_module.h b/frameworks/ets/ani/app/context/include/ets_context_module.h new file mode 100644 index 0000000000..47343c4611 --- /dev/null +++ b/frameworks/ets/ani/app/context/include/ets_context_module.h @@ -0,0 +1,52 @@ +/* +* 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_CONTEXT_MODULE_H +#define OHOS_ABILITY_RUNTIME_ETS_CONTEXT_MODULE_H + +#include + +#include "ability_stage_context.h" +#include "ani.h" +#include "application_context.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsContextModule { +public: + EtsContextModule() = default; + ~EtsContextModule() = default; + + EtsContextModule(const EtsContextModule&) = delete; + EtsContextModule(EtsContextModule&&) = delete; + EtsContextModule& operator=(const EtsContextModule&) = delete; + EtsContextModule& operator=(EtsContextModule&&) = delete; + + static ani_object NativeTransferStatic(ani_env *env, ani_object aniObj, ani_object input, ani_object type); + static ani_object NativeTransferDynamic(ani_env *env, ani_class aniCls, ani_object input); + static napi_value GetOrCreateDynamicObject(napi_env napiEnv, std::shared_ptr context); + +private: + static bool LoadTargetModule(ani_env *aniEnv, const std::string &className); + static std::unique_ptr CreateNativeReference(napi_env napiEnv, std::shared_ptr context); + static ani_object CreateStaticObject(ani_env *aniEnv, ani_object type, std::shared_ptr context); + static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, std::shared_ptr context); +}; + +void EtsContextModuleInit(ani_env *aniEnv); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_CONTEXT_MODULE_H diff --git a/frameworks/ets/ani/app/context/src/ets_context_module.cpp b/frameworks/ets/ani/app/context/src/ets_context_module.cpp new file mode 100644 index 0000000000..6fbecb0340 --- /dev/null +++ b/frameworks/ets/ani/app/context/src/ets_context_module.cpp @@ -0,0 +1,417 @@ +/* + * 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_context_module.h" + +#include +#include +#include + +#include "ani_base_context.h" +#include "ani_common_util.h" +#include "application_context_manager.h" +#include "context_transfer.h" +#include "ets_ability_stage_context.h" +#include "ets_application_context_utils.h" +#include "ets_context_utils.h" +#include "ets_error_utils.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "interop_js/arkts_esvalue.h" +#include "interop_js/arkts_interop_js_api.h" +#include "interop_js/hybridgref_ani.h" +#include "interop_js/hybridgref_napi.h" +#include "js_ability_stage_context.h" +#include "js_application_context_utils.h" +#include "js_context_utils.h" +#include "js_runtime_utils.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *ETS_CONTEXT_CLASS_NAME = "Lapplication/Context/Context;"; + +std::string GetClassNameByContextType(const std::string &contextType) +{ + std::string className; + static const std::unordered_map mapping = { + {"Context", "Lapplication/Context/Context;"}, + {"ApplicationContext", "Lapplication/ApplicationContext/ApplicationContext;"}, + {"AbilityStageContext", "Lapplication/AbilityStageContext/AbilityStageContext;"}, + {"UIAbilityContext", "Lapplication/UIAbilityContext/UIAbilityContext;"} + }; + auto it = mapping.find(contextType); + if (it != mapping.end()) { + className = it->second; + } + return className; +} +} // namespace + +ani_object EtsContextModule::NativeTransferStatic(ani_env *aniEnv, ani_object self, ani_object input, ani_object type) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "transfer static Context"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null aniEnv"); + return nullptr; + } + void *unwrapResult = nullptr; + bool success = arkts_esvalue_unwrap(aniEnv, input, &unwrapResult); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "failed to unwrap"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + if (unwrapResult == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null unwrapResult"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto context = reinterpret_cast *>(unwrapResult)->lock(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null Context"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto &bindingObj = context->GetBindingObject(); + if (bindingObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null bindingObj"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto staticContext = bindingObj->Get(); + if (staticContext != nullptr) { + TAG_LOGI(AAFwkTag::CONTEXT, "there exist a staticContext"); + return reinterpret_cast(*staticContext); + } + + auto contextObj = CreateStaticObject(aniEnv, type, context); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "contextObj invalid"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return contextObj; +} + +ani_object EtsContextModule::CreateStaticObject(ani_env *aniEnv, ani_object type, std::shared_ptr context) +{ + std::string contextType; + if (!AppExecFwk::GetStdString(aniEnv, reinterpret_cast(type), contextType)) { + TAG_LOGE(AAFwkTag::JSNAPI, "GetStdString failed"); + return nullptr; + } + TAG_LOGD(AAFwkTag::CONTEXT, "contextType %{public}s", contextType.c_str()); + + if (!ContextTransfer::GetInstance().IsStaticCreatorExist(contextType)) { + std::string className = GetClassNameByContextType(contextType); + if (!LoadTargetModule(aniEnv, className)) { + return nullptr; + } + } + + auto contextObj = ContextTransfer::GetInstance().GetStaticObject(contextType, aniEnv, context); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "contextObj invalid"); + return nullptr; + } + + return contextObj; +} + +bool EtsContextModule::LoadTargetModule(ani_env *aniEnv, const std::string &className) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + ani_class contextCls = nullptr; + auto status = aniEnv->FindClass(className.c_str(), &contextCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass %{public}s failed status: %{public}d", className.c_str(), status); + return false; + } + + std::string gotContextType; + if (!AppExecFwk::GetStaticFieldString(aniEnv, contextCls, "contextType", gotContextType)) { + TAG_LOGE(AAFwkTag::CONTEXT, "get context type failed"); + return false; + } + + TAG_LOGD(AAFwkTag::CONTEXT, "gotContext %{public}s", gotContextType.c_str()); + return true; +} + +std::unique_ptr EtsContextModule::CreateNativeReference(napi_env napiEnv, + std::shared_ptr context) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + auto value = CreateJsBaseContext(napiEnv, context); + auto systemModule = JsRuntime::LoadSystemModuleByEngine(napiEnv, "application.Context", &value, 1); + if (systemModule == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null system module"); + return nullptr; + } + + napi_value object = systemModule->GetNapiValue(); + if (!CheckTypeForNapiValue(napiEnv, object, napi_object)) { + TAG_LOGE(AAFwkTag::CONTEXT, "check type failed"); + return nullptr; + } + + auto workContext = new (std::nothrow) std::weak_ptr(context); + if (workContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null workContext"); + return nullptr; + } + auto status = napi_coerce_to_native_binding_object(napiEnv, object, DetachCallbackFunc, AttachBaseContext, + workContext, nullptr); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CONTEXT, "coerce context failed: %{public}d", status); + delete workContext; + return nullptr; + } + + status = napi_wrap(napiEnv, object, workContext, + [](napi_env, void *data, void *) { + TAG_LOGD(AAFwkTag::CONTEXT, "finalizer for weak_ptr context"); + delete static_cast *>(data); + }, nullptr, nullptr); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CONTEXT, "wrap failed: %{public}d", status); + delete workContext; + return nullptr; + } + + return systemModule; +} + +napi_value EtsContextModule::GetOrCreateDynamicObject(napi_env napiEnv, std::shared_ptr context) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + // if sub-thread, create a new context and return + if (getpid() != syscall(SYS_gettid)) { + auto subThreadObj = static_cast(context->GetSubThreadObject(static_cast(napiEnv))); + if (subThreadObj != nullptr) { + return subThreadObj->Get(); + } + auto subThreadRef = CreateNativeReference(napiEnv, context); + if (subThreadRef == nullptr) { + return nullptr; + } + auto newObject = subThreadRef->Get(); + context->BindSubThreadObject(static_cast(napiEnv), static_cast(subThreadRef.release())); + return newObject; + } + + // if main-thread, get bindingObj firstly + auto &bindingObj = context->GetBindingObject(); + if (bindingObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null bindingObj"); + return nullptr; + } + + // if main-thread bindingObj exist, return it directly + auto dynamicContext = bindingObj->Get(); + if (dynamicContext != nullptr) { + TAG_LOGI(AAFwkTag::UIABILITY, "there exist a dynamicContext"); + return dynamicContext->Get(); + } + + // if main-thread bindingObj didn't exist, create and bind + std::unique_ptr nativeRef = CreateNativeReference(napiEnv, context); + if (nativeRef == nullptr) { + return nullptr; + } + + auto object = nativeRef->Get(); + context->Bind(nativeRef.release()); + return object; +} + +ani_object EtsContextModule::NativeTransferDynamic(ani_env *aniEnv, ani_class aniCls, ani_object input) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "transfer dynamic Context"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null aniEnv"); + return nullptr; + } + + auto context = AbilityRuntime::GetStageModeContext(aniEnv, input); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null context"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + ani_object object = CreateDynamicObject(aniEnv, aniCls, context); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid object"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return object; +} + +ani_object EtsContextModule::CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, + std::shared_ptr contextPtr) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + std::string contextType; + if (!AppExecFwk::GetStaticFieldString(aniEnv, aniCls, "contextType", contextType)) { + TAG_LOGE(AAFwkTag::CONTEXT, "get context type failed"); + return nullptr; + } + TAG_LOGD(AAFwkTag::CONTEXT, "contextType %{public}s", contextType.c_str()); + + if (!ContextTransfer::GetInstance().IsDynamicCreatorExist(contextType)) { + std::string className = GetClassNameByContextType(contextType); + if (!LoadTargetModule(aniEnv, className)) { + return nullptr; + } + } + + // get napiEnv from aniEnv + napi_env napiEnv = {}; + if (!arkts_napi_scope_open(aniEnv, &napiEnv)) { + TAG_LOGE(AAFwkTag::CONTEXT, "arkts_napi_scope_open failed"); + return nullptr; + } + + // create normal context + auto contextObj = ContextTransfer::GetInstance().GetDynamicObject(contextType, napiEnv, contextPtr); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "create Context failed"); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + hybridgref ref = nullptr; + bool success = hybridgref_create_from_napi(napiEnv, contextObj, &ref); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "hybridgref_create_from_napi failed"); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + ani_object result = nullptr; + success = hybridgref_get_esvalue(aniEnv, ref, &result); + if (!success) { + TAG_LOGE(AAFwkTag::CONTEXT, "hybridgref_get_esvalue failed"); + hybridgref_delete_from_napi(napiEnv, ref); + arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr); + return nullptr; + } + + hybridgref_delete_from_napi(napiEnv, ref); + + if (!arkts_napi_scope_close_n(napiEnv, 0, nullptr, nullptr)) { + TAG_LOGE(AAFwkTag::CONTEXT, "arkts_napi_scope_close_n failed"); + return nullptr; + } + + return result; +} + +void EtsContextModuleInit(ani_env *aniEnv) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "Init Context kit"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null ani env"); + return; + } + + ani_class contextCls = nullptr; + auto status = aniEnv->FindClass(ETS_CONTEXT_CLASS_NAME, &contextCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass Context failed status: %{public}d", status); + return; + } + + std::array nativeFuncs = { + ani_native_function { "nativeTransferStatic", "Lstd/interop/ESValue;Lstd/core/String;:Lstd/core/Object;", + reinterpret_cast(EtsContextModule::NativeTransferStatic) }, + ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;", + reinterpret_cast(EtsContextModule::NativeTransferDynamic) }, + }; + status = aniEnv->Class_BindNativeMethods(contextCls, nativeFuncs.data(), nativeFuncs.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Class_BindNativeMethods failed status: %{public}d", status); + return; + } + + ContextTransfer::GetInstance().RegisterStaticObjectCreator("Context", + [](ani_env *aniEnv, std::shared_ptr context) -> ani_object { + ani_class cls {}; + ani_status status = ANI_ERROR; + if ((status = aniEnv->FindClass("Lapplication/Context/Context;", &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); + return nullptr; + } + return ContextUtil::CreateContextObject(aniEnv, cls, context); + }); + + ContextTransfer::GetInstance().RegisterDynamicObjectCreator("Context", + [](napi_env napiEnv, std::shared_ptr context) -> napi_value { + auto object = EtsContextModule::GetOrCreateDynamicObject(napiEnv, context); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "get or create object failed"); + return nullptr; + } + return object; + }); + + TAG_LOGD(AAFwkTag::CONTEXT, "Init Context kit end"); +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "ANI_Constructor"); + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null vm"); + return ANI_ERROR; + } + + ani_env *aniEnv = nullptr; + ani_status status = vm->GetEnv(ANI_VERSION_1, &aniEnv); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "GetEnv failed status: %{public}d", status); + return ANI_NOT_FOUND; + } + + EtsContextModuleInit(aniEnv); + *result = ANI_VERSION_1; + TAG_LOGD(AAFwkTag::CONTEXT, "ANI_Constructor finish"); + return ANI_OK; +} +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/ets/ets/application/AbilityStageContext.ets b/frameworks/ets/ets/application/AbilityStageContext.ets index 93655dab82..5e2e9fa438 100644 --- a/frameworks/ets/ets/application/AbilityStageContext.ets +++ b/frameworks/ets/ets/application/AbilityStageContext.ets @@ -20,12 +20,32 @@ import { HapModuleInfo } from 'bundleManager.HapModuleInfo' export default class AbilityStageContext extends Context { static { loadLibraryWithPermissionCheck("context_ani", "application.AbilityStageContext"); + loadLibraryWithPermissionCheck("ability_stage_context_ani_kit.z", "application.AbilityStageContext"); } config?: Configuration; currentHapModuleInfo: HapModuleInfo; native constructor(); constructor(currentHapModuleInfo: HapModuleInfo) { - super(); - this.currentHapModuleInfo = currentHapModuleInfo; + super(); + this.currentHapModuleInfo = currentHapModuleInfo; } -} \ No newline at end of file + + private static native nativeTransferStatic(input: ESValue, type: string): Object; + private static native nativeTransferDynamic(input: Object): ESValue; + private static contextType: string = 'AbilityStageContext'; + + static transferStatic(input: Any): Object { + let type: string = ''; + try { + type = ESValue.wrap(input).getProperty('__context_impl__').getProperty('contextType').toString(); + } catch (err) { + console.log('transferStatic err: ' + err.toString()); + } + console.log('transferStatic type: ' + type); + return AbilityStageContext.nativeTransferStatic(ESValue.wrap(input), type); + } + + static transferDynamic(input: Object): Any { + return AbilityStageContext.nativeTransferDynamic(input).unwrap(); + } +} diff --git a/frameworks/ets/ets/application/ApplicationContext.ets b/frameworks/ets/ets/application/ApplicationContext.ets index 5239b314fe..cf7845dc62 100644 --- a/frameworks/ets/ets/application/ApplicationContext.ets +++ b/frameworks/ets/ets/application/ApplicationContext.ets @@ -40,6 +40,10 @@ let destroyRegister = new FinalizationRegistry(callback); let unregisterToken = new object(); export default class ApplicationContext extends Context { + static { + loadLibraryWithPermissionCheck("application_context_ani_kit.z", "application.ApplicationContext"); + } + etsApplicationContextPtr: long = 0; private cleaner: Cleaner | null = null; @@ -58,6 +62,7 @@ export default class ApplicationContext extends Context { unregisterCleaner(): void { destroyRegister.unregister(unregisterToken); } + public native nativekillAllProcessesSync(clearPageStack: boolean, callback: AsyncCallbackWrapper): void; public native nativepreloadUIExtensionAbilitySync(want: Want, callback: AsyncCallbackWrapper): void; public native setSupportedProcessCacheSync(isSupported : boolean):void; @@ -75,6 +80,9 @@ export default class ApplicationContext extends Context { public native nativeOffApplicationStateChangeSync(callback?: ApplicationStateChangeCallback): void; public native nativegetCurrentAppCloneIndex(): int; public native nativegetCurrentInstanceKey(): string; + private static native nativeTransferStatic(input: ESValue, type: string): Object; + private static native nativeTransferDynamic(input: Object): ESValue; + private static contextType: string = 'ApplicationContext'; setSupportedProcessCache(isSupported : boolean):void { this.setSupportedProcessCacheSync(isSupported); @@ -271,4 +279,19 @@ export default class ApplicationContext extends Context { getCurrentAppCloneIndex(): int { return this.nativegetCurrentAppCloneIndex(); } -} \ No newline at end of file + + static transferStatic(input: Any): Object { + let type: string = ''; + try { + type = ESValue.wrap(input).getProperty('__context_impl__').getProperty('contextType').toString(); + } catch (err) { + console.log('transferStatic err: ' + err.toString()); + } + console.log('transferStatic contextType: ' + type); + return ApplicationContext.nativeTransferStatic(ESValue.wrap(input), type); + } + + static transferDynamic(input: Object): Any { + return ApplicationContext.nativeTransferDynamic(input).unwrap(); + } +} diff --git a/frameworks/ets/ets/application/Context.ets b/frameworks/ets/ets/application/Context.ets index bafd64bf6e..4f54e84536 100644 --- a/frameworks/ets/ets/application/Context.ets +++ b/frameworks/ets/ets/application/Context.ets @@ -38,7 +38,9 @@ let unregisterToken = new object(); export class Context extends BaseContext { static { loadLibraryWithPermissionCheck("context_ani", "application.Context"); + loadLibraryWithPermissionCheck("context_ani_kit.z", "application.Context"); } + etsContextPtr: long = 0; private cleaner: Cleaner | null = null; filesDir: string = ""; @@ -72,6 +74,7 @@ export class Context extends BaseContext { unregisterCleaner(): void { destroyRegister.unregister(unregisterToken); } + public native getApplicationContextSync(): ApplicationContext; public native createModuleResourceManagerSync(bundleName: string, moduleName: string): resmgr.ResourceManager; private native switchArea(mode: contextConstant.AreaMode): void; @@ -80,6 +83,9 @@ export class Context extends BaseContext { public native nativeCreateDisplayContext(displayId: long): Context; public native nativeCreateAreaModeContext(areaMode: contextConstant.AreaMode): Context; public native nativeCreateSystemHspModuleResourceManager(bundleName: string, moduleName: string): resmgr.ResourceManager; + private static native nativeTransferStatic(input: ESValue, type: string): Object; + private static native nativeTransferDynamic(input: Object): ESValue; + private static contextType: string = 'Context'; getApplicationContext(): ApplicationContext { return this.getApplicationContextSync(); @@ -130,4 +136,19 @@ export class Context extends BaseContext { createSystemHspModuleResourceManager(bundleName: string, moduleName: string): resmgr.ResourceManager { return this.nativeCreateSystemHspModuleResourceManager(bundleName, moduleName); } + + static transferStatic(input: Any): Object { + let type: string = ''; + try { + type = ESValue.wrap(input).getProperty('__context_impl__').getProperty('contextType').toString(); + } catch (err) { + console.log('transferStatic err: ' + err.toString()); + } + console.log('transferStatic type: ' + type); + return Context.nativeTransferStatic(ESValue.wrap(input), type); + } + + static transferDynamic(input: Object): Any { + return Context.nativeTransferDynamic(input).unwrap(); + } }