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
parent 8dbfaa1d43
commit ee6afbf824
32 changed files with 535 additions and 553 deletions
-1
View File
@@ -22,7 +22,6 @@ 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",
+1
View File
@@ -49,6 +49,7 @@ ohos_shared_library("ani_common") {
"src/ani_common_start_options.cpp",
"src/ani_common_util.cpp",
"src/ani_common_want.cpp",
"src/context_transfer.cpp",
"src/ets_application_context_utils.cpp",
"src/ets_context_utils.cpp",
"src/ets_data_struct_converter.cpp",
@@ -74,6 +74,8 @@ bool SetDoublePropertyObject(ani_env *env, ani_object param, const char *name, d
bool SetDoublePropertyValue(ani_env *env, ani_object param, const char *name, double value);
bool SetStringArrayProperty(ani_env *env, ani_object param, const char *name, const std::vector<std::string> &values);
bool SetRefProperty(ani_env *env, ani_object param, const char *name, ani_ref value);
bool GetStaticFieldString(ani_env *env, ani_class classObj, const char *fieldName, std::string &value);
} // namespace AppExecFwk
} // namespace OHOS
#endif // OHOS_ABILITY_RUNTIME_ANI_COMMON_UTIL_H
+56
View File
@@ -0,0 +1,56 @@
/*
* 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_CONTEXT_TRANSFER_H
#define OHOS_ABILITY_RUNTIME_CONTEXT_TRANSFER_H
#include <memory>
#include "ani.h"
#include "context.h"
#include "native_engine/native_engine.h"
namespace OHOS {
namespace AbilityRuntime {
using CreateStaticObject = std::function<ani_object (ani_env *aniEnv, std::shared_ptr<Context> context)>;
using CreateDynamicObject = std::function<napi_value (napi_env napiEnv, std::shared_ptr<Context> context)>;
class ContextTransfer {
public:
static ContextTransfer &GetInstance();
ContextTransfer() = default;
~ContextTransfer() = default;
void RegisterStaticObjectCreator(const std::string &contextType, const CreateStaticObject &createFunc);
ani_object GetStaticObject(const std::string &contextType, ani_env *aniEnv, std::shared_ptr<Context> context);
void RegisterDynamicObjectCreator(const std::string &contextType, const CreateDynamicObject &createFunc);
napi_value GetDynamicObject(const std::string &contextType, napi_env napiEnv, std::shared_ptr<Context> context);
bool IsStaticCreatorExist(const std::string &contextType);
bool IsDynamicCreatorExist(const std::string &contextType);
private:
ContextTransfer(const ContextTransfer&) = delete;
ContextTransfer(ContextTransfer&&) = delete;
ContextTransfer& operator=(const ContextTransfer&) = delete;
ContextTransfer& operator=(ContextTransfer&&) = delete;
std::mutex creatorMutex_;
std::unordered_map<std::string, CreateStaticObject> staticCreators_;
std::unordered_map<std::string, CreateDynamicObject> dynamicCreators_;
};
} // namespace AbilityRuntime
} // namespace OHOS
#endif // OHOS_ABILITY_RUNTIME_CONTEXT_TRANSFER_H
@@ -34,6 +34,7 @@ public:
static void ThrowInvalidParamError(ani_env *env, const std::string &message);
static void ThrowErrorByNativeErr(ani_env *env, int32_t err);
static void ThrowNotSystemAppError(ani_env *env);
static void ThrowEtsTransferClassError(ani_env *env);
static ani_object CreateError(ani_env *env, const AbilityErrorCode &err);
static ani_object CreateError(ani_env *env, ani_int code, const std::string &msg);
@@ -558,7 +558,7 @@ bool GetStringOrUndefined(ani_env *env, ani_object param, const char *name, std:
ani_ref obj = nullptr;
ani_boolean isUndefined = true;
ani_status status = ANI_ERROR;
if (env == nullptr || param == nullptr || name == nullptr) {
TAG_LOGE(AAFwkTag::ANI, "null env or param or name");
return false;
@@ -1181,5 +1181,42 @@ bool SetRefProperty(ani_env *env, ani_object param, const char *name, ani_ref va
}
return true;
}
bool GetStaticFieldString(ani_env *env, ani_class classObj, const char *fieldName, std::string &value)
{
if (env == nullptr) {
TAG_LOGE(AAFwkTag::JSNAPI, "null env");
return false;
}
ani_status status = ANI_ERROR;
ani_static_field field {};
if ((status = env->Class_FindStaticField(classObj, fieldName, &field)) != ANI_OK) {
TAG_LOGE(AAFwkTag::JSNAPI, "Class_FindStaticField status: %{public}d", status);
return false;
}
ani_ref obj = nullptr;
if ((status = env->Class_GetStaticField_Ref(classObj, field, &obj)) != ANI_OK) {
TAG_LOGE(AAFwkTag::JSNAPI, "Class_GetStaticField_Ref status: %{public}d", status);
return false;
}
ani_boolean isUndefined = true;
if ((status = env->Reference_IsUndefined(obj, &isUndefined)) != ANI_OK) {
TAG_LOGE(AAFwkTag::JSNAPI, "status: %{public}d", status);
return false;
}
if (isUndefined) {
TAG_LOGE(AAFwkTag::JSNAPI, "%{public}s : undefined", fieldName);
return false;
}
if (!AppExecFwk::GetStdString(env, reinterpret_cast<ani_string>(obj), value)) {
TAG_LOGE(AAFwkTag::JSNAPI, "GetStdString failed");
return false;
}
return true;
}
} // namespace AppExecFwk
} // namespace OHOS
+81
View File
@@ -0,0 +1,81 @@
/*
* 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 "context_transfer.h"
#include "hilog_tag_wrapper.h"
namespace OHOS {
namespace AbilityRuntime {
ContextTransfer &ContextTransfer::GetInstance()
{
static ContextTransfer contextTransfer;
return contextTransfer;
}
void ContextTransfer::RegisterStaticObjectCreator(const std::string &contextType, const CreateStaticObject &createFunc)
{
TAG_LOGD(AAFwkTag::CONTEXT, "Reg static creator for %{public}s", contextType.c_str());
std::lock_guard<std::mutex> lock(creatorMutex_);
staticCreators_.emplace(contextType, createFunc);
}
ani_object ContextTransfer::GetStaticObject(const std::string &contextType, ani_env *aniEnv,
std::shared_ptr<Context> context)
{
TAG_LOGD(AAFwkTag::CONTEXT, "Get static creator for %{public}s", contextType.c_str());
std::lock_guard<std::mutex> lock(creatorMutex_);
auto it = staticCreators_.find(contextType);
if (it != staticCreators_.end()) {
return it->second(aniEnv, context);
}
return nullptr;
}
void ContextTransfer::RegisterDynamicObjectCreator(const std::string &contextType,
const CreateDynamicObject &createFunc)
{
TAG_LOGD(AAFwkTag::CONTEXT, "Reg dynamic creator for %{public}s", contextType.c_str());
std::lock_guard<std::mutex> lock(creatorMutex_);
dynamicCreators_.emplace(contextType, createFunc);
}
napi_value ContextTransfer::GetDynamicObject(const std::string &contextType, napi_env napiEnv,
std::shared_ptr<Context> context)
{
TAG_LOGD(AAFwkTag::CONTEXT, "Get dynamic creator for %{public}s", contextType.c_str());
std::lock_guard<std::mutex> lock(creatorMutex_);
auto it = dynamicCreators_.find(contextType);
if (it != dynamicCreators_.end()) {
return it->second(napiEnv, context);
}
return nullptr;
}
bool ContextTransfer::IsStaticCreatorExist(const std::string &contextType)
{
std::lock_guard<std::mutex> lock(creatorMutex_);
auto it = staticCreators_.find(contextType);
return it != staticCreators_.end();
}
bool ContextTransfer::IsDynamicCreatorExist(const std::string &contextType)
{
std::lock_guard<std::mutex> lock(creatorMutex_);
auto it = dynamicCreators_.find(contextType);
return it != dynamicCreators_.end();
}
} // namespace AbilityRuntime
} // namespace OHOS
@@ -559,6 +559,13 @@ ani_object EtsApplicationContextUtils::CreateEtsApplicationContext(ani_env* aniE
return nullptr;
}
ContextUtil::CreateEtsBaseContext(aniEnv, applicationContextClass, applicationContextObject, applicationContext);
ani_ref* contextGlobalRef = new (std::nothrow) ani_ref;
if ((status = aniEnv->GlobalReference_Create(applicationContextObject, contextGlobalRef)) != ANI_OK) {
TAG_LOGE(AAFwkTag::APPKIT, "GlobalReference_Create failed status: %{public}d", status);
delete contextGlobalRef;
return nullptr;
}
applicationContext->Bind(contextGlobalRef);
return applicationContextObject;
}
} // namespace AbilityRuntime
@@ -26,6 +26,8 @@ constexpr const char *ERR_MSG_INVALID_NUM_PARAMS = "Parameter error. The number
constexpr const char *NOT_SYSTEM_APP = "The application is not system-app, can not use system-api.";
constexpr const char *BUSINESS_ERROR_CLASS = "L@ohos/base/BusinessError;";
constexpr const char *ERROR_CLASS_NAME = "Lescompat/Error;";
constexpr const char* ERROR_MSG_TRANSFER_CLASS_NOT_FOUND = "Unable to find the class for transferring.";
constexpr int32_t ERROR_CODE_TRANSFER_CLASS_NOT_FOUND = 10200067;
} // namespace
void EtsErrorUtil::ThrowError(ani_env *env, ani_object err)
@@ -106,6 +108,12 @@ void EtsErrorUtil::ThrowNotSystemAppError(ani_env *env)
env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP), NOT_SYSTEM_APP));
}
void EtsErrorUtil::ThrowEtsTransferClassError(ani_env *env)
{
EtsErrorUtil::ThrowError(env, EtsErrorUtil::CreateError(
env, static_cast<int32_t>(ERROR_CODE_TRANSFER_CLASS_NOT_FOUND), ERROR_MSG_TRANSFER_CLASS_NOT_FOUND));
}
void EtsErrorUtil::ThrowInvalidParamError(ani_env *env, const std::string &message)
{
if (env == nullptr) {
@@ -1,72 +0,0 @@
# 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"
}
@@ -1,52 +0,0 @@
/*
* 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 <memory>
#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> abilityContext);
private:
static bool IsInstanceOf(ani_env *aniEnv, ani_object aniObj);
static std::unique_ptr<NativeReference> CreateNativeReference(napi_env napiEnv,
std::shared_ptr<AbilityContext> abilityContext);
static ani_object CreateDynamicObject(ani_env *aniEnv, ani_class aniCls,
std::shared_ptr<AbilityContext> abilityContext);
};
void EtsAbilityContextModuleInit(ani_env *aniEnv);
} // namespace AbilityRuntime
} // namespace OHOS
#endif // OHOS_ABILITY_RUNTIME_ETS_ABILITY_CONTEXT_MODULE_H
@@ -1,387 +0,0 @@
/*
* 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 <cstdio>
#include <sys/syscall.h>
#include <unistd.h>
#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<std::weak_ptr<AbilityContext> *>(unwrapResult)->lock();
if (context == nullptr) {
TAG_LOGE(AAFwkTag::CONTEXT, "null AbilityContext");
EtsErrorUtil::ThrowEtsTransferClassError(aniEnv);
return nullptr;
}
auto abilityContext = Context::ConvertTo<AbilityContext>(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<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 abilityContext failed");
EtsErrorUtil::ThrowEtsTransferClassError(aniEnv);
return nullptr;
}
return newContext;
}
std::unique_ptr<NativeReference> EtsAbilityContextModule::CreateNativeReference(napi_env napiEnv,
std::shared_ptr<AbilityContext> 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>(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<std::weak_ptr<AbilityContext> *>(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> 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<NativeReference *>(
abilityContext->GetSubThreadObject(static_cast<void *>(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<void *>(napiEnv), static_cast<void *>(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<NativeReference>();
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> abilityContext = Context::ConvertTo<AbilityContext>(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> 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<void*>(EtsAbilityContextModule::NativeTransferStatic) },
ani_native_function { "nativeTransferDynamic", "Lstd/core/Object;:Lstd/interop/ESValue;",
reinterpret_cast<void*>(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> 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> context) -> napi_value {
auto abilityContext = Context::ConvertTo<AbilityContext>(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
@@ -45,7 +45,6 @@ let unregisterToken = new object();
export default class UIAbilityContext extends Context {
static {
loadLibrary("context_ani");
loadLibrary("ability_context_ani_kit.z");
}
private cleaner: Cleaner | null = null;
@@ -81,24 +80,6 @@ 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>): void;
private native nativeStartAbilitySync(want: Want, options: StartOptions, callback: AsyncCallbackWrapper<void>): void;
@@ -18,11 +18,14 @@
#include <native_engine/native_engine.h>
#include "ability_manager_client.h"
#include "hitrace_meter.h"
#include "application_configuration_manager.h"
#include "configuration_convertor.h"
#include "bindable_sub_thread.h"
#include "connection_manager.h"
#include "dialog_request_callback_impl.h"
#include "dialog_ui_extension_callback.h"
#include "hilog_tag_wrapper.h"
#include "hitrace_meter.h"
#include "json_utils.h"
#include "remote_object_wrapper.h"
#include "request_constants.h"
@@ -34,8 +37,6 @@
#include "ui_content.h"
#endif // SUPPORT_SCREEN
#include "want_params_wrapper.h"
#include "configuration_convertor.h"
#include "application_configuration_manager.h"
namespace OHOS {
namespace AbilityRuntime {
@@ -55,6 +56,11 @@ struct RequestResult {
RequestDialogResultTask task;
};
AbilityContextImpl::AbilityContextImpl()
{
subThreadObject_ = std::make_unique<BindableSubThread>();
}
Global::Resource::DeviceType AbilityContextImpl::GetDeviceType() const
{
return (stageContext_ != nullptr) ? stageContext_->GetDeviceType() : Global::Resource::DeviceType::DEVICE_PHONE;
@@ -2223,6 +2223,9 @@ napi_value CreateJsAbilityContext(napi_env env, std::shared_ptr<AbilityContext>
napi_set_named_property(env, object, "config", CreateJsConfiguration(env, *configuration));
}
std::string type = "UIAbilityContext";
napi_set_named_property(env, object, "contextType", CreateJsValue(env, type));
const char *moduleName = "JsAbilityContext";
BindNativeFunction(env, object, "startAbility", moduleName, JsAbilityContext::StartAbility);
BindNativeFunction(env, object, "openLink", moduleName, JsAbilityContext::OpenLink);
@@ -704,7 +704,7 @@ void UIAbility::BindHybridContext(const std::shared_ptr<AppExecFwk::OHOSApplicat
TAG_LOGE(AAFwkTag::UIABILITY, "null appInfo");
return;
}
if (appInfo->codeLanguage != AppExecFwk::Constants::CODE_LANGUAGE_HYBRID) {
if (appInfo->arkTSMode != AppExecFwk::Constants::ARKTS_MODE_HYBRID) {
TAG_LOGD(AAFwkTag::UIABILITY, "not hybrid app, no need to create hybrid context");
return;
}
@@ -714,12 +714,12 @@ void UIAbility::BindHybridContext(const std::shared_ptr<AppExecFwk::OHOSApplicat
TAG_LOGE(AAFwkTag::UIABILITY, "null abilityInfo");
return;
}
if (abilityInfo->codeLanguage == AppExecFwk::Constants::CODE_LANGUAGE_1_1) {
if (abilityInfo->arkTSMode == AppExecFwk::Constants::ARKTS_MODE_DYNAMIC) {
BindEtsContext(application, record);
} else if (abilityInfo->codeLanguage == AppExecFwk::Constants::CODE_LANGUAGE_1_2) {
} else if (abilityInfo->arkTSMode == AppExecFwk::Constants::ARKTS_MODE_STATIC) {
BindJsContext(application, record);
} else {
TAG_LOGE(AAFwkTag::UIABILITY, "unknown codeLanguage");
TAG_LOGE(AAFwkTag::UIABILITY, "unknown arkTSMode");
}
}
+1
View File
@@ -453,6 +453,7 @@ ohos_shared_library("app_context") {
"${ability_runtime_native_path}/appkit/ability_runtime/context/ability_stage_context.cpp",
"${ability_runtime_native_path}/appkit/ability_runtime/context/application_context.cpp",
"${ability_runtime_native_path}/appkit/ability_runtime/context/application_state_change_callback.cpp",
"${ability_runtime_native_path}/appkit/ability_runtime/context/bindable_sub_thread.cpp",
"${ability_runtime_native_path}/appkit/ability_runtime/context/context_impl.cpp",
"${ability_runtime_native_path}/appkit/ability_runtime/context/environment_callback.cpp",
"${ability_runtime_native_path}/appkit/app/overlay_event_subscriber.cpp",
@@ -79,6 +79,15 @@ ETSAbilityStage::ETSAbilityStage(
: etsRuntime_(etsRuntime), etsAbilityStageObj_(std::move(etsAbilityStageObj))
{}
ETSAbilityStage::~ETSAbilityStage()
{
TAG_LOGI(AAFwkTag::APPKIT, "destructor");
auto context = GetContext();
if (context != nullptr) {
context->Unbind();
}
}
void ETSAbilityStage::Init(const std::shared_ptr<Context> &context,
const std::weak_ptr<AppExecFwk::OHOSApplication> application)
{
@@ -36,21 +36,18 @@ ani_object ETSAbilityStageContext::CreateEtsAbilityStageContext(ani_env *env, st
ani_status status = ANI_OK;
ani_class abilityStageCtxCls;
status = env->FindClass(ETS_ABILITY_STAGE_CONTEXT_CLASS_NAME, &abilityStageCtxCls);
if (status != ANI_OK) {
if ((status = env->FindClass(ETS_ABILITY_STAGE_CONTEXT_CLASS_NAME, &abilityStageCtxCls)) != ANI_OK) {
TAG_LOGE(AAFwkTag::ABILITY, "call FindClass LAbilityStageContext failed, status:%{public}d", status);
return nullptr;
}
ani_method method = nullptr;
status = env->Class_FindMethod(abilityStageCtxCls, "<ctor>", ":V", &method);
if (status != ANI_OK) {
if ((status = env->Class_FindMethod(abilityStageCtxCls, "<ctor>", ":V", &method)) != ANI_OK) {
TAG_LOGE(AAFwkTag::ABILITY, "call Class_FindMethod ctor failed");
return nullptr;
}
ani_object obj = nullptr;
status = env->Object_New(abilityStageCtxCls, method, &obj);
if (status != ANI_OK) {
if ((status = env->Object_New(abilityStageCtxCls, method, &obj)) != ANI_OK) {
TAG_LOGE(AAFwkTag::ABILITY, "call Object_New abilityStageCtxCls failed");
return nullptr;
}
@@ -63,13 +60,11 @@ ani_object ETSAbilityStageContext::CreateEtsAbilityStageContext(ani_env *env, st
return nullptr;
}
ani_field contextField;
status = env->Class_FindField(abilityStageCtxCls, "nativeContext", &contextField);
if (status != ANI_OK) {
if ((status = env->Class_FindField(abilityStageCtxCls, "nativeContext", &contextField)) != ANI_OK) {
TAG_LOGE(AAFwkTag::ABILITY, "call Class_FindField nativeContext failed");
}
ani_long nativeContextLong = (ani_long)workContext;
status = env->Object_SetField_Long(obj, contextField, nativeContextLong);
if (status != ANI_OK) {
if ((status = env->Object_SetField_Long(obj, contextField, nativeContextLong)) != ANI_OK) {
TAG_LOGE(AAFwkTag::ABILITY, "call Object_SetField_Long contextField failed");
delete workContext;
return nullptr;
@@ -77,6 +72,14 @@ ani_object ETSAbilityStageContext::CreateEtsAbilityStageContext(ani_env *env, st
ContextUtil::CreateEtsBaseContext(env, abilityStageCtxCls, obj, context);
SetConfiguration(env, abilityStageCtxCls, obj, context);
ani_ref* contextGlobalRef = new (std::nothrow) ani_ref;
if ((status = env->GlobalReference_Create(obj, contextGlobalRef)) != ANI_OK) {
TAG_LOGE(AAFwkTag::ABILITY, "GlobalReference_Create failed status: %{public}d", status);
delete contextGlobalRef;
delete workContext;
return nullptr;
}
context->Bind(contextGlobalRef);
return obj;
}
@@ -84,6 +84,10 @@ napi_value CreateJsAbilityStageContext(napi_env env, std::shared_ptr<AbilityRunt
if (configuration != nullptr && CheckTypeForNapiValue(env, objValue, napi_object)) {
napi_set_named_property(env, objValue, "config", CreateJsConfiguration(env, *configuration));
}
std::string type = "AbilityStageContext";
napi_set_named_property(env, objValue, "contextType", CreateJsValue(env, type));
return objValue;
}
@@ -0,0 +1,121 @@
/*
* 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 "bindable_sub_thread.h"
#include "hilog_tag_wrapper.h"
#include "native_engine/native_engine.h"
namespace OHOS {
namespace AbilityRuntime {
namespace {
struct HookData {
std::weak_ptr<BindableSubThread> instance;
napi_env env = nullptr;
};
} // namespace
BindableSubThread::~BindableSubThread()
{
TAG_LOGD(AAFwkTag::CONTEXT, "destructor");
}
void BindableSubThread::BindSubThreadObject(void* napiEnv, void* object)
{
TAG_LOGD(AAFwkTag::CONTEXT, "bind sub thread object");
uintptr_t key = reinterpret_cast<uintptr_t>(napiEnv);
std::lock_guard guard(objectsMutex_);
auto it = objects_.find(key);
if (it != objects_.end()) {
TAG_LOGD(AAFwkTag::CONTEXT, "object has bound");
return;
}
napi_env acutalEnv = static_cast<napi_env>(napiEnv);
HookData* data = new (std::nothrow) HookData { weak_from_this(), acutalEnv };
if (data == nullptr) {
TAG_LOGE(AAFwkTag::CONTEXT, "data err");
return;
}
napi_status ret = napi_add_env_cleanup_hook(acutalEnv,
StaticRemoveSubThreadObject, data);
if (ret != napi_status::napi_ok) {
TAG_LOGE(AAFwkTag::CONTEXT, "add hook err");
delete data;
return;
}
std::unique_ptr<void, void (*)(void*)> obj(object,
[](void* ptr) {
TAG_LOGD(AAFwkTag::CONTEXT, "delete sub thread ptr");
delete static_cast<NativeReference*>(ptr);
});
objects_.emplace(key, std::move(obj));
}
void* BindableSubThread::GetSubThreadObject(void* napiEnv)
{
TAG_LOGD(AAFwkTag::CONTEXT, "get sub thread object");
uintptr_t key = reinterpret_cast<uintptr_t>(napiEnv);
std::lock_guard guard(objectsMutex_);
const auto& iter = objects_.find(key);
if (iter == objects_.end()) {
TAG_LOGD(AAFwkTag::CONTEXT, "not found target object");
return nullptr;
}
return static_cast<void*>(iter->second.get());
}
void BindableSubThread::RemoveSubThreadObject(void* napiEnv)
{
TAG_LOGD(AAFwkTag::CONTEXT, "remove sub thread object");
uintptr_t key = reinterpret_cast<uintptr_t>(napiEnv);
std::lock_guard guard(objectsMutex_);
const auto& iter = objects_.find(key);
if (iter == objects_.end()) {
TAG_LOGW(AAFwkTag::CONTEXT, "not found target object");
return;
}
objects_.erase(key);
}
void BindableSubThread::RemoveAllObject()
{
TAG_LOGD(AAFwkTag::CONTEXT, "remove all object");
std::lock_guard guard(objectsMutex_);
objects_.clear();
}
void BindableSubThread::StaticRemoveSubThreadObject(void* arg)
{
TAG_LOGD(AAFwkTag::CONTEXT, "remove sub thread object");
HookData* data = static_cast<HookData*>(arg);
if (data == nullptr) {
return;
}
std::shared_ptr<BindableSubThread> instance = data->instance.lock();
if (instance == nullptr) {
TAG_LOGW(AAFwkTag::CONTEXT, "instance nullptr");
delete data;
return;
}
instance->RemoveSubThreadObject(data->env);
delete data;
}
} // namespace AbilityRuntime
} // namespace OHOS
@@ -21,6 +21,7 @@
#include "ability_manager_client.h"
#include "app_mgr_client.h"
#include "application_context.h"
#include "bindable_sub_thread.h"
#include "bundle_mgr_helper.h"
#include "bundle_mgr_proxy.h"
#include "common_event_manager.h"
@@ -91,6 +92,11 @@ const int AREA2 = 2;
const int AREA3 = 3;
const int AREA4 = 4;
ContextImpl::ContextImpl()
{
subThreadObject_ = std::make_unique<BindableSubThread>();
}
ContextImpl::~ContextImpl()
{
UnsubscribeToOverlayEvents();
@@ -1757,6 +1757,10 @@ napi_value JsApplicationContextUtils::CreateJsApplicationContext(napi_env env)
return nullptr;
}
napi_set_named_property(env, object, "index", applicationContextValue);
std::string type = "ApplicationContext";
napi_set_named_property(env, object, "contextType", CreateJsValue(env, type));
BindNativeApplicationContextOne(env, object);
BindNativeApplicationContextTwo(env, object);
return object;
@@ -1000,6 +1000,10 @@ napi_value CreateJsBaseContext(napi_env env, std::shared_ptr<Context> context, b
return nullptr;
}
napi_set_named_property(env, object, "index", contextValue);
std::string type = "Context";
napi_set_named_property(env, object, "contextType", CreateJsValue(env, type));
const char *moduleName = "JsBaseContext";
BindPropertyAndFunction(env, object, moduleName);
return object;
@@ -30,7 +30,7 @@ namespace OHOS {
namespace AbilityRuntime {
class AbilityContextImpl : public AbilityContext {
public:
AbilityContextImpl() = default;
AbilityContextImpl();
virtual ~AbilityContextImpl() = default;
Global::Resource::DeviceType GetDeviceType() const override;
@@ -35,7 +35,7 @@ public:
const std::unique_ptr<Runtime>& runtime, const AppExecFwk::HapModuleInfo& hapModuleInfo);
ETSAbilityStage(ETSRuntime &etsRuntime, std::unique_ptr<AppExecFwk::ETSNativeReference> &&ETSAbilityStageObj);
~ETSAbilityStage() override {}
~ETSAbilityStage() override;
void Init(const std::shared_ptr<Context> &context,
const std::weak_ptr<AppExecFwk::OHOSApplication> application) override;
@@ -40,6 +40,16 @@ public:
objects_.emplace(typeName, std::move(obj));
}
template<class T>
void Bind(T* object)
{
static_assert(IsValidType<T>(), "T must be ani_ref or NativeReference");
const std::string typeName = GetTypeString<T>();
std::lock_guard guard(objectsMutex_);
std::unique_ptr<void, void (*)(void*)> obj(object, SimpleRelease<T>);
objects_.emplace(typeName, std::move(obj));
}
template<class T>
T* Get()
{
@@ -105,6 +115,23 @@ private:
std::mutex objectsMutex_;
};
class BindingObjectSubThread {
public:
BindingObjectSubThread() = default;
virtual ~BindingObjectSubThread() = default;
virtual void BindSubThreadObject(void* napiEnv, void* object);
virtual void* GetSubThreadObject(void* napiEnv);
virtual void RemoveSubThreadObject(void* napiEnv);
virtual void RemoveAllObject();
private:
BindingObjectSubThread(const BindingObjectSubThread&) = delete;
BindingObjectSubThread(BindingObjectSubThread&&) = delete;
BindingObjectSubThread& operator=(const BindingObjectSubThread&) = delete;
BindingObjectSubThread& operator=(BindingObjectSubThread&&) = delete;
};
class Bindable {
public:
virtual ~Bindable() = default;
@@ -117,11 +144,23 @@ public:
}
}
template<class T>
void Bind(T* object)
{
if (object_) {
object_->Bind(object);
}
}
void Unbind() const
{
if (object_) {
object_->Unbind();
}
if (subThreadObject_) {
subThreadObject_->RemoveAllObject();
}
}
template<class T>
@@ -130,6 +169,10 @@ public:
if (object_) {
object_->Unbind<T>();
}
if (subThreadObject_) {
subThreadObject_->RemoveAllObject();
}
}
const std::unique_ptr<BindingObject>& GetBindingObject() const
@@ -137,8 +180,24 @@ public:
return object_;
}
void BindSubThreadObject(void* napiEnv, void* object)
{
if (subThreadObject_) {
subThreadObject_->BindSubThreadObject(napiEnv, object);
}
}
void* GetSubThreadObject(void* napiEnv)
{
if (subThreadObject_) {
return subThreadObject_->GetSubThreadObject(napiEnv);
}
return nullptr;
}
protected:
Bindable() = default;
std::unique_ptr<BindingObjectSubThread> subThreadObject_ = nullptr;
private:
std::unique_ptr<BindingObject> object_ = std::make_unique<BindingObject>();
@@ -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_BINDABLE_SUB_THREAD_H
#define OHOS_ABILITY_RUNTIME_BINDABLE_SUB_THREAD_H
#include <map>
#include <mutex>
#include <string>
#include "bindable.h"
namespace OHOS {
namespace AbilityRuntime {
class BindableSubThread : public BindingObjectSubThread,
public std::enable_shared_from_this<BindableSubThread> {
public:
BindableSubThread() = default;
virtual ~BindableSubThread();
void BindSubThreadObject(void* napiEnv, void* object) override;
void* GetSubThreadObject(void* napiEnv) override;
void RemoveSubThreadObject(void* napiEnv) override;
void RemoveAllObject() override;
static void StaticRemoveSubThreadObject(void* arg);
private:
BindableSubThread(const BindableSubThread&) = delete;
BindableSubThread(BindableSubThread&&) = delete;
BindableSubThread& operator=(const BindableSubThread&) = delete;
BindableSubThread& operator=(BindableSubThread&&) = delete;
std::mutex objectsMutex_;
std::map<uintptr_t, std::unique_ptr<void, void (*)(void*)>> objects_;
};
} // namespace AbilityRuntime
} // namespace OHOS
#endif // OHOS_ABILITY_RUNTIME_BINDABLE_SUB_THREAD_H
@@ -40,7 +40,8 @@ class Configuration;
namespace AbilityRuntime {
class ApplicationContext;
class Context : public Bindable, public std::enable_shared_from_this<Context> {
class Context : public Bindable,
public std::enable_shared_from_this<Context> {
public:
Context() = default;
~Context() override = default;
@@ -36,7 +36,7 @@ using GetDisplayConfigCallback = std::function<bool(uint64_t displayId, float &d
#endif
class ContextImpl : public Context {
public:
ContextImpl() = default;
ContextImpl();
virtual ~ContextImpl();
/**
@@ -146,14 +146,18 @@ ohos_unittest("context_impl_test") {
"${ability_runtime_innerkits_path}/ability_manager:ability_manager",
"${ability_runtime_innerkits_path}/app_manager:app_manager",
"${ability_runtime_innerkits_path}/deps_wrapper:ability_deps_wrapper",
"${ability_runtime_innerkits_path}/error_utils:ability_runtime_error_util",
"${ability_runtime_native_path}/ability/native:ability_thread",
"${ability_runtime_native_path}/ability/native:abilitykit_native",
"${ability_runtime_native_path}/ability/native:abilitykit_utils",
"${ability_runtime_native_path}/ability/native:configuration_helper",
"${ability_runtime_native_path}/ability/native:uiabilitykit_native",
"${ability_runtime_native_path}/appkit:app_context",
"${ability_runtime_native_path}/appkit:app_context_utils",
"${ability_runtime_native_path}/appkit:appkit_manager_helper",
"${ability_runtime_native_path}/appkit:appkit_native",
"${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common",
"${ability_runtime_path}/js_environment/frameworks/js_environment:js_environment",
]
external_deps = [
@@ -177,6 +181,7 @@ ohos_unittest("context_impl_test") {
"napi:ace_napi",
"resource_management:global_resmgr",
"resource_management:librawfile",
"runtime_core:ani",
"samgr:samgr_proxy",
"runtime_core:ani",
]
@@ -24,8 +24,13 @@
#include "hap_module_info.h"
#include "hilog_tag_wrapper.h"
#include "iremote_object.h"
#include "js_context_utils.h"
#include "js_runtime_utils.h"
#include "js_runtime_lite.h"
#include "mock_ability_token.h"
#include "mock_bundle_manager.h"
#include "napi/native_api.h"
#include "native_engine/native_engine.h"
#include "sys_mgr_client.h"
#include "system_ability_definition.h"
@@ -1878,5 +1883,40 @@ HWTEST_F(ContextImplTest, AppExecFwk_ContextImpl_InitPluginHapModuleInfo_003, Fu
EXPECT_EQ(contextImpl->GetHapModuleInfo(), nullptr);
GTEST_LOG_(INFO) << "AppExecFwk_ContextImpl_InitPluginHapModuleInfo_003 end";
}
/**
* @tc.number: AppExecFwk_ContextImpl_Bind_001
* @tc.name: AppExecFwk_ContextImpl_Bind_001
* @tc.desc: test Bind and UnBind function.
* @tc.type: FUNC
*/
HWTEST_F(ContextImplTest, AppExecFwk_ContextImpl_Bind_001, Function | MediumTest | Level1)
{
TAG_LOGI(AAFwkTag::TEST, "ContextImpl_Bind_001 start");
auto context = std::make_shared<AbilityRuntime::ContextImpl>();
ASSERT_NE(context, nullptr);
std::shared_ptr<JsEnv::JsEnvironment> jsEnv = nullptr;
Options options;
auto errCode = AbilityRuntime::JsRuntimeLite::GetInstance().CreateJsEnv(options, jsEnv);
EXPECT_NE(jsEnv, nullptr);
napi_env napiEnv = reinterpret_cast<napi_env>(jsEnv->GetNativeEngine());
EXPECT_NE(napiEnv, nullptr);
auto value = AbilityRuntime::CreateJsBaseContext(napiEnv, context);
auto systemModule = AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(napiEnv, "application.Context", &value, 1);
EXPECT_NE(systemModule, nullptr);
context->Bind(systemModule.get());
auto &bindingObj = context->GetBindingObject();
ASSERT_NE(bindingObj, nullptr);
auto dynamicContext = bindingObj->Get<NativeReference>();
EXPECT_NE(dynamicContext, nullptr);
EXPECT_EQ(dynamicContext, systemModule.get());
context->Unbind();
TAG_LOGI(AAFwkTag::TEST, "ContextImpl_Bind_001 end");
}
} // namespace AppExecFwk
}