Description:add abilitystagecontext applicationcontext context transfter

Sig:SIG_ApplicationFramework
Feature or BugFix: Feature
Binary Source: No

Signed-off-by: zhangyafei.echo <zhangyafei12@huawei.com>
Change-Id: I03ae6b16d51395b372752cf5ab5a8738faa726d9

Description:add context transfer dynamic
Sig:SIG_ApplicationFramework
Feature or BugFix: Feature
Binary Source: No

Signed-off-by: zhangyafei.echo <zhangyafei12@huawei.com>
Change-Id: I60311120b492a947ab91a7035e304e55669c7988

Description:context transfer bugfix.
Sig:SIG_ApplicationFramework
Feature or BugFix: Feature
Binary Source: No

Signed-off-by: zhangyafei.echo <zhangyafei12@huawei.com>
Change-Id: Iff2ffa198547d51805ca09dbf977ecaa31d92d38
This commit is contained in:
zhangyafei.echo
2025-06-17 23:34:56 +08:00
committed by yangzk
parent 1376888553
commit dd346604ca
13 changed files with 1663 additions and 4 deletions
+3
View File
@@ -22,6 +22,9 @@ group("ani_packages") {
"${ability_runtime_path}/frameworks/ets/ani/ani_mission_manager:missionmanager_ani",
"${ability_runtime_path}/frameworks/ets/ani/ani_wantagent_common:ani_wantagent_common",
"${ability_runtime_path}/frameworks/ets/ani/app/ability_context:ability_context_ani_kit",
"${ability_runtime_path}/frameworks/ets/ani/app/ability_stage_context:ability_stage_context_ani_kit",
"${ability_runtime_path}/frameworks/ets/ani/app/application_context:application_context_ani_kit",
"${ability_runtime_path}/frameworks/ets/ani/app/context:context_ani_kit",
"${ability_runtime_path}/frameworks/ets/ani/app_manager:app_manager_ani",
"${ability_runtime_path}/frameworks/ets/ani/application:application_ani",
"${ability_runtime_path}/frameworks/ets/ani/apprecovery:appRecovery_ani",
@@ -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"
}
@@ -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 <memory>
#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> abilityStageContext);
private:
static bool IsInstanceOf(ani_env *aniEnv, ani_object aniObj);
static std::unique_ptr<NativeReference> CreateNativeReference(napi_env napiEnv,
std::shared_ptr<AbilityStageContext> abilityStageContext);
static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls,
std::shared_ptr<AbilityStageContext> abilityStageContext);
};
void EtsAbilityStageContextModuleInit(ani_env *aniEnv);
} // namespace AbilityRuntime
} // namespace OHOS
#endif // OHOS_ABILITY_RUNTIME_ETS_ABILITY_STAGE_CONTEXT_MODULE_H
@@ -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 <cstdio>
#include <sys/syscall.h>
#include <unistd.h>
#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<std::weak_ptr<AbilityStageContext> *>(unwrapResult)->lock();
if (context == nullptr) {
TAG_LOGE(AAFwkTag::CONTEXT, "null AbilityStageContext");
EtsErrorUtil::ThrowEtsTransferClassError(aniEnv);
return nullptr;
}
auto abilityStageContext = Context::ConvertTo<AbilityStageContext>(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<ani_ref>();
if (staticContext != nullptr) {
TAG_LOGI(AAFwkTag::CONTEXT, "there exist a staticContext");
return reinterpret_cast<ani_object>(*staticContext);
}
// if not exist, create a new one
std::string contextType;
if (!AppExecFwk::GetStdString(aniEnv, reinterpret_cast<ani_string>(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<NativeReference> EtsAbilityStageContextModule::CreateNativeReference(napi_env napiEnv,
std::shared_ptr<AbilityStageContext> 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>(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<std::weak_ptr<AbilityStageContext> *>(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> 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<NativeReference *>(
abilityStageContext->GetSubThreadObject(static_cast<void *>(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<void *>(napiEnv), static_cast<void *>(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<NativeReference>();
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> abilityStageContext = Context::ConvertTo<AbilityStageContext>(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> 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<void*>(EtsAbilityStageContextModule::NativeTransferStatic) },
ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;",
reinterpret_cast<void*>(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> 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> context) -> napi_value {
auto abilityStageContext = Context::ConvertTo<AbilityStageContext>(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
@@ -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"
}
@@ -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 <memory>
#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> applicationContext);
static void RegisterContextObjectCreator();
private:
static bool IsInstanceOf(ani_env *aniEnv, ani_object aniObj);
static std::unique_ptr<NativeReference> CreateNativeReference(napi_env napiEnv,
std::shared_ptr<ApplicationContext> applicationContext);
static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls,
std::shared_ptr<ApplicationContext> applicationContext);
};
void EtsApplicationContextModuleInit(ani_env *aniEnv);
} // namespace AbilityRuntime
} // namespace OHOS
#endif // OHOS_ABILITY_RUNTIME_ETS_APPLICATION_CONTEXT_MODULE_H
@@ -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 <cstdio>
#include <sys/syscall.h>
#include <unistd.h>
#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<std::weak_ptr<ApplicationContext> *>(unwrapResult)->lock();
if (context == nullptr) {
TAG_LOGE(AAFwkTag::CONTEXT, "null application context");
EtsErrorUtil::ThrowEtsTransferClassError(aniEnv);
return nullptr;
}
auto applicationContext = Context::ConvertTo<ApplicationContext>(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<ani_ref>();
if (staticContext != nullptr) {
TAG_LOGI(AAFwkTag::CONTEXT, "got an exist staticContext");
return reinterpret_cast<ani_object>(*staticContext);
}
// create a new one
std::string contextType;
if (!AppExecFwk::GetStdString(aniEnv, reinterpret_cast<ani_string>(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<NativeReference> EtsApplicationContextModule::CreateNativeReference(napi_env napiEnv,
std::shared_ptr<ApplicationContext> 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>(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<std::weak_ptr<ApplicationContext> *>(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> 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<NativeReference *>(
applicationContext->GetSubThreadObject(static_cast<void *>(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<void *>(napiEnv), static_cast<void *>(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<NativeReference>();
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> applicationContext = Context::ConvertTo<ApplicationContext>(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> 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> context) -> ani_object {
auto applicationContext = Context::ConvertTo<ApplicationContext>(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> context) -> napi_value {
auto applicationContext = Context::ConvertTo<ApplicationContext>(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<void*>(EtsApplicationContextModule::NativeTransferStatic) },
ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;",
reinterpret_cast<void*>(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
+70
View File
@@ -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"
}
@@ -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 <memory>
#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> context);
private:
static bool LoadTargetModule(ani_env *aniEnv, const std::string &className);
static std::unique_ptr<NativeReference> CreateNativeReference(napi_env napiEnv, std::shared_ptr<Context> context);
static ani_object CreateStaticObject(ani_env *aniEnv, ani_object type, std::shared_ptr<Context> context);
static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls, std::shared_ptr<Context> context);
};
void EtsContextModuleInit(ani_env *aniEnv);
} // namespace AbilityRuntime
} // namespace OHOS
#endif // OHOS_ABILITY_RUNTIME_ETS_CONTEXT_MODULE_H
@@ -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 <cstdio>
#include <sys/syscall.h>
#include <unistd.h>
#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<std::string, std::string> 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<std::weak_ptr<Context> *>(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<ani_ref>();
if (staticContext != nullptr) {
TAG_LOGI(AAFwkTag::CONTEXT, "there exist a staticContext");
return reinterpret_cast<ani_object>(*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> context)
{
std::string contextType;
if (!AppExecFwk::GetStdString(aniEnv, reinterpret_cast<ani_string>(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<NativeReference> EtsContextModule::CreateNativeReference(napi_env napiEnv,
std::shared_ptr<Context> 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>(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<std::weak_ptr<Context> *>(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> 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<NativeReference *>(context->GetSubThreadObject(static_cast<void *>(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<void *>(napiEnv), static_cast<void *>(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<NativeReference>();
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<NativeReference> 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<Context> 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<void*>(EtsContextModule::NativeTransferStatic) },
ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;",
reinterpret_cast<void*>(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> 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> 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
@@ -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;
}
}
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();
}
}
@@ -40,6 +40,10 @@ let destroyRegister = new FinalizationRegistry<Cleaner>(callback);
let unregisterToken = new object();
export default class ApplicationContext extends Context {
static {
loadLibraryWithPermissionCheck("application_context_ani_kit.z", "application.ApplicationContext");
}
etsApplicationContextPtr: long = 0;
private cleaner: Cleaner | null = null;
@@ -58,6 +62,7 @@ export default class ApplicationContext extends Context {
unregisterCleaner(): void {
destroyRegister.unregister(unregisterToken);
}
public native nativekillAllProcessesSync(clearPageStack: boolean, callback: AsyncCallbackWrapper<void>): void;
public native nativepreloadUIExtensionAbilitySync(want: Want, callback: AsyncCallbackWrapper<void>): void;
public native setSupportedProcessCacheSync(isSupported : boolean):void;
@@ -75,6 +80,9 @@ export default class ApplicationContext extends Context {
public native nativeOffApplicationStateChangeSync(callback?: ApplicationStateChangeCallback): void;
public native nativegetCurrentAppCloneIndex(): int;
public native nativegetCurrentInstanceKey(): string;
private static native nativeTransferStatic(input: ESValue, type: string): Object;
private static native nativeTransferDynamic(input: Object): ESValue;
private static contextType: string = 'ApplicationContext';
setSupportedProcessCache(isSupported : boolean):void {
this.setSupportedProcessCacheSync(isSupported);
@@ -271,4 +279,19 @@ export default class ApplicationContext extends Context {
getCurrentAppCloneIndex(): int {
return this.nativegetCurrentAppCloneIndex();
}
}
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();
}
}
@@ -38,7 +38,9 @@ let unregisterToken = new object();
export class Context extends BaseContext {
static {
loadLibraryWithPermissionCheck("context_ani", "application.Context");
loadLibraryWithPermissionCheck("context_ani_kit.z", "application.Context");
}
etsContextPtr: long = 0;
private cleaner: Cleaner | null = null;
filesDir: string = "";
@@ -72,6 +74,7 @@ export class Context extends BaseContext {
unregisterCleaner(): void {
destroyRegister.unregister(unregisterToken);
}
public native getApplicationContextSync(): ApplicationContext;
public native createModuleResourceManagerSync(bundleName: string, moduleName: string): resmgr.ResourceManager;
private native switchArea(mode: contextConstant.AreaMode): void;
@@ -80,6 +83,9 @@ export class Context extends BaseContext {
public native nativeCreateDisplayContext(displayId: long): Context;
public native nativeCreateAreaModeContext(areaMode: contextConstant.AreaMode): Context;
public native nativeCreateSystemHspModuleResourceManager(bundleName: string, moduleName: string): resmgr.ResourceManager;
private static native nativeTransferStatic(input: ESValue, type: string): Object;
private static native nativeTransferDynamic(input: Object): ESValue;
private static contextType: string = 'Context';
getApplicationContext(): ApplicationContext {
return this.getApplicationContextSync();
@@ -130,4 +136,19 @@ export class Context extends BaseContext {
createSystemHspModuleResourceManager(bundleName: string, moduleName: string): resmgr.ResourceManager {
return this.nativeCreateSystemHspModuleResourceManager(bundleName, moduleName);
}
static transferStatic(input: Any): Object {
let type: string = '';
try {
type = ESValue.wrap(input).getProperty('__context_impl__').getProperty('contextType').toString();
} catch (err) {
console.log('transferStatic err: ' + err.toString());
}
console.log('transferStatic type: ' + type);
return Context.nativeTransferStatic(ESValue.wrap(input), type);
}
static transferDynamic(input: Object): Any {
return Context.nativeTransferDynamic(input).unwrap();
}
}