From 925d86d4ce8376d17b472d4fd03850bbbf2f9bcf Mon Sep 17 00:00:00 2001 From: yangzk Date: Tue, 5 Aug 2025 18:12:39 +0800 Subject: [PATCH 1/5] =?UTF-8?q?Description:=20ui=20ability=20context?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20transfer=20IssueNo:=20#IBTG0R=20Sig:=20SIG?= =?UTF-8?q?=5FApplicationFramework=20Feature=20or=20Bugfix:=20Bugfix=20Bin?= =?UTF-8?q?ary=20Source:=20No?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangzk Change-Id: Id03b37a5c386503c5fe8a2229c15fdc810ae8580 --- frameworks/ets/ani/BUILD.gn | 1 + .../ets/ani/app/ability_context/BUILD.gn | 72 ++++ .../include/ets_ability_context_module.h | 52 +++ .../src/ets_ability_context_module.cpp | 387 ++++++++++++++++++ .../ets/ets/application/UIAbilityContext.ets | 19 + 5 files changed, 531 insertions(+) create mode 100644 frameworks/ets/ani/app/ability_context/BUILD.gn create mode 100644 frameworks/ets/ani/app/ability_context/include/ets_ability_context_module.h create mode 100644 frameworks/ets/ani/app/ability_context/src/ets_ability_context_module.cpp diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index 359adf59688..f1d215e0f12 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -22,6 +22,7 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/ani_wantagent_common:ani_wantagent_common", "${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/app/ability_context:ability_context_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/insight_intent/insight_intent_driver:insight_intent_driver_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/native_constructor:context_ani", "${ability_runtime_path}/frameworks/ets/ani/uri_permission_manager:uri_permission_manager_ani_kit", diff --git a/frameworks/ets/ani/app/ability_context/BUILD.gn b/frameworks/ets/ani/app/ability_context/BUILD.gn new file mode 100644 index 00000000000..5eb598fce09 --- /dev/null +++ b/frameworks/ets/ani/app/ability_context/BUILD.gn @@ -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. + +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_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_path}/interfaces/kits/native/ability/native/ability_runtime", + "${ability_runtime_services_path}/common/include", + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", + "${ability_runtime_path}/frameworks/ets/ani/ui_ability/include", + ] + + configs = [] + + public_configs = [] + + sources = [ "./src/ets_ability_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}/ability/native:abilitykit_native", + "${ability_runtime_native_path}/ability/native:ui_ability_ani", + "${ability_runtime_native_path}/ability:ability_context_native", + "${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_context/include/ets_ability_context_module.h b/frameworks/ets/ani/app/ability_context/include/ets_ability_context_module.h new file mode 100644 index 00000000000..46d7f78c5eb --- /dev/null +++ b/frameworks/ets/ani/app/ability_context/include/ets_ability_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_ABILITY_CONTEXT_MODULE_H +#define OHOS_ABILITY_RUNTIME_ETS_ABILITY_CONTEXT_MODULE_H + +#include +#include "ability_context.h" +#include "ani.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +class EtsAbilityContextModule { +public: + EtsAbilityContextModule() = default; + ~EtsAbilityContextModule() = default; + + EtsAbilityContextModule(const EtsAbilityContextModule&) = delete; + EtsAbilityContextModule(EtsAbilityContextModule&&) = delete; + EtsAbilityContextModule& operator=(const EtsAbilityContextModule&) = delete; + EtsAbilityContextModule& operator=(EtsAbilityContextModule&&) = 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 abilityContext); + +private: + static bool IsInstanceOf(ani_env *aniEnv, ani_object aniObj); + static std::unique_ptr CreateNativeReference(napi_env napiEnv, + std::shared_ptr abilityContext); + static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, + std::shared_ptr abilityContext); +}; + +void EtsAbilityContextModuleInit(ani_env *aniEnv); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_ABILITY_CONTEXT_MODULE_H diff --git a/frameworks/ets/ani/app/ability_context/src/ets_ability_context_module.cpp b/frameworks/ets/ani/app/ability_context/src/ets_ability_context_module.cpp new file mode 100644 index 00000000000..638c9a786b8 --- /dev/null +++ b/frameworks/ets/ani/app/ability_context/src/ets_ability_context_module.cpp @@ -0,0 +1,387 @@ +/* + * 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_context_module.h" + +#include +#include +#include +#include "ability_context.h" +#include "ani_base_context.h" +#include "ani_common_util.h" +#include "context_transfer.h" +#include "ets_ability_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_context.h" +#include "js_runtime_utils.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *ETS_ABILITY_CONTEXT_CLASS_NAME = "Lapplication/UIAbilityContext/UIAbilityContext;"; +} // namespace + +ani_object EtsAbilityContextModule::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 AbilityContext"); + 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 AbilityContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto abilityContext = Context::ConvertTo(context); + if (abilityContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid abilityContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + auto &bindingObj = abilityContext->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 abilityContext failed"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return newContext; +} + +std::unique_ptr EtsAbilityContextModule::CreateNativeReference(napi_env napiEnv, + std::shared_ptr abilityContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || abilityContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + auto value = CreateJsAbilityContext(napiEnv, abilityContext); + auto systemModule = JsRuntime::LoadSystemModuleByEngine(napiEnv, "application.AbilityContext", &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(abilityContext); + if (workContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null workContext"); + return nullptr; + } + auto status = napi_coerce_to_native_binding_object(napiEnv, object, DetachCallbackFunc, AttachJsUIAbilityContext, + workContext, nullptr); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CONTEXT, "coerce AbilityContext 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 AbilityContext"); + 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 EtsAbilityContextModule::GetOrCreateDynamicObject(napi_env napiEnv, + std::shared_ptr abilityContext) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + if (napiEnv == nullptr || abilityContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null param"); + return nullptr; + } + + // if sub-thread, create a new abilityContext and return + if (getpid() != syscall(SYS_gettid)) { + auto subThreadObj = static_cast( + abilityContext->GetSubThreadObject(static_cast(napiEnv))); + if (subThreadObj != nullptr) { + return subThreadObj->Get(); + } + auto subThreadRef = CreateNativeReference(napiEnv, abilityContext); + if (subThreadRef == nullptr) { + return nullptr; + } + auto newObject = subThreadRef->Get(); + abilityContext->BindSubThreadObject( + static_cast(napiEnv), static_cast(subThreadRef.release())); + return newObject; + } + + // if main-thread, get bindingObj firstly + auto &bindingObj = abilityContext->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, return null + return nullptr; +} + +ani_object EtsAbilityContextModule::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 AbilityContext"); + if (!IsInstanceOf(aniEnv, input)) { + TAG_LOGE(AAFwkTag::CONTEXT, "not AbilityContext"); + 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 abilityContext = Context::ConvertTo(context); + if (abilityContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid abilityContext"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + ani_object object = CreateDynamicObject(aniEnv, aniCls, abilityContext); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid object"); + EtsErrorUtil::ThrowEtsTransferClassError(aniEnv); + return nullptr; + } + + return object; +} + +ani_object EtsAbilityContextModule::CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, + std::shared_ptr abilityContext) +{ + 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 ability context + auto contextObj = ContextTransfer::GetInstance().GetDynamicObject(contextType, napiEnv, abilityContext); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "create AbilityContext 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 EtsAbilityContextModule::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_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 EtsAbilityContextModuleInit(ani_env *aniEnv) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "Init AbilityContext kit"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null ani env"); + return; + } + + ani_class abilityContextCls = nullptr; + auto status = aniEnv->FindClass(ETS_ABILITY_CONTEXT_CLASS_NAME, &abilityContextCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "FindClass AbilityContext failed status: %{public}d", status); + return; + } + + std::array nativeFuncs = { + ani_native_function { "nativeTransferStatic", "Lstd/interop/ESValue;Lstd/core/String;:Lstd/core/Object;", + reinterpret_cast(EtsAbilityContextModule::NativeTransferStatic) }, + ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;", + reinterpret_cast(EtsAbilityContextModule::NativeTransferDynamic) }, + }; + status = aniEnv->Class_BindNativeMethods(abilityContextCls, nativeFuncs.data(), nativeFuncs.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "Class_BindNativeMethods failed status: %{public}d", status); + return; + } + + ContextTransfer::GetInstance().RegisterStaticObjectCreator("UIAbilityContext", + [](ani_env *aniEnv, std::shared_ptr context) -> ani_object { + TAG_LOGE(AAFwkTag::APPKIT, "AbilityContext should be created during ability startup"); + return nullptr; + }); + + ContextTransfer::GetInstance().RegisterDynamicObjectCreator("UIAbilityContext", + [](napi_env napiEnv, std::shared_ptr context) -> napi_value { + auto abilityContext = Context::ConvertTo(context); + if (abilityContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "invalid abilityContext"); + return nullptr; + } + + auto object = EtsAbilityContextModule::GetOrCreateDynamicObject(napiEnv, abilityContext); + if (object == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "get or create object failed"); + return nullptr; + } + return object; + }); + + TAG_LOGD(AAFwkTag::CONTEXT, "Init AbilityContext 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; + } + + EtsAbilityContextModuleInit(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/UIAbilityContext.ets b/frameworks/ets/ets/application/UIAbilityContext.ets index cbc3c846776..af29923453f 100644 --- a/frameworks/ets/ets/application/UIAbilityContext.ets +++ b/frameworks/ets/ets/application/UIAbilityContext.ets @@ -45,6 +45,7 @@ let unregisterToken = new object(); export default class UIAbilityContext extends Context { static { loadLibraryWithPermissionCheck("context_ani", "application.UIAbilityContext"); + loadLibraryWithPermissionCheck("ability_context_ani_kit.z", "application.UIAbilityContext"); } private cleaner: Cleaner | null = null; @@ -80,6 +81,24 @@ export default class UIAbilityContext extends Context { destroyRegister.unregister(unregisterToken); } + private static native nativeTransferStatic(input: ESValue, type: string): Object; + private static native nativeTransferDynamic(input: Object): ESValue; + private static contextType: string = 'UIAbilityContext'; + + 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 UIAbilityContext.nativeTransferStatic(ESValue.wrap(input), type); + } + static transferDynamic(input: Object): Any { + return UIAbilityContext.nativeTransferDynamic(input).unwrap(); + } + private native nativeStartAbilitySync(want: Want, callback: AsyncCallbackWrapper): void; private native nativeStartAbilitySync(want: Want, options: StartOptions, callback: AsyncCallbackWrapper): void; -- Gitee From 813d7592fc71e895f0188d7c89f050335fa6cf7a Mon Sep 17 00:00:00 2001 From: "zhangyafei.echo" Date: Tue, 17 Jun 2025 23:34:56 +0800 Subject: [PATCH 2/5] 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 f1d215e0f12..8cc50323780 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -23,6 +23,9 @@ group("ani_packages") { "${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/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/insight_intent/insight_intent_driver:insight_intent_driver_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/native_constructor:context_ani", "${ability_runtime_path}/frameworks/ets/ani/uri_permission_manager:uri_permission_manager_ani_kit", 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 00000000000..238e2bca633 --- /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 00000000000..be39cb7c5f9 --- /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 00000000000..cb0d663bde7 --- /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 00000000000..34a117c9e10 --- /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 00000000000..bfd3117b4b1 --- /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 00000000000..758d122e746 --- /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 00000000000..81a953ec41c --- /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 00000000000..47343c4611f --- /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 00000000000..6fbecb0340e --- /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 93655dab825..5e2e9fa438b 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 c48da89fe52..c3b702e3ff6 100644 --- a/frameworks/ets/ets/application/ApplicationContext.ets +++ b/frameworks/ets/ets/application/ApplicationContext.ets @@ -38,6 +38,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; @@ -56,6 +60,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; @@ -66,6 +71,9 @@ export default class ApplicationContext extends Context { public native nativesetColorMode(colorMode: ConfigurationConstant.ColorMode): void; public native nativesetFont(font: string): void; public native nativerestartApp(want: Want): void; + 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); @@ -196,4 +204,19 @@ export default class ApplicationContext extends Context { restartApp(want: Want): void { this.nativerestartApp(want); } -} \ 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 3def579decc..11e9b986fe1 100644 --- a/frameworks/ets/ets/application/Context.ets +++ b/frameworks/ets/ets/application/Context.ets @@ -35,7 +35,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 = ""; @@ -64,10 +66,14 @@ 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; private native getArea(): contextConstant.AreaMode; + 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(); @@ -84,4 +90,19 @@ export class Context extends BaseContext { get area(): contextConstant.AreaMode { return this.getArea(); } + + 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(); + } } -- Gitee From 031a10a231cb2ea1b04c037eb3d8e87c0114d148 Mon Sep 17 00:00:00 2001 From: yangzk Date: Sat, 19 Jul 2025 16:27:29 +0800 Subject: [PATCH 3/5] Description:add want param Sig:SIG_ApplicationFramework Feature or BugFix: Feature Binary Source: No Signed-off-by: yangzk Change-Id: Ie487f29e5dc9419ae4d6792f2796e0c51f5b078e --- frameworks/ets/ani/BUILD.gn | 1 + frameworks/ets/ani/want/BUILD.gn | 57 ++ .../ets/ani/want/include/ani_want_module.h | 74 ++ .../ets/ani/want/src/ani_want_module.cpp | 763 ++++++++++++++++++ frameworks/ets/ets/@ohos.app.ability.Want.ets | 172 ++++ 5 files changed, 1067 insertions(+) create mode 100644 frameworks/ets/ani/want/BUILD.gn create mode 100644 frameworks/ets/ani/want/include/ani_want_module.h create mode 100644 frameworks/ets/ani/want/src/ani_want_module.cpp diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index 8cc50323780..930cb3e639c 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -30,6 +30,7 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/native_constructor:context_ani", "${ability_runtime_path}/frameworks/ets/ani/uri_permission_manager:uri_permission_manager_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/vertical_panel_manager:vertical_panel_manager_ani_kit", + "${ability_runtime_path}/frameworks/ets/ani/want:want_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/wantagent:aniwantagent", ] } diff --git a/frameworks/ets/ani/want/BUILD.gn b/frameworks/ets/ani/want/BUILD.gn new file mode 100644 index 00000000000..51e2f6360d1 --- /dev/null +++ b/frameworks/ets/ani/want/BUILD.gn @@ -0,0 +1,57 @@ +# 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") + +ohos_shared_library("want_ani_kit") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + branch_protector_ret = "pac_ret" + + include_dirs = [ + "./include", + "${ability_runtime_services_path}/common/include", + ] + + sources = [ "src/ani_want_module.cpp" ] + + deps = [ + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + external_deps = [ + "ability_base:want", + "ability_base:base", + "c_utils:utils", + "hilog:libhilog", + "ipc:rpc_ani", + "runtime_core:ani", + ] + + cflags_cc = [] + if (os_dlp_part_enabled) { + cflags_cc += [ "-DWITH_DLP" ] + } + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/ets/ani/want/include/ani_want_module.h b/frameworks/ets/ani/want/include/ani_want_module.h new file mode 100644 index 00000000000..ee520b43361 --- /dev/null +++ b/frameworks/ets/ani/want/include/ani_want_module.h @@ -0,0 +1,74 @@ +/* + * 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_ANI_WANT_MODULE_H +#define OHOS_ABILITY_RUNTIME_ANI_WANT_MODULE_H + +#include "ani.h" +#include "want_params.h" + +namespace OHOS::AppExecFwk { +class EtsWantParams { +public: + EtsWantParams() = default; + ~EtsWantParams() = default; + + static ani_long NativeCreate(ani_env *env, ani_object); + static void NativeDestroy(ani_env *env, ani_object, ani_long nativeWantParams); + static ani_boolean NativeSetStringParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_string value); + static ani_boolean NativeSetDoubleParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_double value); + static ani_boolean NativeSetIntParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_int value); + static ani_boolean NativeSetLongParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_long value); + static ani_boolean NativeSetBooleanParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_boolean value); + static ani_boolean NativeSetWantParams(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_long value); + + static ani_boolean NativeSetArrayStringParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_object value); + static ani_boolean NativeSetArrayDoubleParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_object value); + static ani_boolean NativeSetArrayIntParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_object value); + static ani_boolean NativeSetArrayLongParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_object value); + static ani_boolean NativeSetArrayBooleanParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_object value); + static ani_boolean NativeSetArrayWantParams(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_object value); + + static ani_boolean NativeSetRemoteObjectParam(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value); + +private: + static bool SetArrayString(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams& wantParams); + static bool SetArrayDouble(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams& wantParams); + static bool SetArrayInt(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams& wantParams); + static bool SetArrayLong(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams& wantParams); + static bool SetArrayBoolean(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams& wantParams); + static bool SetArrayWantParams(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams& wantParams); +}; +} // namespace OHOS::AppExecFwk +#endif // OHOS_ABILITY_RUNTIME_ANI_WANT_MODULE_H diff --git a/frameworks/ets/ani/want/src/ani_want_module.cpp b/frameworks/ets/ani/want/src/ani_want_module.cpp new file mode 100644 index 00000000000..1726c10222d --- /dev/null +++ b/frameworks/ets/ani/want/src/ani_want_module.cpp @@ -0,0 +1,763 @@ +/* + * 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 "ani_want_module.h" + +#include "ani_common_util.h" +#include "ani_remote_object.h" +#include "array_wrapper.h" +#include "bool_wrapper.h" +#include "double_wrapper.h" +#include "hilog_tag_wrapper.h" +#include "int_wrapper.h" +#include "long_wrapper.h" +#include "remote_object_wrapper.h" +#include "string_wrapper.h" +#include "want_params.h" +#include "want_params_wrapper.h" + +namespace OHOS::AppExecFwk { +namespace { +constexpr const char *ETS_NATIVE_WANT_PARAMS_CLASS_NAME = "L@ohos/app/ability/Want/NativeWantParams;"; +constexpr const char *ETS_NATIVE_WANT_PARAMS_CLEANER_CLASS_NAME = "L@ohos/app/ability/Want/NativeWantParamsCleaner;"; +} // namespace + +ani_long EtsWantParams::NativeCreate(ani_env *env, ani_object) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return 0; + } + auto *params = new(std::nothrow) AAFwk::WantParams(); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null params"); + return 0; + } + + return reinterpret_cast(params); +} + +void EtsWantParams::NativeDestroy(ani_env *env, ani_object, ani_long nativeWantParams) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return; + } + + delete params; +} + +ani_boolean EtsWantParams::NativeSetStringParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_string value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + std::string valueString; + if (!GetStdString(env, value, valueString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + params->SetParam(keyString, AAFwk::String::Box(valueString)); + return true; +} + +ani_boolean EtsWantParams::NativeSetDoubleParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_double value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + params->SetParam(keyString, AAFwk::Double::Box(value)); + return true; +} + +ani_boolean EtsWantParams::NativeSetIntParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_int value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + params->SetParam(keyString, AAFwk::Integer::Box(value)); + return true; +} + +ani_boolean EtsWantParams::NativeSetLongParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_long value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + params->SetParam(keyString, AAFwk::Long::Box(value)); + return true; +} + +ani_boolean EtsWantParams::NativeSetBooleanParam(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_boolean value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + params->SetParam(keyString, AAFwk::Boolean::Box(value)); + return true; +} + +ani_boolean EtsWantParams::NativeSetWantParams(ani_env *env, ani_object, ani_long nativeWantParams, ani_string key, + ani_long value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + auto *valueWantParams = reinterpret_cast(value); + if (valueWantParams == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null valueWantParams"); + return false; + } + + params->SetParam(keyString, AAFwk::WantParamWrapper::Box(*valueWantParams)); + return true; +} + +bool EtsWantParams::SetArrayString(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams &wantParams) +{ + ani_boolean isUndefined = true; + ani_status status = env->Reference_IsUndefined(value, &isUndefined); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Reference_IsUndefined status: %{public}d", status); + return false; + } + if (isUndefined) { + TAG_LOGE(AAFwkTag::WANT, "value is undefined"); + return false; + } + + ani_double valLength = 0.0; + status = env->Object_GetPropertyByName_Double(value, "length", &valLength); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Object_GetPropertyByName_Double status: %{public}d", status); + return false; + } + int32_t length = static_cast(valLength); + sptr ao = sptr::MakeSptr(length, AAFwk::g_IID_IString); + + for (int i = 0; i < length; i++) { + ani_ref itemRef; + status = env->Object_CallMethodByName_Ref(value, "$_get", "I:Lstd/core/Object;", &itemRef, i); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "status: %{public}d, index: %{public}d", status, i); + return false; + } + + std::string item; + if (!GetStdString(env, reinterpret_cast(itemRef), item)) { + TAG_LOGE(AAFwkTag::WANT, "GetStdString failed, index: %{public}d", i); + return false; + } + ao->Set(i, AAFwk::String::Box(item)); + } + wantParams.SetParam(key, ao); + return true; +} + +ani_boolean EtsWantParams::NativeSetArrayStringParam(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + return SetArrayString(env, keyString, value, *params); +} + +bool EtsWantParams::SetArrayDouble(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams &wantParams) +{ + ani_boolean isUndefined = true; + ani_status status = env->Reference_IsUndefined(value, &isUndefined); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Reference_IsUndefined status: %{public}d", status); + return false; + } + if (isUndefined) { + TAG_LOGE(AAFwkTag::WANT, "value is undefined"); + return false; + } + + ani_double valLength = 0.0; + status = env->Object_GetPropertyByName_Double(value, "length", &valLength); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Object_GetPropertyByName_Double status: %{public}d", status); + return false; + } + int32_t length = static_cast(valLength); + + auto array = reinterpret_cast(value); + std::vector nativeArray(length); + status = env->Array_GetRegion_Double(array, 0, length, nativeArray.data()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Array_GetRegion_Double status: %{public}d", status); + return false; + } + + sptr ao = sptr::MakeSptr(length, AAFwk::g_IID_IDouble); + for (int i = 0; i < length; i++) { + ao->Set(i, AAFwk::Double::Box(nativeArray[i])); + } + wantParams.SetParam(key, ao); + return true; +} + +ani_boolean EtsWantParams::NativeSetArrayDoubleParam(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + return SetArrayDouble(env, keyString, value, *params); +} + +bool EtsWantParams::SetArrayInt(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams &wantParams) +{ + ani_boolean isUndefined = true; + ani_status status = env->Reference_IsUndefined(value, &isUndefined); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Reference_IsUndefined status: %{public}d", status); + return false; + } + if (isUndefined) { + TAG_LOGE(AAFwkTag::WANT, "value is undefined"); + return false; + } + + ani_double valLength = 0.0; + status = env->Object_GetPropertyByName_Double(value, "length", &valLength); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Object_GetPropertyByName_Double status: %{public}d", status); + return false; + } + int32_t length = static_cast(valLength); + + auto array = reinterpret_cast(value); + std::vector nativeArray(length); + status = env->Array_GetRegion_Int(array, 0, length, nativeArray.data()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Array_GetRegion_Int status: %{public}d", status); + return false; + } + + sptr ao = sptr::MakeSptr(length, AAFwk::g_IID_IInteger); + for (int i = 0; i < length; i++) { + ao->Set(i, AAFwk::Integer::Box(nativeArray[i])); + } + wantParams.SetParam(key, ao); + return true; +} + +ani_boolean EtsWantParams::NativeSetArrayIntParam(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + return SetArrayInt(env, keyString, value, *params); +} + +bool EtsWantParams::SetArrayLong(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams &wantParams) +{ + ani_boolean isUndefined = true; + ani_status status = env->Reference_IsUndefined(value, &isUndefined); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Reference_IsUndefined status: %{public}d", status); + return false; + } + if (isUndefined) { + TAG_LOGE(AAFwkTag::WANT, "value is undefined"); + return false; + } + + ani_double valLength = 0.0; + status = env->Object_GetPropertyByName_Double(value, "length", &valLength); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Object_GetPropertyByName_Double status: %{public}d", status); + return false; + } + int32_t length = static_cast(valLength); + + auto array = reinterpret_cast(value); + std::vector nativeArray(length); + status = env->Array_GetRegion_Long(array, 0, length, nativeArray.data()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Array_GetRegion_Long status: %{public}d", status); + return false; + } + + sptr ao = sptr::MakeSptr(length, AAFwk::g_IID_ILong); + for (int i = 0; i < length; i++) { + ao->Set(i, AAFwk::Long::Box(nativeArray[i])); + } + wantParams.SetParam(key, ao); + return true; +} + +ani_boolean EtsWantParams::NativeSetArrayLongParam(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + return SetArrayLong(env, keyString, value, *params); +} + +bool EtsWantParams::SetArrayBoolean(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams &wantParams) +{ + ani_boolean isUndefined = true; + ani_status status = env->Reference_IsUndefined(value, &isUndefined); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Reference_IsUndefined status: %{public}d", status); + return false; + } + if (isUndefined) { + TAG_LOGE(AAFwkTag::WANT, "value is undefined"); + return false; + } + + ani_double valLength = 0.0; + status = env->Object_GetPropertyByName_Double(value, "length", &valLength); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Object_GetPropertyByName_Double status: %{public}d", status); + return false; + } + int32_t length = static_cast(valLength); + + auto array = reinterpret_cast(value); + std::vector nativeArray(length); + status = env->Array_GetRegion_Boolean(array, 0, length, nativeArray.data()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Array_GetRegion_Boolean status: %{public}d", status); + return false; + } + + sptr ao = sptr::MakeSptr(length, AAFwk::g_IID_IBoolean); + for (int i = 0; i < length; i++) { + ao->Set(i, AAFwk::Boolean::Box(nativeArray[i])); + } + wantParams.SetParam(key, ao); + return true; +} + +ani_boolean EtsWantParams::NativeSetArrayBooleanParam(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + return SetArrayBoolean(env, keyString, value, *params); +} + +bool EtsWantParams::SetArrayWantParams(ani_env *env, const std::string &key, ani_object value, + AAFwk::WantParams &wantParams) +{ + ani_boolean isUndefined = true; + ani_status status = env->Reference_IsUndefined(value, &isUndefined); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Reference_IsUndefined status: %{public}d", status); + return false; + } + if (isUndefined) { + TAG_LOGE(AAFwkTag::WANT, "value is undefined"); + return false; + } + + ani_double valLength = 0.0; + status = env->Object_GetPropertyByName_Double(value, "length", &valLength); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Object_GetPropertyByName_Double status: %{public}d", status); + return false; + } + int32_t length = static_cast(valLength); + + auto array = reinterpret_cast(value); + std::vector nativeArray(length); + status = env->Array_GetRegion_Long(array, 0, length, nativeArray.data()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Array_GetRegion_Long status: %{public}d", status); + return false; + } + + sptr ao = sptr::MakeSptr(length, AAFwk::g_IID_IWantParams); + for (int i = 0; i < length; i++) { + auto *params = reinterpret_cast(nativeArray[i]); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + ao->Set(i, AAFwk::WantParamWrapper::Box(*params)); + } + wantParams.SetParam(key, ao); + return true; +} + +ani_boolean EtsWantParams::NativeSetArrayWantParams(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + return SetArrayWantParams(env, keyString, value, *params); +} + +ani_boolean EtsWantParams::NativeSetRemoteObjectParam(ani_env *env, ani_object, ani_long nativeWantParams, + ani_string key, ani_object value) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null env"); + return false; + } + + auto *params = reinterpret_cast(nativeWantParams); + if (params == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null nativeWantParams"); + return false; + } + + std::string keyString; + if (!GetStdString(env, key, keyString)) { + TAG_LOGE(AAFwkTag::WANT, "get key failed"); + return false; + } + + auto remoteObject = AniGetNativeRemoteObject(env, value); + if (remoteObject == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null remoteObject"); + return false; + } + params->SetParam(keyString, AAFwk::RemoteObjectWrap::Box(remoteObject)); + return true; +} + +ani_status BindNativeFunctions(ani_env *aniEnv) +{ + TAG_LOGD(AAFwkTag::WANT, "call"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null ani env"); + return ANI_INVALID_ARGS; + } + + ani_class nativeWantParamsCls = nullptr; + auto status = aniEnv->FindClass(ETS_NATIVE_WANT_PARAMS_CLASS_NAME, &nativeWantParamsCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "FindClass NativeWantParams failed status: %{public}d", status); + return status; + } + + std::array nativeFuncs = { + ani_native_function{ + "nativeCreate", ":J", + reinterpret_cast(EtsWantParams::NativeCreate) + }, + ani_native_function{ + "nativeSetStringParam", "JLstd/core/String;Lstd/core/String;:Z", + reinterpret_cast(EtsWantParams::NativeSetStringParam) + }, + ani_native_function{ + "nativeSetDoubleParam", "JLstd/core/String;D:Z", + reinterpret_cast(EtsWantParams::NativeSetDoubleParam) + }, + ani_native_function{ + "nativeSetIntParam", "JLstd/core/String;I:Z", + reinterpret_cast(EtsWantParams::NativeSetIntParam) + }, + ani_native_function{ + "nativeSetLongParam", "JLstd/core/String;J:Z", + reinterpret_cast(EtsWantParams::NativeSetLongParam) + }, + ani_native_function{ + "nativeSetBooleanParam", "JLstd/core/String;Z:Z", + reinterpret_cast(EtsWantParams::NativeSetBooleanParam) + }, + ani_native_function{ + "nativeSetWantParams", "JLstd/core/String;J:Z", + reinterpret_cast(EtsWantParams::NativeSetWantParams) + }, + ani_native_function{ + "nativeSetArrayStringParam", "JLstd/core/String;Lescompat/Array;:Z", + reinterpret_cast(EtsWantParams::NativeSetArrayStringParam) + }, + ani_native_function{ + "nativeSetArrayDoubleParam", "JLstd/core/String;Lescompat/Array;:Z", + reinterpret_cast(EtsWantParams::NativeSetArrayDoubleParam) + }, + ani_native_function{ + "nativeSetArrayIntParam", "JLstd/core/String;Lescompat/Array;:Z", + reinterpret_cast(EtsWantParams::NativeSetArrayIntParam) + }, + ani_native_function{ + "nativeSetArrayLongParam", "JLstd/core/String;Lescompat/Array;:Z", + reinterpret_cast(EtsWantParams::NativeSetArrayLongParam) + }, + ani_native_function{ + "nativeSetArrayBooleanParam", "JLstd/core/String;Lescompat/Array;:Z", + reinterpret_cast(EtsWantParams::NativeSetArrayBooleanParam) + }, + ani_native_function{ + "nativeSetArrayWantParams", "JLstd/core/String;Lescompat/Array;:Z", + reinterpret_cast(EtsWantParams::NativeSetArrayWantParams) + }, + ani_native_function{ + "nativeSetRemoteObjectParam", "JLstd/core/String;L@ohos/rpc/rpc/RemoteObject;:Z", + reinterpret_cast(EtsWantParams::NativeSetRemoteObjectParam) + }, + }; + status = aniEnv->Class_BindNativeMethods(nativeWantParamsCls, nativeFuncs.data(), nativeFuncs.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Class_BindNativeMethods failed status: %{public}d", status); + return status; + } + + ani_class nativeWantParamsCleanerCls = nullptr; + status = aniEnv->FindClass(ETS_NATIVE_WANT_PARAMS_CLEANER_CLASS_NAME, &nativeWantParamsCleanerCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "FindClass NativeWantParams failed status: %{public}d", status); + return status; + } + std::array cleanerNativeFuncs = { + ani_native_function{ + "nativeDestroy", "J:V", + reinterpret_cast(EtsWantParams::NativeDestroy) + }, + }; + status = aniEnv->Class_BindNativeMethods(nativeWantParamsCleanerCls, cleanerNativeFuncs.data(), + cleanerNativeFuncs.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "Class_BindNativeMethods failed status: %{public}d", status); + return status; + } + return ANI_OK; +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::WANT, "ANI_Constructor"); + ani_env *env = nullptr; + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "null vm"); + return ANI_NOT_FOUND; + } + ani_status status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK || env == nullptr) { + TAG_LOGE(AAFwkTag::WANT, "GetEnv failed status: %{public}d, or null env", status); + return status; + } + if ((status = BindNativeFunctions(env)) != ANI_OK) { + TAG_LOGE(AAFwkTag::WANT, "BindNativeFunctions failed status: %{public}d", status); + return status; + } + *result = ANI_VERSION_1; + return ANI_OK; +} +} +} // namespace OHOS::AppExecFwk diff --git a/frameworks/ets/ets/@ohos.app.ability.Want.ets b/frameworks/ets/ets/@ohos.app.ability.Want.ets index 2d81ad45d82..4a61767d1c8 100644 --- a/frameworks/ets/ets/@ohos.app.ability.Want.ets +++ b/frameworks/ets/ets/@ohos.app.ability.Want.ets @@ -14,6 +14,7 @@ */ import hilog from '@ohos.hilog' +import rpc from '@ohos.rpc'; type valueType = NullishType; const DOMAIN_ID = 0xD001300; @@ -218,6 +219,177 @@ export class RecordSerializeTool { } } +class NativeWantParamsCleaner { + public nativeWantParams: long = 0; + + constructor(nativeWantParams: long) { + this.nativeWantParams = nativeWantParams; + } + + private static native nativeDestroy(nativeWantParams: long): void; + + public clean(): void { + NativeWantParamsCleaner.nativeDestroy(this.nativeWantParams); + this.nativeWantParams = 0; + } +} + +function nativeWantParamsCleanerCallback(cleaner: NativeWantParamsCleaner): void { + cleaner.clean(); +} + +let destroyRegister = new FinalizationRegistry(nativeWantParamsCleanerCallback); + +class NativeWantParams { + static { + loadLibrary("want_ani_kit.z"); + } + + private nativeWantParams: long = 0; + private cleaner: NativeWantParamsCleaner | null = null; + + constructor(wantParams?: long) { + if (wantParams === undefined) { + this.nativeWantParams = NativeWantParams.nativeCreate(); + this.registerCleaner(this.nativeWantParams) + return; + } + this.nativeWantParams = wantParams; + } + + private static native nativeCreate(): long; + + private static native nativeSetStringParam(nativeWantParams: long, key: string, value: string): boolean; + private static native nativeSetDoubleParam(nativeWantParams: long, key: string, value: double): boolean; + private static native nativeSetIntParam(nativeWantParams: long, key: string, value: int): boolean; + private static native nativeSetLongParam(nativeWantParams: long, key: string, value: long): boolean; + private static native nativeSetBooleanParam(nativeWantParams: long, key: string, value: boolean): boolean; + private static native nativeSetWantParams(nativeWantParams: long, key: string, value: long): boolean; + + private static native nativeSetArrayStringParam(nativeWantParams: long, key: string, value: Array): boolean; + private static native nativeSetArrayDoubleParam(nativeWantParams: long, key: string, value: Array): boolean; + private static native nativeSetArrayIntParam(nativeWantParams: long, key: string, value: Array): boolean; + private static native nativeSetArrayLongParam(nativeWantParams: long, key: string, value: Array): boolean; + private static native nativeSetArrayBooleanParam(nativeWantParams: long, key: string, value: Array): boolean; + private static native nativeSetArrayWantParams(nativeWantParams: long, key: string, value: Array): boolean; + + private static native nativeSetRemoteObjectParam( + nativeWantParams: long, key: string, value: rpc.RemoteObject): boolean; + + private registerCleaner(nativeWantParams: long): void { + this.cleaner = new NativeWantParamsCleaner(nativeWantParams); + destroyRegister.register(this, this.cleaner!, this); + } + + public setParam(key: string, value: string): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetStringParam(this.nativeWantParams, key, value); + } + + public setParam(key: string, value: double): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetDoubleParam(this.nativeWantParams, key, value); + } + + public setParam(key: string, value: int): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetIntParam(this.nativeWantParams, key, value); + } + + public setParam(key: string, value: long): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetLongParam(this.nativeWantParams, key, value); + } + + public setParam(key: string, value: boolean): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetBooleanParam(this.nativeWantParams, key, value); + } + + public setParam(key: string, value: NativeWantParams): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetWantParams(this.nativeWantParams, key, value.nativeWantParams); + } + + public SetArrayStringParam(key: string, value: Array): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetArrayStringParam(this.nativeWantParams, key, value); + } + + public SetArrayDoubleParam(key: string, value: Array): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetArrayDoubleParam(this.nativeWantParams, key, value); + } + + public SetArrayIntParam(key: string, value: Array): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetArrayIntParam(this.nativeWantParams, key, value); + } + + public SetArrayLongParam(key: string, value: Array): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetArrayLongParam(this.nativeWantParams, key, value); + } + + public SetArrayBooleanParam(key: string, value: Array): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetArrayBooleanParam(this.nativeWantParams, key, value); + } + + public SetArrayWantParams(key: string, value: Array): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + let nativeWantParams: Array = new Array(); + for (let item of value) { + nativeWantParams.push(item.nativeWantParams); + } + return NativeWantParams.nativeSetArrayWantParams(this.nativeWantParams, key, nativeWantParams); + } + + public setParam(key: string, value: rpc.RemoteObject): boolean { + if (this.nativeWantParams == 0) { + hilog.error(DOMAIN_ID, TAG, `nativeWantParams null`); + return false; + } + return NativeWantParams.nativeSetRemoteObjectParam(this.nativeWantParams, key, value); + } +} + export default class Want { bundleName?: string; abilityName?: string; -- Gitee From ea36388a447156dc57382b41d6579fafe1e354f4 Mon Sep 17 00:00:00 2001 From: yangzk Date: Tue, 29 Jul 2025 17:33:58 +0800 Subject: [PATCH 4/5] Description:add wrap want param Sig:SIG_ApplicationFramework Feature or BugFix: Feature Binary Source: No Signed-off-by: yangzk Change-Id: Ie487f29e5dc9419ae4d6792f2796e0c51f5b078e --- frameworks/ets/ani/ani_common/BUILD.gn | 1 + .../ani/ani_common/src/ani_common_want.cpp | 1018 ++++++++++++++++- 2 files changed, 985 insertions(+), 34 deletions(-) diff --git a/frameworks/ets/ani/ani_common/BUILD.gn b/frameworks/ets/ani/ani_common/BUILD.gn index 12fe1f08f4f..6b5ab09c751 100644 --- a/frameworks/ets/ani/ani_common/BUILD.gn +++ b/frameworks/ets/ani/ani_common/BUILD.gn @@ -89,6 +89,7 @@ ohos_shared_library("ani_common") { "hilog:libhilog", "hitrace:hitrace_meter", "image_framework:image_ani", + "ipc:rpc_ani", "ipc:ipc_core", "ipc:ipc_napi", "json:nlohmann_json_static", diff --git a/frameworks/ets/ani/ani_common/src/ani_common_want.cpp b/frameworks/ets/ani/ani_common/src/ani_common_want.cpp index d0bb2b35e68..773c44c98aa 100644 --- a/frameworks/ets/ani/ani_common/src/ani_common_want.cpp +++ b/frameworks/ets/ani/ani_common/src/ani_common_want.cpp @@ -15,6 +15,7 @@ #include "ani_common_want.h" #include "ani_common_util.h" +#include "ani_remote_object.h" #include "array_wrapper.h" #include "bool_wrapper.h" #include "byte_wrapper.h" @@ -37,12 +38,15 @@ namespace OHOS { namespace AppExecFwk { using namespace OHOS::AbilityRuntime; namespace { -constexpr const char* ABILITY_WANT_CLASS_NAME = "L@ohos/app/ability/Want/Want;"; -constexpr const char* TOOL_CLASS_NAME = "L@ohos/app/ability/Want/RecordSerializeTool;"; -constexpr const char* INNER_CLASS_NAME = "Lability/abilityResult/AbilityResultInner;"; -constexpr const char* ELEMENTNAME_CLASS_NAME = "LbundleManager/ElementNameInner/ElementNameInner;"; +constexpr const char *ABILITY_WANT_CLASS_NAME = "L@ohos/app/ability/Want/Want;"; +constexpr const char *TOOL_CLASS_NAME = "L@ohos/app/ability/Want/RecordSerializeTool;"; +constexpr const char *INNER_CLASS_NAME = "Lability/abilityResult/AbilityResultInner;"; +constexpr const char *ELEMENTNAME_CLASS_NAME = "LbundleManager/ElementNameInner/ElementNameInner;"; +constexpr const char *RECORD_CLASS_NAME = "Lescompat/Record;"; +constexpr const char *RECORD_SET_NAME = + "X{C{std.core.Numeric}C{std.core.String}C{std.core.BaseEnum}}C{std.core.Object}:"; -bool InnerWrapWantParams(ani_env* env, ani_class wantCls, ani_object wantObject, const AAFwk::WantParams& wantParams) +bool InnerWrapWantParams(ani_env *env, ani_class wantCls, ani_object wantObject, const AAFwk::WantParams &wantParams) { ani_ref wantParamRef = WrapWantParams(env, wantParams); if (wantParamRef == nullptr) { @@ -52,7 +56,7 @@ bool InnerWrapWantParams(ani_env* env, ani_class wantCls, ani_object wantObject, return SetFieldRefByName(env, wantCls, wantObject, "parameters", wantParamRef); } -bool InnerUnwrapWantParams(ani_env* env, ani_object wantObject, AAFwk::WantParams& wantParams) +bool InnerUnwrapWantParams(ani_env *env, ani_object wantObject, AAFwk::WantParams &wantParams) { ani_ref wantParamRef = nullptr; if (!GetFieldRefByName(env, wantObject, "parameters", wantParamRef)) { @@ -61,6 +65,946 @@ bool InnerUnwrapWantParams(ani_env* env, ani_object wantObject, AAFwk::WantParam } return UnwrapWantParams(env, wantParamRef, wantParams); } + +bool InnerCreateRecordObject(ani_env *env, ani_object &recordObject) +{ + ani_class recordCls = nullptr; + ani_method recordCtorMethod = nullptr; + ani_status status = env->FindClass(RECORD_CLASS_NAME, &recordCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(recordCls, "", ":V", &recordCtorMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + return false; + } + status = env->Object_New(recordCls, recordCtorMethod, &recordObject); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); + return false; + } + return true; +} + +bool InnerSetRecord(ani_env *env, ani_object recordObject, ani_string key, ani_object value) +{ + ani_class recordCls = nullptr; + ani_method recordSetMethod = nullptr; + ani_status status = env->FindClass(RECORD_CLASS_NAME, &recordCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(recordCls, "$_set", RECORD_SET_NAME, &recordSetMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod set failed: %{public}d", status); + return false; + } + + status = env->Object_CallMethod_Void(recordObject, recordSetMethod, key, value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_CallMethod_Void failed status: %{public}d", status); + return false; + } + return true; +} + +bool InnerWrapWantParamsString( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IString *ao = AAFwk::IString::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + std::string natValue = AAFwk::String::Unbox(ao); + ani_string aniValue = GetAniString(env, natValue); + if (aniValue == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "value GetAniString failed"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerCreateBooleanObject(ani_env *env, ani_boolean value, ani_object &object) +{ + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_status status = env->FindClass("Lstd/core/Boolean;", &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(cls, "", "Z:V", &ctorMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + return false; + } + status = env->Object_New(cls, ctorMethod, &object, value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); + return false; + } + return true; +} + +bool InnerWrapWantParamsBool( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IBoolean *ao = AAFwk::IBoolean::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + ani_boolean natValue = AAFwk::Boolean::Unbox(ao); + ani_object aniValue = nullptr; + if (!InnerCreateBooleanObject(env, natValue, aniValue)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create object"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerCreateShortObject(ani_env *env, ani_short value, ani_object &object) +{ + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_status status = env->FindClass("Lstd/core/Short;", &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(cls, "", "S:V", &ctorMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + return false; + } + status = env->Object_New(cls, ctorMethod, &object, value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); + return false; + } + return true; +} + +bool InnerWrapWantParamsShort( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IShort *ao = AAFwk::IShort::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + ani_short natValue = AAFwk::Short::Unbox(ao); + ani_object aniValue = nullptr; + if (!InnerCreateShortObject(env, natValue, aniValue)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create object"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerCreateIntObject(ani_env *env, ani_int value, ani_object &object) +{ + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_status status = env->FindClass("Lstd/core/Int;", &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(cls, "", "I:V", &ctorMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + return false; + } + status = env->Object_New(cls, ctorMethod, &object, value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); + return false; + } + return true; +} + +bool InnerWrapWantParamsInt32( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IInteger *ao = AAFwk::IInteger::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + ani_int natValue = AAFwk::Integer::Unbox(ao); + ani_object aniValue = nullptr; + if (!InnerCreateIntObject(env, natValue, aniValue)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create object"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerCreateLongObject(ani_env *env, ani_long value, ani_object &object) +{ + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_status status = env->FindClass("Lstd/core/Long;", &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(cls, "", "J:V", &ctorMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + return false; + } + status = env->Object_New(cls, ctorMethod, &object, value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); + return false; + } + return true; +} + +bool InnerWrapWantParamsInt64( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::ILong *ao = AAFwk::ILong::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + ani_long natValue = AAFwk::Long::Unbox(ao); + ani_object aniValue = nullptr; + if (!InnerCreateLongObject(env, natValue, aniValue)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create object"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerCreateFloatObject(ani_env *env, ani_float value, ani_object &object) +{ + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_status status = env->FindClass("Lstd/core/Float;", &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(cls, "", "F:V", &ctorMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + return false; + } + status = env->Object_New(cls, ctorMethod, &object, value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); + return false; + } + return true; +} + +bool InnerWrapWantParamsFloat( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IFloat *ao = AAFwk::IFloat::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + ani_float natValue = AAFwk::Float::Unbox(ao); + ani_object aniValue = nullptr; + if (!InnerCreateFloatObject(env, natValue, aniValue)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create object"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerCreateDoubleObject(ani_env *env, ani_double value, ani_object &object) +{ + ani_class cls = nullptr; + ani_method ctorMethod = nullptr; + ani_status status = env->FindClass("Lstd/core/Double;", &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + return false; + } + status = env->Class_FindMethod(cls, "", "D:V", &ctorMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + return false; + } + status = env->Object_New(cls, ctorMethod, &object, value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); + return false; + } + return true; +} + +bool InnerWrapWantParamsDouble( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IDouble *ao = AAFwk::IDouble::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + ani_double natValue = AAFwk::Double::Unbox(ao); + ani_object aniValue = nullptr; + if (!InnerCreateDoubleObject(env, natValue, aniValue)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create object"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerWrapWantParamsChar( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IChar *ao = AAFwk::IChar::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + std::string natValue = static_cast(ao)->ToString(); + ani_string aniValue = GetAniString(env, natValue); + if (aniValue == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "value GetAniString failed"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerWrapWantParamsByte( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IByte *ao = AAFwk::IByte::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + ani_int natValue = AAFwk::Byte::Unbox(ao); + ani_object aniValue = nullptr; + if (!InnerCreateIntObject(env, natValue, aniValue)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create object"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerWrapWantParamsWantParams( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IWantParams *ao = AAFwk::IWantParams::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + AAFwk::WantParams natValue = AAFwk::WantParamWrapper::Unbox(ao); + ani_ref aniValue = WrapWantParams(env, natValue); + if (aniValue == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null aniValue"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, reinterpret_cast(aniValue)); +} + +bool InnerWrapWantParamsRemoteObject( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + AAFwk::IRemoteObjectWrap *ao = AAFwk::IRemoteObjectWrap::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + auto remoteObject = AAFwk::RemoteObjectWrap::UnBox(ao); + ani_object aniValue = ANI_ohos_rpc_CreateJsRemoteObject(env, remoteObject); + if (aniValue == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null aniValue"); + return false; + } + return InnerSetRecord(env, recordObject, aniKey, aniValue); +} + +bool InnerSetArrayString(ani_env *env, ani_object recordObject, ani_string aniKey, + const std::vector &natArray) +{ + ani_class stringCls = nullptr; + ani_status status = env->FindClass("Lstd/core/String;", &stringCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed, status: %{public}d", status); + return false; + } + ani_ref undefinedRef = nullptr; + status = env->GetUndefined(&undefinedRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetUndefined failed, status: %{public}d", status); + return false; + } + ani_array_ref refArray = nullptr; + status = env->Array_New_Ref(stringCls, natArray.size(), undefinedRef, &refArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + for (size_t i = 0; i < natArray.size(); i++) { + ani_string aniValue = GetAniString(env, natArray[i]); + if (aniValue == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "value GetAniString failed"); + continue; + } + status = env->Array_Set_Ref(refArray, i, aniValue); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_Set_Ref failed, status: %{public}d", status); + } + } + + return InnerSetRecord(env, recordObject, aniKey, refArray); +} + +bool InnerWrapWantParamsArrayString(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IString *iValue = AAFwk::IString::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::String::Unbox(iValue)); + } + } + } + return InnerSetArrayString(env, recordObject, aniKey, natArray); +} + +bool InnerWrapWantParamsArrayBool(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IBoolean *iValue = AAFwk::IBoolean::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::Boolean::Unbox(iValue)); + } + } + } + + ani_array_boolean aniArray = nullptr; + ani_status status = env->Array_New_Boolean(natArray.size(), &aniArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + auto *aniArrayBuf = reinterpret_cast(natArray.data()); + status = env->Array_SetRegion_Boolean(aniArray, 0, natArray.size(), aniArrayBuf); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_SetRegion_Boolean failed, status: %{public}d", status); + return false; + } + + return InnerSetRecord(env, recordObject, aniKey, aniArray); +} + +bool InnerWrapWantParamsArrayShort(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IShort *iValue = AAFwk::IShort::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::Short::Unbox(iValue)); + } + } + } + + ani_array_short aniArray = nullptr; + ani_status status = env->Array_New_Short(natArray.size(), &aniArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + auto *aniArrayBuf = reinterpret_cast(natArray.data()); + status = env->Array_SetRegion_Short(aniArray, 0, natArray.size(), aniArrayBuf); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_SetRegion failed, status: %{public}d", status); + return false; + } + + return InnerSetRecord(env, recordObject, aniKey, aniArray); +} + +bool InnerWrapWantParamsArrayInt32(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IInteger *iValue = AAFwk::IInteger::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::Integer::Unbox(iValue)); + } + } + } + + ani_array_int aniArray = nullptr; + ani_status status = env->Array_New_Int(natArray.size(), &aniArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + auto *aniArrayBuf = reinterpret_cast(natArray.data()); + status = env->Array_SetRegion_Int(aniArray, 0, natArray.size(), aniArrayBuf); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_SetRegion failed, status: %{public}d", status); + return false; + } + + return InnerSetRecord(env, recordObject, aniKey, aniArray); +} + +bool InnerWrapWantParamsArrayInt64(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::ILong *iValue = AAFwk::ILong::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::Long::Unbox(iValue)); + } + } + } + + ani_array_long aniArray = nullptr; + ani_status status = env->Array_New_Long(natArray.size(), &aniArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + auto *aniArrayBuf = reinterpret_cast(natArray.data()); + status = env->Array_SetRegion_Long(aniArray, 0, natArray.size(), aniArrayBuf); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_SetRegion failed, status: %{public}d", status); + return false; + } + + return InnerSetRecord(env, recordObject, aniKey, aniArray); +} + +bool InnerWrapWantParamsArrayFloat(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IFloat *iValue = AAFwk::IFloat::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::Float::Unbox(iValue)); + } + } + } + + ani_array_float aniArray = nullptr; + ani_status status = env->Array_New_Float(natArray.size(), &aniArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + auto *aniArrayBuf = reinterpret_cast(natArray.data()); + status = env->Array_SetRegion_Float(aniArray, 0, natArray.size(), aniArrayBuf); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_SetRegion failed, status: %{public}d", status); + return false; + } + + return InnerSetRecord(env, recordObject, aniKey, aniArray); +} + +bool InnerWrapWantParamsArrayByte(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IByte *iValue = AAFwk::IByte::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::Byte::Unbox(iValue)); + } + } + } + + ani_array_byte aniArray = nullptr; + ani_status status = env->Array_New_Byte(natArray.size(), &aniArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + auto *aniArrayBuf = reinterpret_cast(natArray.data()); + status = env->Array_SetRegion_Byte(aniArray, 0, natArray.size(), aniArrayBuf); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_SetRegion failed, status: %{public}d", status); + return false; + } + + return InnerSetRecord(env, recordObject, aniKey, aniArray); +} + +bool InnerWrapWantParamsArrayChar(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IChar *iValue = AAFwk::IChar::Query(iface); + if (iValue != nullptr) { + std::string str(static_cast(iValue)->ToString()); + natArray.push_back(str); + } + } + } + + return InnerSetArrayString(env, recordObject, aniKey, natArray); +} + +bool InnerWrapWantParamsArrayDouble(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IDouble *iValue = AAFwk::IDouble::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::Double::Unbox(iValue)); + } + } + } + + ani_array_double aniArray = nullptr; + ani_status status = env->Array_New_Double(natArray.size(), &aniArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + auto *aniArrayBuf = reinterpret_cast(natArray.data()); + status = env->Array_SetRegion_Double(aniArray, 0, natArray.size(), aniArrayBuf); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_SetRegion failed, status: %{public}d", status); + return false; + } + + return InnerSetRecord(env, recordObject, aniKey, aniArray); +} + +bool InnerSetArrayObject(ani_env *env, ani_object recordObject, ani_string aniKey, + const std::vector &natArray) +{ + ani_class recordCls = nullptr; + ani_status status = env->FindClass(RECORD_CLASS_NAME, &recordCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass failed, status: %{public}d", status); + return false; + } + ani_ref undefinedRef = nullptr; + status = env->GetUndefined(&undefinedRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetUndefined failed, status: %{public}d", status); + return false; + } + ani_array_ref refArray = nullptr; + status = env->Array_New_Ref(recordCls, natArray.size(), undefinedRef, &refArray); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_New failed, status: %{public}d", status); + return false; + } + + for (size_t i = 0; i < natArray.size(); i++) { + ani_ref aniValue = WrapWantParams(env, natArray[i]); + if (aniValue == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "value GetAniString failed"); + continue; + } + status = env->Array_Set_Ref(refArray, i, aniValue); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Array_Set_Ref failed, status: %{public}d", status); + } + } + + return InnerSetRecord(env, recordObject, aniKey, refArray); +} + +bool InnerWrapWantParamsArrayWantParams(ani_env *env, ani_object recordObject, const std::string &key, + const sptr &ao) +{ + ani_string aniKey = GetAniString(env, key); + if (aniKey == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "key GetAniString failed"); + return false; + } + + long size = 0; + ErrCode code = ao->GetLength(size); + if (code != ERR_OK) { + TAG_LOGE(AAFwkTag::ANI, "GetLength failed, status: %{public}d", code); + return false; + } + + std::vector natArray; + for (long i = 0; i < size; i++) { + sptr iface = nullptr; + if (ao->Get(i, iface) == ERR_OK) { + AAFwk::IWantParams *iValue = AAFwk::IWantParams::Query(iface); + if (iValue != nullptr) { + natArray.push_back(AAFwk::WantParamWrapper::Unbox(iValue)); + } + } + } + + return InnerSetArrayObject(env, recordObject, aniKey, natArray); +} + +bool InnerWrapWantParamsArray( + ani_env *env, ani_object recordObject, const std::string &key, const sptr &value) +{ + AAFwk::IArray *ao = AAFwk::IArray::Query(value); + if (ao == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null value"); + return false; + } + sptr array(ao); + if (array == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null array"); + return false; + } + + if (AAFwk::Array::IsStringArray(ao)) { + return InnerWrapWantParamsArrayString(env, recordObject, key, array); + } else if (AAFwk::Array::IsBooleanArray(ao)) { + return InnerWrapWantParamsArrayBool(env, recordObject, key, array); + } else if (AAFwk::Array::IsShortArray(ao)) { + return InnerWrapWantParamsArrayShort(env, recordObject, key, array); + } else if (AAFwk::Array::IsIntegerArray(ao)) { + return InnerWrapWantParamsArrayInt32(env, recordObject, key, array); + } else if (AAFwk::Array::IsLongArray(ao)) { + return InnerWrapWantParamsArrayInt64(env, recordObject, key, array); + } else if (AAFwk::Array::IsFloatArray(ao)) { + return InnerWrapWantParamsArrayFloat(env, recordObject, key, array); + } else if (AAFwk::Array::IsByteArray(ao)) { + return InnerWrapWantParamsArrayByte(env, recordObject, key, array); + } else if (AAFwk::Array::IsCharArray(ao)) { + return InnerWrapWantParamsArrayChar(env, recordObject, key, array); + } else if (AAFwk::Array::IsDoubleArray(ao)) { + return InnerWrapWantParamsArrayDouble(env, recordObject, key, array); + } else if (AAFwk::Array::IsWantParamsArray(ao)) { + return InnerWrapWantParamsArrayWantParams(env, recordObject, key, array); + } else { + return false; + } +} } ani_object WrapWant(ani_env *env, const AAFwk::Want &want) @@ -116,39 +1060,45 @@ ani_ref WrapWantParams(ani_env *env, const AAFwk::WantParams &wantParams) TAG_LOGE(AAFwkTag::ANI, "null env"); return nullptr; } - ani_status status = ANI_ERROR; - ani_class cls = nullptr; - if ((status = env->FindClass(TOOL_CLASS_NAME, &cls)) != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass RecordSerializeTool failed, status: %{public}d", status); - return nullptr; - } - if (cls == nullptr) { - TAG_LOGE(AAFwkTag::ANI, "RecordSerializeTool class null"); - return nullptr; - } - ani_static_method parseNoThrowMethod = nullptr; - status = env->Class_FindStaticMethod(cls, "parseNoThrow", nullptr, &parseNoThrowMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "failed to get parseNoThrow method, status: %{public}d", status); - return nullptr; - } - nlohmann::json wantParamsJson = wantParams; - std::string wantParamsString = wantParamsJson.dump(); - ani_string wantParamsAniString; - status = env->String_NewUTF8(wantParamsString.c_str(), wantParamsString.length(), &wantParamsAniString); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "String_NewUTF8 wantParamsString failed, status: %{public}d", status); + ani_object wantParamsRecord = nullptr; + if (!InnerCreateRecordObject(env, wantParamsRecord)) { + TAG_LOGE(AAFwkTag::ANI, "failed to create record object"); return nullptr; } - ani_ref wantParamsRef = nullptr; - status = env->Class_CallStaticMethod_Ref(cls, parseNoThrowMethod, &wantParamsRef, wantParamsAniString); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "failed to call parseNoThrow method, status: %{public}d", status); - return nullptr; + const std::map> ¶mList = wantParams.GetParams(); + for (const auto &[first, second] : paramList) { + if (second == nullptr) { + continue; + } + if (AAFwk::IString::Query(second) != nullptr) { + InnerWrapWantParamsString(env, wantParamsRecord, first, second); + } else if (AAFwk::IBoolean::Query(second) != nullptr) { + InnerWrapWantParamsBool(env, wantParamsRecord, first, second); + } else if (AAFwk::IShort::Query(second) != nullptr) { + InnerWrapWantParamsShort(env, wantParamsRecord, first, second); + } else if (AAFwk::IInteger::Query(second) != nullptr) { + InnerWrapWantParamsInt32(env, wantParamsRecord, first, second); + } else if (AAFwk::ILong::Query(second) != nullptr) { + InnerWrapWantParamsInt64(env, wantParamsRecord, first, second); + } else if (AAFwk::IFloat::Query(second) != nullptr) { + InnerWrapWantParamsFloat(env, wantParamsRecord, first, second); + } else if (AAFwk::IDouble::Query(second) != nullptr) { + InnerWrapWantParamsDouble(env, wantParamsRecord, first, second); + } else if (AAFwk::IChar::Query(second) != nullptr) { + InnerWrapWantParamsChar(env, wantParamsRecord, first, second); + } else if (AAFwk::IByte::Query(second) != nullptr) { + InnerWrapWantParamsByte(env, wantParamsRecord, first, second); + } else if (AAFwk::IArray::Query(second) != nullptr) { + InnerWrapWantParamsArray(env, wantParamsRecord, first, second); + } else if (AAFwk::IWantParams::Query(second) != nullptr) { + InnerWrapWantParamsWantParams(env, wantParamsRecord, first, second); + } else if (AAFwk::IRemoteObjectWrap::Query(second) != nullptr) { + InnerWrapWantParamsRemoteObject(env, wantParamsRecord, first, second); + } } - return wantParamsRef; + return wantParamsRecord; } bool InnerWrapWantParamsString( -- Gitee From 108eb791532f98dd951ae3b4d72699b30a351c44 Mon Sep 17 00:00:00 2001 From: yangzk Date: Thu, 28 Aug 2025 22:41:21 +0800 Subject: [PATCH 5/5] Description:cache class and method Sig:SIG_ApplicationFramework Feature or BugFix: BugFix Binary Source: No Signed-off-by: yangzk Change-Id: I7d3de997ae2ba2ae98570faf29d6601614822fab --- frameworks/ets/ani/BUILD.gn | 4 +- frameworks/ets/ani/ani_common/BUILD.gn | 3 +- .../ani_common/include/ani_common_cache_mgr.h | 58 ++++++++ .../ani_common/src/ani_common_cache_mgr.cpp | 129 ++++++++++++++++++ .../ani/ani_common/src/ani_common_want.cpp | 120 ++++++---------- .../ets/ani/app/ability_context/BUILD.gn | 2 +- frameworks/ets/ani/want/BUILD.gn | 6 +- 7 files changed, 233 insertions(+), 89 deletions(-) create mode 100644 frameworks/ets/ani/ani_common/include/ani_common_cache_mgr.h create mode 100644 frameworks/ets/ani/ani_common/src/ani_common_cache_mgr.cpp diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index 930cb3e639c..1052e9b87f2 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -20,12 +20,12 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/ability_manager:ability_manager_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", "${ability_runtime_path}/frameworks/ets/ani/ani_wantagent_common:ani_wantagent_common", - "${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/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/insight_intent/insight_intent_driver:insight_intent_driver_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/native_constructor:context_ani", "${ability_runtime_path}/frameworks/ets/ani/uri_permission_manager:uri_permission_manager_ani_kit", diff --git a/frameworks/ets/ani/ani_common/BUILD.gn b/frameworks/ets/ani/ani_common/BUILD.gn index 6b5ab09c751..ec8e58c4fc0 100644 --- a/frameworks/ets/ani/ani_common/BUILD.gn +++ b/frameworks/ets/ani/ani_common/BUILD.gn @@ -43,6 +43,7 @@ ohos_shared_library("ani_common") { sources = [ "src/ani_common_ability_result.cpp", "src/ani_common_ability_state_data.cpp", + "src/ani_common_cache_mgr.cpp", "src/ani_common_configuration.cpp", "src/ani_common_execute_param.cpp", "src/ani_common_execute_result.cpp", @@ -89,9 +90,9 @@ ohos_shared_library("ani_common") { "hilog:libhilog", "hitrace:hitrace_meter", "image_framework:image_ani", - "ipc:rpc_ani", "ipc:ipc_core", "ipc:ipc_napi", + "ipc:rpc_ani", "json:nlohmann_json_static", "napi:ace_napi", "resource_management:global_resmgr", diff --git a/frameworks/ets/ani/ani_common/include/ani_common_cache_mgr.h b/frameworks/ets/ani/ani_common/include/ani_common_cache_mgr.h new file mode 100644 index 00000000000..0a3e08af1c0 --- /dev/null +++ b/frameworks/ets/ani/ani_common/include/ani_common_cache_mgr.h @@ -0,0 +1,58 @@ +/* + * 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_ANI_COMMON_CACHE_MGR_H +#define OHOS_ABILITY_RUNTIME_ANI_COMMON_CACHE_MGR_H + +#include +#include +#include +#include "ani.h" + +namespace OHOS { +namespace AppExecFwk { +constexpr const char *CLASSNAME_BOOLEAN = "Lstd/core/Boolean;"; +constexpr const char *CLASSNAME_SHORT = "Lstd/core/Short;"; +constexpr const char *CLASSNAME_INT = "Lstd/core/Int;"; +constexpr const char *CLASSNAME_LONG = "Lstd/core/Long;"; +constexpr const char *CLASSNAME_FLOAT = "Lstd/core/Float;"; +constexpr const char *CLASSNAME_DOUBLE = "Lstd/core/Double;"; +constexpr const char *CLASSNAME_STRING = "Lstd/core/String;"; +constexpr const char *CLASSNAME_RECORD = "Lescompat/Record;"; + +using AniCommonMethodCacheKey = std::pair; + +struct AniCommonCacheItem { + ani_ref classRef_ = nullptr; + std::map methodMap_; +}; + +class AniCommonCacheMgr { +public: + static bool GetCachedClass(ani_env *env, const std::string &className, ani_class &cls); + + static bool GetCachedClassAndMethod(ani_env *env, const std::string &className, + const AniCommonMethodCacheKey &methodKey, ani_class &cls, ani_method &method); + +private: + static bool InnerFindMethod(ani_env *env, const AniCommonMethodCacheKey &methodKey, ani_class cls, + ani_method &method); + + static std::mutex mutex_; + static std::map aniCache_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ANI_COMMON_CACHE_MGR_H diff --git a/frameworks/ets/ani/ani_common/src/ani_common_cache_mgr.cpp b/frameworks/ets/ani/ani_common/src/ani_common_cache_mgr.cpp new file mode 100644 index 00000000000..77119be82ae --- /dev/null +++ b/frameworks/ets/ani/ani_common/src/ani_common_cache_mgr.cpp @@ -0,0 +1,129 @@ +/* + * 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 "ani_common_cache_mgr.h" + +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +std::mutex AniCommonCacheMgr::mutex_; +std::map AniCommonCacheMgr::aniCache_ = { + { CLASSNAME_BOOLEAN, {} }, + { CLASSNAME_SHORT, {} }, + { CLASSNAME_INT, {} }, + { CLASSNAME_LONG, {} }, + { CLASSNAME_FLOAT, {} }, + { CLASSNAME_DOUBLE, {} }, + { CLASSNAME_STRING, {} }, + { CLASSNAME_RECORD, {} }, +}; + +bool AniCommonCacheMgr::GetCachedClass(ani_env *env, const std::string &className, ani_class &cls) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null env"); + return false; + } + + std::lock_guard lock(mutex_); + const auto iter = aniCache_.find(className); + if (iter == aniCache_.end()) { + TAG_LOGE(AAFwkTag::ANI, "Not support cache %{public}s", className.c_str()); + return false; + } + if (iter->second.classRef_ != nullptr) { + cls = reinterpret_cast(iter->second.classRef_); + return true; + } + + ani_status status = env->FindClass(className.c_str(), &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass %{public}s failed %{public}d", className.c_str(), status); + return false; + } + ani_ref ref = nullptr; + status = env->GlobalReference_Create(cls, &ref); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "GlobalReference_Create %{public}s failed %{public}d", className.c_str(), status); + return false; + } + iter->second.classRef_ = ref; + return true; +} + +bool AniCommonCacheMgr::GetCachedClassAndMethod(ani_env *env, const std::string &className, + const AniCommonMethodCacheKey &methodKey, ani_class &cls, ani_method &method) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::ANI, "null env"); + return false; + } + + std::lock_guard lock(mutex_); + const auto iter = aniCache_.find(className); + if (iter == aniCache_.end()) { + TAG_LOGE(AAFwkTag::ANI, "Not support cache %{public}s", className.c_str()); + return false; + } + if (iter->second.classRef_ == nullptr) { + ani_status status = env->FindClass(className.c_str(), &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "FindClass %{public}s failed %{public}d", className.c_str(), status); + return false; + } + ani_ref ref = nullptr; + status = env->GlobalReference_Create(cls, &ref); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "GlobalReference_Create %{public}s failed %{public}d", className.c_str(), status); + return false; + } + iter->second.classRef_ = ref; + } + + cls = reinterpret_cast(iter->second.classRef_); + const auto methodIter = iter->second.methodMap_.find(methodKey); + if (methodIter == iter->second.methodMap_.end()) { + if (!InnerFindMethod(env, methodKey, cls, method)) { + return false; + } + iter->second.methodMap_.emplace(methodKey, method); + return true; + } + if (methodIter->second == nullptr) { + if (!InnerFindMethod(env, methodKey, cls, method)) { + return false; + } + methodIter->second = method; + return true; + } + method = methodIter->second; + return true; +} + +bool AniCommonCacheMgr::InnerFindMethod(ani_env *env, const AniCommonMethodCacheKey &methodKey, ani_class cls, + ani_method &method) +{ + ani_status status = + env->Class_FindMethod(cls, methodKey.first, methodKey.second, &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod %{public}s signature %{public}s failed %{public}d", + methodKey.first, methodKey.second, status); + return false; + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/frameworks/ets/ani/ani_common/src/ani_common_want.cpp b/frameworks/ets/ani/ani_common/src/ani_common_want.cpp index 773c44c98aa..d56ca4345b5 100644 --- a/frameworks/ets/ani/ani_common/src/ani_common_want.cpp +++ b/frameworks/ets/ani/ani_common/src/ani_common_want.cpp @@ -14,6 +14,7 @@ */ #include "ani_common_want.h" +#include "ani_common_cache_mgr.h" #include "ani_common_util.h" #include "ani_remote_object.h" #include "array_wrapper.h" @@ -42,7 +43,6 @@ constexpr const char *ABILITY_WANT_CLASS_NAME = "L@ohos/app/ability/Want/Want;"; constexpr const char *TOOL_CLASS_NAME = "L@ohos/app/ability/Want/RecordSerializeTool;"; constexpr const char *INNER_CLASS_NAME = "Lability/abilityResult/AbilityResultInner;"; constexpr const char *ELEMENTNAME_CLASS_NAME = "LbundleManager/ElementNameInner/ElementNameInner;"; -constexpr const char *RECORD_CLASS_NAME = "Lescompat/Record;"; constexpr const char *RECORD_SET_NAME = "X{C{std.core.Numeric}C{std.core.String}C{std.core.BaseEnum}}C{std.core.Object}:"; @@ -70,17 +70,12 @@ bool InnerCreateRecordObject(ani_env *env, ani_object &recordObject) { ani_class recordCls = nullptr; ani_method recordCtorMethod = nullptr; - ani_status status = env->FindClass(RECORD_CLASS_NAME, &recordCls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + AniCommonMethodCacheKey recordCtor = std::make_pair("", ":V"); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_RECORD, recordCtor, + recordCls, recordCtorMethod)) { return false; } - status = env->Class_FindMethod(recordCls, "", ":V", &recordCtorMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); - return false; - } - status = env->Object_New(recordCls, recordCtorMethod, &recordObject); + ani_status status = env->Object_New(recordCls, recordCtorMethod, &recordObject); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); return false; @@ -92,18 +87,13 @@ bool InnerSetRecord(ani_env *env, ani_object recordObject, ani_string key, ani_o { ani_class recordCls = nullptr; ani_method recordSetMethod = nullptr; - ani_status status = env->FindClass(RECORD_CLASS_NAME, &recordCls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); - return false; - } - status = env->Class_FindMethod(recordCls, "$_set", RECORD_SET_NAME, &recordSetMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod set failed: %{public}d", status); + AniCommonMethodCacheKey recordSet = std::make_pair("$_set", RECORD_SET_NAME); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_RECORD, recordSet, + recordCls, recordSetMethod)) { return false; } - status = env->Object_CallMethod_Void(recordObject, recordSetMethod, key, value); + ani_status status = env->Object_CallMethod_Void(recordObject, recordSetMethod, key, value); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_CallMethod_Void failed status: %{public}d", status); return false; @@ -138,17 +128,12 @@ bool InnerCreateBooleanObject(ani_env *env, ani_boolean value, ani_object &objec { ani_class cls = nullptr; ani_method ctorMethod = nullptr; - ani_status status = env->FindClass("Lstd/core/Boolean;", &cls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + AniCommonMethodCacheKey ctorKey = std::make_pair("", "Z:V"); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_BOOLEAN, ctorKey, + cls, ctorMethod)) { return false; } - status = env->Class_FindMethod(cls, "", "Z:V", &ctorMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); - return false; - } - status = env->Object_New(cls, ctorMethod, &object, value); + ani_status status = env->Object_New(cls, ctorMethod, &object, value); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); return false; @@ -183,17 +168,12 @@ bool InnerCreateShortObject(ani_env *env, ani_short value, ani_object &object) { ani_class cls = nullptr; ani_method ctorMethod = nullptr; - ani_status status = env->FindClass("Lstd/core/Short;", &cls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + AniCommonMethodCacheKey ctorKey = std::make_pair("", "S:V"); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_SHORT, ctorKey, + cls, ctorMethod)) { return false; } - status = env->Class_FindMethod(cls, "", "S:V", &ctorMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); - return false; - } - status = env->Object_New(cls, ctorMethod, &object, value); + ani_status status = env->Object_New(cls, ctorMethod, &object, value); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); return false; @@ -228,17 +208,12 @@ bool InnerCreateIntObject(ani_env *env, ani_int value, ani_object &object) { ani_class cls = nullptr; ani_method ctorMethod = nullptr; - ani_status status = env->FindClass("Lstd/core/Int;", &cls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + AniCommonMethodCacheKey ctorKey = std::make_pair("", "I:V"); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_INT, ctorKey, + cls, ctorMethod)) { return false; } - status = env->Class_FindMethod(cls, "", "I:V", &ctorMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); - return false; - } - status = env->Object_New(cls, ctorMethod, &object, value); + ani_status status = env->Object_New(cls, ctorMethod, &object, value); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); return false; @@ -273,17 +248,12 @@ bool InnerCreateLongObject(ani_env *env, ani_long value, ani_object &object) { ani_class cls = nullptr; ani_method ctorMethod = nullptr; - ani_status status = env->FindClass("Lstd/core/Long;", &cls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + AniCommonMethodCacheKey ctorKey = std::make_pair("", "J:V"); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_LONG, ctorKey, + cls, ctorMethod)) { return false; } - status = env->Class_FindMethod(cls, "", "J:V", &ctorMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); - return false; - } - status = env->Object_New(cls, ctorMethod, &object, value); + ani_status status = env->Object_New(cls, ctorMethod, &object, value); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); return false; @@ -318,17 +288,12 @@ bool InnerCreateFloatObject(ani_env *env, ani_float value, ani_object &object) { ani_class cls = nullptr; ani_method ctorMethod = nullptr; - ani_status status = env->FindClass("Lstd/core/Float;", &cls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); + AniCommonMethodCacheKey ctorKey = std::make_pair("", "F:V"); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_FLOAT, ctorKey, + cls, ctorMethod)) { return false; } - status = env->Class_FindMethod(cls, "", "F:V", &ctorMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); - return false; - } - status = env->Object_New(cls, ctorMethod, &object, value); + ani_status status = env->Object_New(cls, ctorMethod, &object, value); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); return false; @@ -363,17 +328,12 @@ bool InnerCreateDoubleObject(ani_env *env, ani_double value, ani_object &object) { ani_class cls = nullptr; ani_method ctorMethod = nullptr; - ani_status status = env->FindClass("Lstd/core/Double;", &cls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed status: %{public}d", status); - return false; - } - status = env->Class_FindMethod(cls, "", "D:V", &ctorMethod); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "Class_FindMethod constructor failed: %{public}d", status); + AniCommonMethodCacheKey ctorKey = std::make_pair("", "D:V"); + if (!AniCommonCacheMgr::GetCachedClassAndMethod(env, CLASSNAME_DOUBLE, ctorKey, + cls, ctorMethod)) { return false; } - status = env->Object_New(cls, ctorMethod, &object, value); + ani_status status = env->Object_New(cls, ctorMethod, &object, value); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "Object_New failed: %{public}d", status); return false; @@ -500,13 +460,12 @@ bool InnerSetArrayString(ani_env *env, ani_object recordObject, ani_string aniKe const std::vector &natArray) { ani_class stringCls = nullptr; - ani_status status = env->FindClass("Lstd/core/String;", &stringCls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed, status: %{public}d", status); + bool res = AniCommonCacheMgr::GetCachedClass(env, CLASSNAME_STRING, stringCls); + if (!res) { return false; } ani_ref undefinedRef = nullptr; - status = env->GetUndefined(&undefinedRef); + ani_status status = env->GetUndefined(&undefinedRef); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "GetUndefined failed, status: %{public}d", status); return false; @@ -904,13 +863,12 @@ bool InnerSetArrayObject(ani_env *env, ani_object recordObject, ani_string aniKe const std::vector &natArray) { ani_class recordCls = nullptr; - ani_status status = env->FindClass(RECORD_CLASS_NAME, &recordCls); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::ANI, "FindClass failed, status: %{public}d", status); + bool res = AniCommonCacheMgr::GetCachedClass(env, CLASSNAME_RECORD, recordCls); + if (!res) { return false; } ani_ref undefinedRef = nullptr; - status = env->GetUndefined(&undefinedRef); + ani_status status = env->GetUndefined(&undefinedRef); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::ANI, "GetUndefined failed, status: %{public}d", status); return false; diff --git a/frameworks/ets/ani/app/ability_context/BUILD.gn b/frameworks/ets/ani/app/ability_context/BUILD.gn index 5eb598fce09..69fb30cfe04 100644 --- a/frameworks/ets/ani/app/ability_context/BUILD.gn +++ b/frameworks/ets/ani/app/ability_context/BUILD.gn @@ -48,9 +48,9 @@ ohos_shared_library("ability_context_ani_kit") { deps = [ "${ability_runtime_innerkits_path}/ani_base_context:ani_base_context", "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability:ability_context_native", "${ability_runtime_native_path}/ability/native:abilitykit_native", "${ability_runtime_native_path}/ability/native:ui_ability_ani", - "${ability_runtime_native_path}/ability:ability_context_native", "${ability_runtime_native_path}/appkit:app_context", "${ability_runtime_native_path}/appkit:app_context_utils", "${ability_runtime_native_path}/appkit:appkit_native", diff --git a/frameworks/ets/ani/want/BUILD.gn b/frameworks/ets/ani/want/BUILD.gn index 51e2f6360d1..e3b2fb7f58c 100644 --- a/frameworks/ets/ani/want/BUILD.gn +++ b/frameworks/ets/ani/want/BUILD.gn @@ -33,13 +33,11 @@ ohos_shared_library("want_ani_kit") { sources = [ "src/ani_want_module.cpp" ] - deps = [ - "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", - ] + deps = [ "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common" ] external_deps = [ - "ability_base:want", "ability_base:base", + "ability_base:want", "c_utils:utils", "hilog:libhilog", "ipc:rpc_ani", -- Gitee