From 71233dbf375497f6bf4ae86e82832339ec15ab6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=BB=E5=9B=BD=E5=86=9B?= Date: Tue, 14 Apr 2026 09:37:30 +0800 Subject: [PATCH] add interopAbilityMonitor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Agent Signed-off-by: 任国军 --- frameworks/ets/ani/ability_delegator/BUILD.gn | 2 + .../include/ets_ability_delegator.h | 16 ++ .../include/ets_interop_ability_monitor.h | 64 +++++ .../src/ets_ability_delegator.cpp | 172 +++++++++++++ .../src/ets_ability_delegator_utils.cpp | 70 ++++-- .../src/ets_interop_ability_monitor.cpp | 233 ++++++++++++++++++ .../ani/ani_common/src/js_interop_object.cpp | 2 +- .../ani/ui_ability/include/ets_ui_ability.h | 7 + .../ets/ani/ui_ability/src/ets_ui_ability.cpp | 136 ++++++---- ...s.app.ability.abilityDelegatorRegistry.ets | 2 + frameworks/ets/ets/BUILD.gn | 18 ++ .../ets/ets/application/AbilityDelegator.ets | 10 + .../ets/application/InteropAbilityMonitor.ets | 48 ++++ .../js/napi/app/ability_delegator/BUILD.gn | 6 + .../interop_ability_monitor.cpp | 125 ++++++++++ .../interop_ability_monitor.h | 50 ++++ .../js_ability_delegator.cpp | 117 +++++++++ .../ability_delegator/js_ability_delegator.h | 24 ++ .../js_ability_delegator_utils.cpp | 4 + .../js_interop_ability_monitor.cpp | 174 +++++++++++++ .../js_interop_ability_monitor.h | 63 +++++ .../native/ability_runtime/js_ui_ability.cpp | 104 ++++++-- frameworks/native/appkit/BUILD.gn | 1 + .../ability_delegator/ability_delegator.cpp | 139 ++++++++--- .../ability_delegator_registry.cpp | 18 ++ .../iinterop_ability_monitor.cpp | 126 ++++++++++ frameworks/native/appkit/app/main_thread.cpp | 36 +++ .../ability_delegator/ability_delegator.h | 18 ++ .../ability_delegator_infos.h | 3 + .../ability_delegator_registry.h | 6 + .../iinterop_ability_monitor.h | 165 +++++++++++++ 31 files changed, 1822 insertions(+), 137 deletions(-) create mode 100644 frameworks/ets/ani/ability_delegator/include/ets_interop_ability_monitor.h create mode 100644 frameworks/ets/ani/ability_delegator/src/ets_interop_ability_monitor.cpp create mode 100644 frameworks/ets/ets/application/InteropAbilityMonitor.ets create mode 100644 frameworks/js/napi/app/ability_delegator/interop_ability_monitor.cpp create mode 100644 frameworks/js/napi/app/ability_delegator/interop_ability_monitor.h create mode 100644 frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.cpp create mode 100644 frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.h create mode 100644 frameworks/native/appkit/ability_delegator/iinterop_ability_monitor.cpp create mode 100644 interfaces/kits/native/appkit/ability_delegator/iinterop_ability_monitor.h diff --git a/frameworks/ets/ani/ability_delegator/BUILD.gn b/frameworks/ets/ani/ability_delegator/BUILD.gn index 9568f863da..b057733e4e 100644 --- a/frameworks/ets/ani/ability_delegator/BUILD.gn +++ b/frameworks/ets/ani/ability_delegator/BUILD.gn @@ -48,6 +48,7 @@ ohos_shared_library("ability_delegator_registry_ani_kit") { "./src/ets_ability_delegator_registry.cpp", "./src/ets_ability_delegator_utils.cpp", "./src/ets_ability_monitor.cpp", + "./src/ets_interop_ability_monitor.cpp", ] cflags = [] @@ -77,6 +78,7 @@ ohos_shared_library("ability_delegator_registry_ani_kit") { "json:nlohmann_json_static", "napi:ace_napi", "runtime_core:ani", + "runtime_core:ani_helpers", ] innerapi_tags = [ "platformsdk" ] diff --git a/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h index a3c6f06583..cf92091958 100644 --- a/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h +++ b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h @@ -22,6 +22,7 @@ #include "ets_ability_delegator_registry.h" #include "ets_ability_monitor.h" #include "ets_ability_stage_monitor.h" +#include "ets_interop_ability_monitor.h" #include "iability_monitor.h" #include "ets_runtime.h" #include "want.h" @@ -97,6 +98,12 @@ public: static ani_ref GetCurrentTopAbility(ani_env *env, [[maybe_unused]]ani_class aniClass, ani_object callback); + static void AddInteropAbilityMonitorSync(ani_env *env, [[maybe_unused]]ani_class aniClass, + ani_object monitorObj); + + static void RemoveInteropAbilityMonitorSync(ani_env *env, [[maybe_unused]]ani_class aniClass, + ani_object monitorObj); + private: static ani_object WrapShellCmdResult(ani_env *env, std::unique_ptr result); @@ -131,6 +138,15 @@ private: static void CleanAndFindMonitorRecord(ani_env *env, ani_object monitorObj); static bool CheckMonitorPara(ani_env *env, ani_object monitorObj); + + static bool ParseInteropMonitorPara(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl); + + static bool ParseInteropMonitorParaInner(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl); + + static std::shared_ptr CleanAndFindInteropMonitorRecord( + ani_env *env, ani_object monitorObj); }; } // namespace AbilityDelegatorEts } // namespace OHOS diff --git a/frameworks/ets/ani/ability_delegator/include/ets_interop_ability_monitor.h b/frameworks/ets/ani/ability_delegator/include/ets_interop_ability_monitor.h new file mode 100644 index 0000000000..9160541833 --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/include/ets_interop_ability_monitor.h @@ -0,0 +1,64 @@ +/* + * 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_INTEROP_ABILITY_MONITOR_H +#define OHOS_ABILITY_RUNTIME_ETS_INTEROP_ABILITY_MONITOR_H + +#include +#include +#include "ani.h" +#include "ets_native_reference.h" +#include "iinterop_ability_monitor.h" +#include + +namespace OHOS { +namespace AbilityDelegatorEts { +class EtsInteropAbilityMonitor : public AppExecFwk::IInteropAbilityMonitor { +public: + explicit EtsInteropAbilityMonitor(const std::string &abilityName); + explicit EtsInteropAbilityMonitor(const std::string &abilityName, const std::string &moduleName); + ~EtsInteropAbilityMonitor() = default; + + void OnAbilityStart(const std::weak_ptr &abilityObj) override; + void OnAbilityForeground(const std::weak_ptr &abilityObj) override; + void OnAbilityBackground(const std::weak_ptr &abilityObj) override; + void OnAbilityStop(const std::weak_ptr &abilityObj) override; + void OnWindowStageCreate(const std::weak_ptr &abilityObj) override; + void OnWindowStageRestore(const std::weak_ptr &abilityObj) override; + void OnWindowStageDestroy(const std::weak_ptr &abilityObj) override; + + void SetEtsInteropAbilityMonitor(ani_env *env, ani_object &monitorObj); + void SetNapiEnv(napi_env env); + + std::unique_ptr &GetEtsInteropAbilityMonitor() + { + return etsInteropMonitor_; + } + +private: + void CallLifecycleCBFunction(const std::string &functionName, + const std::weak_ptr &abilityObj); + ani_object ConvertAbilityToAniRef(const std::weak_ptr &abilityObj); + ani_env *GetAniEnv(); + + ani_vm *vm_ = nullptr; + napi_env napiEnv_ = nullptr; + std::string abilityName_; + std::string moduleName_; + std::unique_ptr etsInteropMonitor_; +}; +} // namespace AbilityDelegatorEts +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_INTEROP_ABILITY_MONITOR_H diff --git a/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator.cpp b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator.cpp index d1af123c70..34ea338822 100644 --- a/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator.cpp +++ b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator.cpp @@ -39,6 +39,8 @@ std::map, sptr, std::owner_less std::mutex g_mtxMonitorRecord; std::mutex g_mtxStageMonitorRecord; std::mutex g_mutexAbilityRecord; +std::map, std::shared_ptr> g_interopMonitorRecord; +std::mutex g_mtxInteropMonitorRecord; namespace { constexpr const char* CONTEXT_CLASS_NAME = "application.Context.Context"; @@ -1268,5 +1270,175 @@ void EtsAbilityDelegator::CleanAndFindMonitorRecord(ani_env *env, ani_object mon ++iter; } } + +void EtsAbilityDelegator::AddInteropAbilityMonitorSync(ani_env *env, [[maybe_unused]]ani_class aniClass, + ani_object monitorObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "AddInteropAbilityMonitorSync called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env is nullptr"); + return; + } + std::shared_ptr monitorImpl = nullptr; + if (!ParseInteropMonitorPara(env, monitorObj, monitorImpl)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "ParseInteropMonitorPara failed"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, + static_cast(AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM), + "Parse param monitor failed, monitor must be InteropAbilityMonitor."); + return; + } + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (delegator) { + monitorImpl->SetLanguage(AbilityRuntime::Runtime::Language::ETS); + delegator->AddInteropAbilityMonitor(monitorImpl); + } else { + TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, COMMON_FAILED, + "Calling AddInteropAbilityMonitorSync failed."); + } + return; +} + +void EtsAbilityDelegator::RemoveInteropAbilityMonitorSync(ani_env *env, [[maybe_unused]]ani_class aniClass, + ani_object monitorObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "RemoveInteropAbilityMonitorSync called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env is nullptr"); + return; + } + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + auto monitor = CleanAndFindInteropMonitorRecord(env, monitorObj); + if (delegator && monitor) { + delegator->RemoveInteropAbilityMonitor(monitor); + } else if (!delegator) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator"); + AbilityRuntime::EtsErrorUtil::ThrowError(env, COMMON_FAILED, + "Calling RemoveInteropAbilityMonitorSync failed."); + } + return; +} + +bool EtsAbilityDelegator::ParseInteropMonitorPara(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl) +{ + if (env == nullptr || monitorObj == nullptr || !CheckMonitorPara(env, monitorObj)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env or monitorObj is nullptr"); + return false; + } + { + std::unique_lock lck(g_mtxInteropMonitorRecord); + TAG_LOGI(AAFwkTag::DELEGATOR, "interopMonitorRecord size: %{public}zu", g_interopMonitorRecord.size()); + for (auto iter = g_interopMonitorRecord.begin(); iter != g_interopMonitorRecord.end();) { + if (iter->first.get() == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "interopMonitorRecord is nullptr"); + iter = g_interopMonitorRecord.erase(iter); + continue; + } + std::shared_ptr etsMonitor = iter->first; + if (etsMonitor == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "etsMonitor is nullptr"); + iter = g_interopMonitorRecord.erase(iter); + continue; + } + ani_boolean result = false; + ani_status status = env->Reference_StrictEquals(reinterpret_cast(monitorObj), + etsMonitor->aniRef, &result); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Reference_StrictEquals failed status: %{public}d", status); + } + if (result) { + TAG_LOGW(AAFwkTag::DELEGATOR, "interop monitor exist"); + monitorImpl = iter->second; + return monitorImpl ? true : false; + } + ++iter; + } + } + if (!ParseInteropMonitorParaInner(env, monitorObj, monitorImpl)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "ParseInteropMonitorParaInner failed"); + return false; + } + return true; +} + +bool EtsAbilityDelegator::ParseInteropMonitorParaInner(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl) +{ + std::string strAbilityName = ""; + if (!GetStringProperty(env, monitorObj, "abilityName", strAbilityName)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GetStringProperty abilityName failed"); + return false; + } + std::string strModuleName = ""; + auto interopMonitor = std::make_shared(strAbilityName); + if (GetStringProperty(env, monitorObj, "moduleName", strModuleName)) { + interopMonitor = std::make_shared(strAbilityName, strModuleName); + } + interopMonitor->SetEtsInteropAbilityMonitor(env, monitorObj); + auto *napiEnvPtr = reinterpret_cast(AppExecFwk::AbilityDelegatorRegistry::GetNapiEnv()); + if (napiEnvPtr != nullptr) { + interopMonitor->SetNapiEnv(napiEnvPtr); + } + monitorImpl = interopMonitor; + + ani_ref monitorRef = nullptr; + if (env->GlobalReference_Create(monitorObj, &monitorRef) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GlobalReference_Create failed"); + return false; + } + auto reference = std::make_shared(); + if (reference != nullptr) { + reference->aniRef = monitorRef; + reference->aniObj = monitorObj; + } + { + std::unique_lock lck(g_mtxInteropMonitorRecord); + g_interopMonitorRecord.emplace(reference, monitorImpl); + } + return true; +} + +std::shared_ptr EtsAbilityDelegator::CleanAndFindInteropMonitorRecord( + ani_env *env, ani_object monitorObj) +{ + if (env == nullptr || monitorObj == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env or monitorObj is nullptr"); + return nullptr; + } + std::unique_lock lck(g_mtxInteropMonitorRecord); + for (auto iter = g_interopMonitorRecord.begin(); iter != g_interopMonitorRecord.end();) { + if (iter->first.get() == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "interopMonitorRecord is nullptr"); + iter = g_interopMonitorRecord.erase(iter); + continue; + } + std::shared_ptr etsMonitor = iter->first; + if (etsMonitor == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "etsMonitor is nullptr"); + iter = g_interopMonitorRecord.erase(iter); + continue; + } + ani_boolean result = false; + ani_status status = env->Reference_StrictEquals(reinterpret_cast(monitorObj), + etsMonitor->aniRef, &result); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Reference_StrictEquals failed status: %{public}d", status); + } + if (result) { + status = env->GlobalReference_Delete(etsMonitor->aniRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GlobalReference_Delete failed status: %{public}d", status); + } + auto monitor = iter->second; + g_interopMonitorRecord.erase(iter); + return monitor; + } + ++iter; + } + return nullptr; +} } // namespace AbilityDelegatorEts } // namespace OHOS diff --git a/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_utils.cpp b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_utils.cpp index fabb30404d..098a28077b 100644 --- a/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_utils.cpp +++ b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_utils.cpp @@ -33,6 +33,8 @@ constexpr const char* WANT_ASYNCCALLBACK = "C{@ohos.app.ability.Want.Want}C{util constexpr const char* ARGS_ABILITY_DELEGATOR_CLASS_NAME = "application.abilityDelegatorArgs.AbilityDelegatorArgsInner"; constexpr const char* SIGNATURE_MONITOR_VOID = "C{application.AbilityMonitor.AbilityMonitor}:"; +constexpr const char* INTEROP_MONITOR_VOID = + "C{application.InteropAbilityMonitor.InteropAbilityMonitor}:"; constexpr const char* SIGNATURE_MONITOR_NUMBER_ASYNCCALLBACK = "C{application.AbilityMonitor.AbilityMonitor}lC{utils.AbilityUtils.AsyncCallbackWrapper}:"; constexpr const char* STAGEMONITOR_ASYNCCALLBACK_VOID = @@ -55,25 +57,45 @@ constexpr const char* RECORD_SET_NAME = "X{C{std.core.BaseEnum}C{std.core.Numeric}C{std.core.String}}Y:"; } -bool BindFunctions(ani_env *aniEnv, ani_class abilityDelegator) +auto GetBaseNativeFunctions() { - if (aniEnv == nullptr) { - return false; - } - std::array functions = { + return std::array { ani_native_function {"getAppContext", VOID_CONTEXT, reinterpret_cast(EtsAbilityDelegator::GetAppContext)}, ani_native_function {"nativeExecuteShellCommand", STRING_NUMBER_ASYNCCALLBACK, reinterpret_cast(EtsAbilityDelegator::ExecuteShellCommand)}, ani_native_function {"nativeFinishTest", STRING_NUMBER_ASYNCCALLBACK, reinterpret_cast(EtsAbilityDelegator::FinishTest)}, - ani_native_function {"printSync", STRING_VOID, reinterpret_cast(EtsAbilityDelegator::PrintSync)}, + ani_native_function {"printSync", STRING_VOID, + reinterpret_cast(EtsAbilityDelegator::PrintSync)}, + ani_native_function {"nativeStartAbility", WANT_ASYNCCALLBACK, + reinterpret_cast(EtsAbilityDelegator::StartAbility)}, + ani_native_function {"printAsync", STRING_ASYNCCALLBACK_VOID, + reinterpret_cast(EtsAbilityDelegator::Print)}, + ani_native_function {"getAbilityState", STRING_UIABILITY_NUMBER, + reinterpret_cast(EtsAbilityDelegator::GetAbilityState)}, + ani_native_function {"nativeGetCurrentTopAbility", STRING_CALLBACK_UIABILITY, + reinterpret_cast(EtsAbilityDelegator::GetCurrentTopAbility)}, + ani_native_function {"doAbilityForegroundAsync", STAGEMONITOR_UIABILITY_ASYNCCALLBACK, + reinterpret_cast(EtsAbilityDelegator::DoAbilityForeground)}, + ani_native_function {"doAbilityForegroundOrBackgroundCheck", STAGEMONITOR_UIABILITY_CHECK, + reinterpret_cast(EtsAbilityDelegator::DoAbilityForegroundOrBackgroundCheck)}, + ani_native_function {"doAbilityBackgroundAsync", STAGEMONITOR_UIABILITY_ASYNCCALLBACK, + reinterpret_cast(EtsAbilityDelegator::DoAbilityBackground)}, + ani_native_function {"addInteropAbilityMonitorSync", INTEROP_MONITOR_VOID, + reinterpret_cast(EtsAbilityDelegator::AddInteropAbilityMonitorSync)}, + ani_native_function {"removeInteropAbilityMonitorSync", INTEROP_MONITOR_VOID, + reinterpret_cast(EtsAbilityDelegator::RemoveInteropAbilityMonitorSync)} + }; +} + +auto GetMonitorNativeFunctions() +{ + return std::array { ani_native_function {"nativeAddAbilityMonitor", MONITOR_ASYNCCALLBACK_VOID, reinterpret_cast(EtsAbilityDelegator::AddAbilityMonitor)}, ani_native_function {"addAbilityMonitorCheck", SIGNATURE_MONITOR_VOID, reinterpret_cast(EtsAbilityDelegator::AddAbilityMonitorCheck)}, - ani_native_function {"nativeStartAbility", WANT_ASYNCCALLBACK, - reinterpret_cast(EtsAbilityDelegator::StartAbility)}, ani_native_function {"addAbilityMonitorSync", SIGNATURE_MONITOR_VOID, reinterpret_cast(EtsAbilityDelegator::AddAbilityMonitorSync)}, ani_native_function {"removeAbilityMonitorAsync", MONITOR_ASYNCCALLBACK_VOID, @@ -97,20 +119,13 @@ bool BindFunctions(ani_env *aniEnv, ani_class abilityDelegator) ani_native_function {"removeAbilityStageMonitorCheck", STAGEMONITOR_VOID, reinterpret_cast(EtsAbilityDelegator::RemoveAbilityStageMonitorCheck)}, ani_native_function {"waitAbilityStageMonitorAsync", SIGNATURE_STAGEMONITOR_NUMBER_ASYNCCALLBACK, - reinterpret_cast(EtsAbilityDelegator::WaitAbilityStageMonitor)}, - ani_native_function {"doAbilityForegroundAsync", STAGEMONITOR_UIABILITY_ASYNCCALLBACK, - reinterpret_cast(EtsAbilityDelegator::DoAbilityForeground)}, - ani_native_function {"doAbilityForegroundOrBackgroundCheck", STAGEMONITOR_UIABILITY_CHECK, - reinterpret_cast(EtsAbilityDelegator::DoAbilityForegroundOrBackgroundCheck)}, - ani_native_function {"doAbilityBackgroundAsync", STAGEMONITOR_UIABILITY_ASYNCCALLBACK, - reinterpret_cast(EtsAbilityDelegator::DoAbilityBackground)}, - ani_native_function {"printAsync", STRING_ASYNCCALLBACK_VOID, - reinterpret_cast(EtsAbilityDelegator::Print)}, - ani_native_function {"getAbilityState", STRING_UIABILITY_NUMBER, - reinterpret_cast(EtsAbilityDelegator::GetAbilityState)}, - ani_native_function {"nativeGetCurrentTopAbility", STRING_CALLBACK_UIABILITY, - reinterpret_cast(EtsAbilityDelegator::GetCurrentTopAbility)} + reinterpret_cast(EtsAbilityDelegator::WaitAbilityStageMonitor)} }; +} + +template +bool BindNativeArray(ani_env *aniEnv, ani_class abilityDelegator, const T &functions) +{ ani_status status = aniEnv->Class_BindNativeMethods(abilityDelegator, functions.data(), functions.size()); if (status != ANI_OK) { TAG_LOGE(AAFwkTag::DELEGATOR, "Class_BindNativeMethods failed status: %{public}d", status); @@ -119,6 +134,19 @@ bool BindFunctions(ani_env *aniEnv, ani_class abilityDelegator) return true; } +bool BindFunctions(ani_env *aniEnv, ani_class abilityDelegator) +{ + if (aniEnv == nullptr) { + return false; + } + auto baseFuncs = GetBaseNativeFunctions(); + auto monitorFuncs = GetMonitorNativeFunctions(); + if (!BindNativeArray(aniEnv, abilityDelegator, baseFuncs)) { + return false; + } + return BindNativeArray(aniEnv, abilityDelegator, monitorFuncs); +} + ani_object CreateEtsAbilityDelegator(ani_env *aniEnv) { TAG_LOGD(AAFwkTag::DELEGATOR, "CreateEtsAbilityDelegator"); diff --git a/frameworks/ets/ani/ability_delegator/src/ets_interop_ability_monitor.cpp b/frameworks/ets/ani/ability_delegator/src/ets_interop_ability_monitor.cpp new file mode 100644 index 0000000000..b8b3da0c3b --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/src/ets_interop_ability_monitor.cpp @@ -0,0 +1,233 @@ +/* + * 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_interop_ability_monitor.h" +#include "ability_delegator_infos.h" +#include "ability_delegator_registry.h" +#include "ets_native_reference.h" +#include "hilog_tag_wrapper.h" +#include "interop_js/hybridgref_ani.h" +#include "interop_js/hybridgref_napi.h" +#include "native_engine/native_reference.h" + +namespace OHOS { +namespace AbilityDelegatorEts { +using namespace OHOS::AbilityRuntime; + +EtsInteropAbilityMonitor::EtsInteropAbilityMonitor(const std::string &abilityName) + : IInteropAbilityMonitor(abilityName), abilityName_(abilityName) +{} + +EtsInteropAbilityMonitor::EtsInteropAbilityMonitor(const std::string &abilityName, const std::string &moduleName) + : IInteropAbilityMonitor(abilityName, moduleName), abilityName_(abilityName), moduleName_(moduleName) +{} + +void EtsInteropAbilityMonitor::OnAbilityStart( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityStart"); + CallLifecycleCBFunction("onAbilityCreate", abilityObj); +} + +void EtsInteropAbilityMonitor::OnAbilityForeground( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityForeground"); + CallLifecycleCBFunction("onAbilityForeground", abilityObj); +} + +void EtsInteropAbilityMonitor::OnAbilityBackground( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityBackground"); + CallLifecycleCBFunction("onAbilityBackground", abilityObj); +} + +void EtsInteropAbilityMonitor::OnAbilityStop( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityStop"); + CallLifecycleCBFunction("onAbilityDestroy", abilityObj); +} + +void EtsInteropAbilityMonitor::OnWindowStageCreate( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnWindowStageCreate"); + CallLifecycleCBFunction("onWindowStageCreate", abilityObj); +} + +void EtsInteropAbilityMonitor::OnWindowStageRestore( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnWindowStageRestore"); + CallLifecycleCBFunction("onWindowStageRestore", abilityObj); +} + +void EtsInteropAbilityMonitor::OnWindowStageDestroy( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnWindowStageDestroy"); + CallLifecycleCBFunction("onWindowStageDestroy", abilityObj); +} + +void EtsInteropAbilityMonitor::SetEtsInteropAbilityMonitor(ani_env *env, ani_object &monitorObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called SetEtsInteropAbilityMonitor"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + etsInteropMonitor_ = std::make_unique(); + ani_ref objRef = nullptr; + if (env->GlobalReference_Create(monitorObj, &objRef) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GlobalReference_Create failed"); + return; + } + + ani_vm *aniVM = nullptr; + if (env->GetVM(&aniVM) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GetVM failed"); + return; + } + vm_ = aniVM; + if (etsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null etsInteropMonitor_"); + return; + } + etsInteropMonitor_->aniObj = monitorObj; + etsInteropMonitor_->aniRef = objRef; +} + +void EtsInteropAbilityMonitor::SetNapiEnv(napi_env env) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called SetNapiEnv"); + napiEnv_ = env; +} + +ani_object EtsInteropAbilityMonitor::ConvertAbilityToAniRef( + const std::weak_ptr &abilityObj) +{ + ani_env *aniEnv = GetAniEnv(); + if (napiEnv_ == nullptr || aniEnv == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null napiEnv_ or aniEnv, fallback to null"); + return nullptr; + } + + auto property = abilityObj.lock(); + if (property == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null property, fallback to null"); + return nullptr; + } + + auto jsProperty = std::static_pointer_cast(property); + if (jsProperty == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null jsProperty, fallback to null"); + return nullptr; + } + + auto jsRef = jsProperty->object_.lock(); + if (jsRef == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null jsRef, fallback to null"); + return nullptr; + } + + napi_value napiValue = jsRef->GetNapiValue(); + if (napiValue == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null napiValue, fallback to null"); + return nullptr; + } + + hybridgref href = nullptr; + if (!hybridgref_create_from_napi(napiEnv_, napiValue, &href) || href == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "hybridgref_create_from_napi failed, fallback to null"); + return nullptr; + } + + ani_object result = nullptr; + bool success = hybridgref_get_esvalue(aniEnv, href, &result); + hybridgref_delete_from_napi(napiEnv_, href); + + if (!success || result == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "hybridgref_get_esvalue failed, fallback to null"); + return nullptr; + } + + return result; +} + +void EtsInteropAbilityMonitor::CallLifecycleCBFunction(const std::string &functionName, + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "CallLifecycleCBFunction, name: %{public}s start", functionName.c_str()); + if (functionName.empty()) { + TAG_LOGE(AAFwkTag::DELEGATOR, "empty funcName"); + return; + } + + if (etsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null etsInteropMonitor_"); + return; + } + + ani_env *env = GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + + ani_status status = ANI_OK; + ani_object monitorObj = reinterpret_cast(etsInteropMonitor_->aniRef); + ani_ref funRef; + status = env->Object_GetPropertyByName_Ref(monitorObj, functionName.c_str(), &funRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_GetPropertyByName_Ref failed status: %{public}d", status); + return; + } + ani_boolean isValue = false; + ani_boolean isUndefined = false; + env->Reference_IsNullishValue(funRef, &isValue); + env->Reference_IsUndefined(funRef, &isUndefined); + if (isUndefined || isValue) { + return; + } + ani_fn_object onFn = reinterpret_cast(funRef); + + ani_ref abilityRef = reinterpret_cast(ConvertAbilityToAniRef(abilityObj)); + if (abilityRef == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null abilityRef, fallback to undefined"); + env->GetUndefined(reinterpret_cast(&abilityRef)); + } + std::vector argv = { abilityRef }; + ani_ref result; + if ((status = env->FunctionalObject_Call(onFn, 1, argv.data(), &result)) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "FunctionalObject_Call failed, status: %{public}d", status); + return; + } +} + +ani_env *EtsInteropAbilityMonitor::GetAniEnv() +{ + if (vm_ == nullptr) { + return nullptr; + } + ani_env *aniEnv = nullptr; + if (vm_->GetEnv(ANI_VERSION_1, &aniEnv) != ANI_OK) { + return nullptr; + } + return aniEnv; +} +} // namespace AbilityDelegatorEts +} // namespace OHOS diff --git a/frameworks/ets/ani/ani_common/src/js_interop_object.cpp b/frameworks/ets/ani/ani_common/src/js_interop_object.cpp index 35072ee17c..c8d884e6cf 100644 --- a/frameworks/ets/ani/ani_common/src/js_interop_object.cpp +++ b/frameworks/ets/ani/ani_common/src/js_interop_object.cpp @@ -104,4 +104,4 @@ extern "C" ETS_EXPORT InteropObject* OHOS_CreateJsInteropObject(const Runtime &r return new (std::nothrow) JsInteropObject(env, ref); } } // namespace AbilityRuntime -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h b/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h index 753b072786..abab594a8a 100644 --- a/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h +++ b/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h @@ -23,6 +23,9 @@ #include "ets_runtime.h" namespace OHOS { +namespace AppExecFwk { +class AbilityDelegator; +} // namespace AppExecFwk namespace AbilityRuntime { struct InsightIntentExecutorInfo; using AbilityHandler = AppExecFwk::AbilityHandler; @@ -351,6 +354,10 @@ private: bool CheckSatisfyTargetAPIVersion(int32_t targetAPIVersion); bool BackPressDefaultValue(); void WriteLifecycleSwitchLog(const std::string lifecycleName); + void NotifyDelegatorProperty( + std::function &, + const std::shared_ptr &)> notifyFunc); + bool SetLastRequestWant(ani_env *env, ani_ref wantRef); int32_t CallSaveState(ani_value args[], WantParams &wantParams, AppExecFwk::StateReason stateReason, AppExecFwk::AbilityTransactionCallbackInfo *callbackInfo); diff --git a/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp b/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp index c5b87450a6..8321704401 100644 --- a/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp +++ b/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp @@ -512,6 +512,38 @@ void EtsUIAbility::WriteLifecycleSwitchLog(const std::string lifecycleName) } } +void EtsUIAbility::NotifyDelegatorProperty( + std::function &, + const std::shared_ptr &)> notifyFunc) +{ + auto property = std::make_shared(); + property->language_ = AbilityRuntime::Runtime::Language::ETS; + if (!CreateProperty(abilityContext_, property)) { + return; + } + property->object_ = etsAbilityObj_; + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (delegator) { + notifyFunc(std::static_pointer_cast(delegator), property); + } + auto jsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::JS); + if (jsDelegator && jsDelegator != delegator) { + notifyFunc(std::static_pointer_cast(jsDelegator), property); + } +} + +bool EtsUIAbility::SetLastRequestWant(ani_env *env, ani_ref wantRef) +{ + ani_status status = env->Object_SetFieldByName_Ref(etsAbilityObj_->aniObj, "lastRequestWant", wantRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "lastRequestWant Object_SetFieldByName_Ref status: %{public}d", status); + return false; + } + return true; +} + void EtsUIAbility::OnStart(const Want &want, sptr sessionInfo) { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); @@ -544,7 +576,7 @@ void EtsUIAbility::OnStartInner(ani_env *env, const Want &want, sptrObject_SetFieldByName_Ref(etsAbilityObj_->aniObj, "lastRequestWant", wantObj)) != ANI_OK) { - TAG_LOGE(AAFwkTag::UIABILITY, "lastRequestWant Object_SetFieldByName_Ref status: %{public}d", status); + TAG_LOGE(AAFwkTag::UIABILITY, "lastRequestWant status: %{public}d", status); return; } SetSelfSpecifiedId(env, sessionInfo); @@ -564,22 +596,14 @@ void EtsUIAbility::OnStartInner(ani_env *env, const Want &want, sptr(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformStart"); - property->object_ = etsAbilityObj_; - delegator->PostPerformStart(property); - } + NotifyDelegatorProperty([](const std::shared_ptr &d, + const std::shared_ptr &p) { d->PostPerformStart(p); }); applicationContext = AbilityRuntime::Context::GetApplicationContext(); if (applicationContext != nullptr) { - TAG_LOGD(AAFwkTag::UIABILITY, "call DispatchOnAbilityCreate"); EtsAbilityLifecycleCallbackArgs ability(etsAbilityObj_); applicationContext->DispatchOnAbilityCreate(ability); DISPATCH_ABILITY_INTEROP(OnAbilityCreate, applicationContext, etsRuntime_, ability); } - TAG_LOGD(AAFwkTag::UIABILITY, "OnStart end"); } int32_t EtsUIAbility::OnShare(WantParams &wantParam) @@ -701,13 +725,21 @@ void EtsUIAbility::OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> *callback void EtsUIAbility::OnStopCallback() { - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( - AbilityRuntime::Runtime::Language::ETS); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformStop"); + property->language_ = AbilityRuntime::Runtime::Language::ETS; + if (CreateProperty(abilityContext_, property)) { property->object_ = etsAbilityObj_; - delegator->PostPerformStop(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformStop"); + delegator->PostPerformStop(property); + } + auto jsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::JS); + if (jsDelegator && jsDelegator != delegator) { + jsDelegator->PostPerformStop(property); + } } bool ret = ConnectionManager::GetInstance().DisconnectCaller(AbilityContext::token_); if (ret) { @@ -754,24 +786,15 @@ void EtsUIAbility::OnSceneCreated() } WriteLifecycleSwitchLog("onWindowStageCreate"); CallObjectMethod(false, "onWindowStageCreate", nullptr, etsAppWindowStage); - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( - AbilityRuntime::Runtime::Language::ETS); - auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformScenceCreated"); - property->object_ = etsAbilityObj_; - delegator->PostPerformScenceCreated(property); - } - + NotifyDelegatorProperty([](const std::shared_ptr &d, + const std::shared_ptr &p) { d->PostPerformScenceCreated(p); }); applicationContext = AbilityRuntime::Context::GetApplicationContext(); if (applicationContext != nullptr && etsAbilityObj_ != nullptr && etsWindowStageObj_ != nullptr) { - TAG_LOGD(AAFwkTag::UIABILITY, "call DispatchOnWindowStageCreate"); EtsAbilityLifecycleCallbackArgs ability(etsAbilityObj_); EtsAbilityLifecycleCallbackArgs stage(etsWindowStageObj_); applicationContext->DispatchOnWindowStageCreate(ability, stage); DISPATCH_WINDOW_INTEROP(OnWindowStageCreate, applicationContext, etsRuntime_, ability, stage); } - TAG_LOGD(AAFwkTag::UIABILITY, "OnSceneCreated end"); } ani_object EtsUIAbility::GetEtsWindowStage() @@ -882,13 +905,21 @@ void EtsUIAbility::onSceneDestroyed() window->UnregisterDisplayMoveListener(abilityDisplayMoveListener_); } } - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( - AbilityRuntime::Runtime::Language::ETS); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformScenceDestroyed"); + property->language_ = AbilityRuntime::Runtime::Language::ETS; + if (CreateProperty(abilityContext_, property)) { property->object_ = etsAbilityObj_; - delegator->PostPerformScenceDestroyed(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformScenceDestroyed"); + delegator->PostPerformScenceDestroyed(property); + } + auto jsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::JS); + if (jsDelegator && jsDelegator != delegator) { + jsDelegator->PostPerformScenceDestroyed(property); + } } applicationContext = AbilityRuntime::Context::GetApplicationContext(); @@ -926,40 +957,31 @@ void EtsUIAbility::CallOnForegroundFunc(const Want &want) TAG_LOGE(AAFwkTag::UIABILITY, "null etsAbilityObj_"); return; } - ani_status status = ANI_ERROR; ani_ref wantRef = AppExecFwk::WrapWant(env, want); if (wantRef == nullptr) { TAG_LOGE(AAFwkTag::UIABILITY, "null wantObj"); return; } + if (!SetLastRequestWant(env, wantRef)) { + return; + } auto applicationContext = AbilityRuntime::Context::GetApplicationContext(); if (applicationContext != nullptr) { EtsAbilityLifecycleCallbackArgs ability(etsAbilityObj_); applicationContext->DispatchOnAbilityWillForeground(ability); } - if ((status = env->Object_SetFieldByName_Ref(etsAbilityObj_->aniObj, "lastRequestWant", wantRef)) != ANI_OK) { - TAG_LOGE(AAFwkTag::UIABILITY, "lastRequestWant Object_SetFieldByName_Ref status: %{public}d", status); - return; - } WriteLifecycleSwitchLog("onForeground"); CallObjectMethod(false, "onForeground", nullptr, wantRef); - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( - AbilityRuntime::Runtime::Language::ETS); - auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformForeground"); - property->object_ = etsAbilityObj_; - delegator->PostPerformForeground(property); - } - + NotifyDelegatorProperty([](const std::shared_ptr &d, + const std::shared_ptr &p) { + d->PostPerformForeground(p); + }); applicationContext = AbilityRuntime::Context::GetApplicationContext(); if (applicationContext != nullptr) { - TAG_LOGD(AAFwkTag::UIABILITY, "call DispatchOnAbilityForeground"); EtsAbilityLifecycleCallbackArgs ability(etsAbilityObj_); applicationContext->DispatchOnAbilityForeground(ability); DISPATCH_ABILITY_INTEROP(OnAbilityForeground, applicationContext, etsRuntime_, ability); } - TAG_LOGD(AAFwkTag::UIABILITY, "CallOnForegroundFunc end"); } void EtsUIAbility::OnBackground() @@ -974,13 +996,21 @@ void EtsUIAbility::OnBackground() WriteLifecycleSwitchLog("onBackground"); CallObjectMethod(false, "onBackground", nullptr); UIAbility::OnBackground(); - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( - AbilityRuntime::Runtime::Language::ETS); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformBackground"); + property->language_ = AbilityRuntime::Runtime::Language::ETS; + if (CreateProperty(abilityContext_, property)) { property->object_ = etsAbilityObj_; - delegator->PostPerformBackground(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformBackground"); + delegator->PostPerformBackground(property); + } + auto jsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::JS); + if (jsDelegator && jsDelegator != delegator) { + jsDelegator->PostPerformBackground(property); + } } applicationContext = AbilityRuntime::Context::GetApplicationContext(); diff --git a/frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets b/frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets index 108c50d15c..1975475fcd 100644 --- a/frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets +++ b/frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets @@ -18,6 +18,7 @@ import { AbilityDelegatorArgs as _AbilityDelegatorArgs } from 'application.abili import { AbilityMonitor as _AbilityMonitor } from 'application.AbilityMonitor'; import { AbilityStageMonitor as _AbilityStageMonitor } from 'application.AbilityStageMonitor'; import { ShellCmdResult as _ShellCmdResult } from 'application.shellCmdResult'; +import { InteropAbilityMonitor as _InteropAbilityMonitor} from 'application.InteropAbilityMonitor'; export default namespace abilityDelegatorRegistry { loadLibraryWithPermissionCheck("ability_delegator_registry_ani_kit.z", "@ohos.app.ability.abilityDelegatorRegistry") @@ -38,4 +39,5 @@ export default namespace abilityDelegatorRegistry { export type AbilityMonitor = _AbilityMonitor; export type ShellCmdResult = _ShellCmdResult; export type AbilityStageMonitor = _AbilityStageMonitor; + export type InteropAbilityMonitor = _InteropAbilityMonitor; } diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index 00ac52cd6a..607b1d3112 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -796,6 +796,23 @@ ohos_prebuilt_etc("ability_delegator_ability_monitor_abc_etc") { deps = [ ":ability_delegator_ability_monitor_abc" ] } +generate_static_abc("ability_delegator_interop_ability_monitor_abc") { + base_url = "." + files = [ "./application/InteropAbilityMonitor.ets" ] + + is_boot_abc = "True" + device_dst_file = + "/system/framework/ability_delegator_interop_ability_monitor_abc.abc" +} + +ohos_prebuilt_etc("ability_delegator_interop_ability_monitor_abc_etc") { + source = "$target_out_dir/ability_delegator_interop_ability_monitor_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_delegator_interop_ability_monitor_abc" ] +} + generate_static_abc("ability_runtime_ability_stage_monitor_abc") { base_url = "./" files = [ "./application/AbilityStageMonitor.ets" ] @@ -2098,6 +2115,7 @@ group("ets_packages") { ":ability_application_abc_etc", ":ability_delegator_abc_etc", ":ability_delegator_ability_monitor_abc_etc", + ":ability_delegator_interop_ability_monitor_abc_etc", ":ability_delegator_application_testRunner_abc_etc", ":ability_delegator_args_abc_etc", ":ability_delegator_registry_abc_etc", diff --git a/frameworks/ets/ets/application/AbilityDelegator.ets b/frameworks/ets/ets/application/AbilityDelegator.ets index 2074e3a0db..80a88b01de 100644 --- a/frameworks/ets/ets/application/AbilityDelegator.ets +++ b/frameworks/ets/ets/application/AbilityDelegator.ets @@ -14,6 +14,7 @@ */ import { AbilityMonitor } from 'application.AbilityMonitor'; +import { InteropAbilityMonitor } from 'application.InteropAbilityMonitor'; import Want from '@ohos.app.ability.Want'; import Context from 'application.Context'; import { BusinessError, AsyncCallback } from '@ohos.base'; @@ -97,6 +98,10 @@ export interface AbilityDelegator { getCurrentTopAbility(callback: AsyncCallback); getCurrentTopAbility(): Promise; + + addInteropAbilityMonitorSync(monitor: InteropAbilityMonitor): void; + + removeInteropAbilityMonitorSync(monitor: InteropAbilityMonitor): void; } class AbilityDelegatorInner implements AbilityDelegator { @@ -154,6 +159,10 @@ class AbilityDelegatorInner implements AbilityDelegator { public native getAbilityState(ability: UIAbility): int; + public native addInteropAbilityMonitorSync(monitor: InteropAbilityMonitor): void; + + public native removeInteropAbilityMonitorSync(monitor: InteropAbilityMonitor): void; + public native nativeStartAbility(want: Want, callback: AsyncCallbackWrapper): void; finishTest(msg: string, code: long, callback: AsyncCallback): void { @@ -509,4 +518,5 @@ class AbilityDelegatorInner implements AbilityDelegator { }); return p; } + } diff --git a/frameworks/ets/ets/application/InteropAbilityMonitor.ets b/frameworks/ets/ets/application/InteropAbilityMonitor.ets new file mode 100644 index 0000000000..a6194bcf01 --- /dev/null +++ b/frameworks/ets/ets/application/InteropAbilityMonitor.ets @@ -0,0 +1,48 @@ +/* + * 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 UIAbility from '@ohos.app.ability.UIAbility'; + +export default interface InteropAbilityMonitor { + + moduleName: string; + abilityName: string; + onAbilityCreate: (ability: UIAbility) => void; + onAbilityForeground: (ability: UIAbility) => void; + onAbilityBackground: (ability: UIAbility) => void; + onAbilityDestroy: (ability: UIAbility) => void; + onWindowStageCreate: (ability: UIAbility) => void; + onWindowStageRestore: (ability: UIAbility) => void; + onWindowStageDestroy: (ability: UIAbility) => void; + +} + +class InteropAbilityMonitorInner implements InteropAbilityMonitor { + moduleName: string = ""; + abilityName: string = ""; + onAbilityCreate: (ability: UIAbility) => void = (ability: UIAbility) => { + }; + onAbilityForeground: (ability: UIAbility) => void = (ability: UIAbility) => { + }; + onAbilityBackground: (ability: UIAbility) => void = (ability: UIAbility) => { + }; + onAbilityDestroy: (ability: UIAbility) => void = (ability: UIAbility) => { + }; + onWindowStageCreate: (ability: UIAbility) => void = (ability: UIAbility) => { + }; + onWindowStageRestore: (ability: UIAbility) => void = (ability: UIAbility) => { + }; + onWindowStageDestroy: (ability: UIAbility) => void = (ability: UIAbility) => { + }; +} diff --git a/frameworks/js/napi/app/ability_delegator/BUILD.gn b/frameworks/js/napi/app/ability_delegator/BUILD.gn index 16bd8beec7..75eff33151 100644 --- a/frameworks/js/napi/app/ability_delegator/BUILD.gn +++ b/frameworks/js/napi/app/ability_delegator/BUILD.gn @@ -27,14 +27,17 @@ template("delegator") { "${ability_runtime_path}/interfaces/kits/native/appkit/ability_delegator/", "${ability_runtime_path}/interfaces/kits/native/ability/native", "${ability_runtime_path}/tools/aa/include", + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", ] sources = [ "ability_monitor.cpp", + "interop_ability_monitor.cpp", "js_ability_delegator.cpp", "js_ability_delegator_registry.cpp", "js_ability_delegator_utils.cpp", "js_ability_monitor.cpp", + "js_interop_ability_monitor.cpp", "native_module.cpp", ] @@ -50,6 +53,7 @@ template("delegator") { "${ability_runtime_native_path}/ability/native:abilitykit_native", "${ability_runtime_native_path}/appkit:app_context_utils", "${ability_runtime_native_path}/appkit:appkit_delegator", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", ] external_deps = [ @@ -64,6 +68,8 @@ template("delegator") { "ipc:ipc_napi", "ipc:ipc_single", "napi:ace_napi", + "runtime_core:ani", + "runtime_core:ani_helpers", ] cflags_cc = [] diff --git a/frameworks/js/napi/app/ability_delegator/interop_ability_monitor.cpp b/frameworks/js/napi/app/ability_delegator/interop_ability_monitor.cpp new file mode 100644 index 0000000000..5b3410b32a --- /dev/null +++ b/frameworks/js/napi/app/ability_delegator/interop_ability_monitor.cpp @@ -0,0 +1,125 @@ +/* + * 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 "interop_ability_monitor.h" +#include "js_ability_delegator_utils.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AbilityDelegatorJs { +using namespace OHOS::AbilityRuntime; + +InteropAbilityMonitor::InteropAbilityMonitor(const std::string &name, + const std::shared_ptr &jsInteropAbilityMonitor) + : IInteropAbilityMonitor(name), jsInteropMonitor_(jsInteropAbilityMonitor) +{} + +InteropAbilityMonitor::InteropAbilityMonitor(const std::string &name, const std::string &moduleName, + const std::shared_ptr &jsInteropAbilityMonitor) + : IInteropAbilityMonitor(name, moduleName), jsInteropMonitor_(jsInteropAbilityMonitor) +{} + +void InteropAbilityMonitor::OnAbilityStart( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + + if (jsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsInteropMonitor_ is nullptr"); + return; + } + + jsInteropMonitor_->OnAbilityCreate(abilityObj); +} + +void InteropAbilityMonitor::OnAbilityForeground( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + + if (jsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsInteropMonitor_ is nullptr"); + return; + } + + jsInteropMonitor_->OnAbilityForeground(abilityObj); +} + +void InteropAbilityMonitor::OnAbilityBackground( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + + if (jsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsInteropMonitor_ is nullptr"); + return; + } + + jsInteropMonitor_->OnAbilityBackground(abilityObj); +} + +void InteropAbilityMonitor::OnAbilityStop( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + + if (jsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsInteropMonitor_ is nullptr"); + return; + } + + jsInteropMonitor_->OnAbilityDestroy(abilityObj); +} + +void InteropAbilityMonitor::OnWindowStageCreate( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + + if (jsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsInteropMonitor_ is nullptr"); + return; + } + + jsInteropMonitor_->OnWindowStageCreate(abilityObj); +} + +void InteropAbilityMonitor::OnWindowStageRestore( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + + if (jsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsInteropMonitor_ is nullptr"); + return; + } + + jsInteropMonitor_->OnWindowStageRestore(abilityObj); +} + +void InteropAbilityMonitor::OnWindowStageDestroy( + const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + + if (jsInteropMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsInteropMonitor_ is nullptr"); + return; + } + + jsInteropMonitor_->OnWindowStageDestroy(abilityObj); +} +} // namespace AbilityDelegatorJs +} // namespace OHOS diff --git a/frameworks/js/napi/app/ability_delegator/interop_ability_monitor.h b/frameworks/js/napi/app/ability_delegator/interop_ability_monitor.h new file mode 100644 index 0000000000..4a3dba29b9 --- /dev/null +++ b/frameworks/js/napi/app/ability_delegator/interop_ability_monitor.h @@ -0,0 +1,50 @@ +/* + * 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_INTEROP_ABILITY_MONITOR_H +#define OHOS_ABILITY_RUNTIME_INTEROP_ABILITY_MONITOR_H + +#include +#include "iinterop_ability_monitor.h" +#include "js_interop_ability_monitor.h" +#include "native_engine/native_reference.h" + +namespace OHOS { +namespace AbilityDelegatorJs { +using namespace OHOS::AppExecFwk; +class InteropAbilityMonitor : public IInteropAbilityMonitor { +public: + InteropAbilityMonitor(const std::string &name, + const std::shared_ptr &jsInteropAbilityMonitor); + + InteropAbilityMonitor(const std::string &name, const std::string &moduleName, + const std::shared_ptr &jsInteropAbilityMonitor); + + ~InteropAbilityMonitor() = default; + + void OnAbilityStart(const std::weak_ptr &abilityObj) override; + void OnAbilityForeground(const std::weak_ptr &abilityObj) override; + void OnAbilityBackground(const std::weak_ptr &abilityObj) override; + void OnAbilityStop(const std::weak_ptr &abilityObj) override; + void OnWindowStageCreate(const std::weak_ptr &abilityObj) override; + void OnWindowStageRestore(const std::weak_ptr &abilityObj) override; + void OnWindowStageDestroy(const std::weak_ptr &abilityObj) override; + +private: + std::shared_ptr jsInteropMonitor_; +}; +} // namespace AbilityDelegatorJs +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_INTEROP_ABILITY_MONITOR_H diff --git a/frameworks/js/napi/app/ability_delegator/js_ability_delegator.cpp b/frameworks/js/napi/app/ability_delegator/js_ability_delegator.cpp index a12b0d6642..214b2acd2a 100644 --- a/frameworks/js/napi/app/ability_delegator/js_ability_delegator.cpp +++ b/frameworks/js/napi/app/ability_delegator/js_ability_delegator.cpp @@ -53,6 +53,7 @@ std::map, std::shared_ptr> std::map, sptr, std::owner_less<>> g_abilityRecord; std::mutex g_mutexAbilityRecord; std::mutex g_mtxStageMonitorRecord; +std::map, std::shared_ptr> g_interopMonitorRecord; enum ERROR_CODE { INCORRECT_PARAMETERS = 401, @@ -262,6 +263,16 @@ napi_value JSAbilityDelegator::SetMockList(napi_env env, napi_callback_info info GET_NAPI_INFO_AND_CALL(env, info, JSAbilityDelegator, OnSetMockList); } +napi_value JSAbilityDelegator::AddInteropAbilityMonitorSync(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JSAbilityDelegator, OnAddInteropAbilityMonitorSync); +} + +napi_value JSAbilityDelegator::RemoveInteropAbilityMonitorSync(napi_env env, napi_callback_info info) +{ + GET_NAPI_INFO_AND_CALL(env, info, JSAbilityDelegator, OnRemoveInteropAbilityMonitorSync); +} + napi_value JSAbilityDelegator::OnAddAbilityMonitor(napi_env env, NapiCallbackInfo& info) { TAG_LOGI(AAFwkTag::DELEGATOR, "argc: %{public}d", static_cast(info.argc)); @@ -1558,5 +1569,111 @@ void JSAbilityDelegator::RemoveStageMonitorRecord(napi_env env, napi_value value } } } + +napi_value JSAbilityDelegator::OnAddInteropAbilityMonitorSync(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "argc: %{public}d", static_cast(info.argc)); + HandleScope handleScope(env); + if (info.argc < ARGC_ONE) { + TAG_LOGE(AAFwkTag::DELEGATOR, "invalid argc"); + return ThrowJsError(env, INCORRECT_PARAMETERS, + "Parse param monitor failed, monitor must be InteropAbilityMonitor."); + } + std::shared_ptr monitor = nullptr; + if (!ParseInteropMonitorPara(env, info.argv[INDEX_ZERO], monitor)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "invalid params"); + return ThrowJsError(env, INCORRECT_PARAMETERS, + "Parse param monitor failed, monitor must be InteropAbilityMonitor."); + } + auto delegator = AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::JS); + if (delegator) { + monitor->SetLanguage(AbilityRuntime::Runtime::Language::JS); + delegator->AddInteropAbilityMonitor(monitor); + } else { + ThrowError(env, COMMON_FAILED, "Calling AddInteropAbilityMonitorSync failed."); + } + return CreateJsUndefined(env); +} + +napi_value JSAbilityDelegator::OnRemoveInteropAbilityMonitorSync(napi_env env, NapiCallbackInfo& info) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "argc: %{public}d", static_cast(info.argc)); + HandleScope handleScope(env); + if (info.argc < ARGC_ONE) { + TAG_LOGE(AAFwkTag::DELEGATOR, "invalid argc"); + return ThrowJsError(env, INCORRECT_PARAMETERS, + "Parse monitor failed, removeInteropAbilityMonitorSync must be InteropAbilityMonitor."); + } + auto delegator = AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::JS); + if (!delegator) { + ThrowError(env, COMMON_FAILED, "Calling RemoveInteropAbilityMonitorSync failed."); + return CreateJsUndefined(env); + } + for (auto iter = g_interopMonitorRecord.begin(); iter != g_interopMonitorRecord.end(); ++iter) { + std::shared_ptr jsMonitor = iter->first; + bool isEquals = false; + napi_strict_equals(env, info.argv[INDEX_ZERO], jsMonitor->GetNapiValue(), &isEquals); + if (isEquals) { + delegator->RemoveInteropAbilityMonitor(iter->second); + g_interopMonitorRecord.erase(iter); + break; + } + } + return CreateJsUndefined(env); +} + +napi_value JSAbilityDelegator::ParseInteropMonitorPara(napi_env env, napi_value value, + std::shared_ptr &monitor) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "interopMonitorRecord size: %{public}zu", g_interopMonitorRecord.size()); + + HandleScope handleScope(env); + for (auto iter = g_interopMonitorRecord.begin(); iter != g_interopMonitorRecord.end(); ++iter) { + std::shared_ptr jsMonitor = iter->first; + bool isEquals = false; + napi_strict_equals(env, value, jsMonitor->GetNapiValue(), &isEquals); + if (isEquals) { + TAG_LOGW(AAFwkTag::DELEGATOR, "interop monitor exist"); + monitor = iter->second; + return monitor ? CreateJsNull(env) : nullptr; + } + } + + napi_value abilityNameValue = nullptr; + napi_get_named_property(env, value, "abilityName", &abilityNameValue); + if (abilityNameValue == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null abilityNameValue"); + return nullptr; + } + + std::string abilityName; + if (!ConvertFromJsValue(env, abilityNameValue, abilityName)) { + return nullptr; + } + + std::string moduleName = ""; + napi_value moduleNameValue = nullptr; + napi_get_named_property(env, value, "moduleName", &moduleNameValue); + if (moduleNameValue != nullptr && !ConvertFromJsValue(env, moduleNameValue, moduleName)) { + TAG_LOGW(AAFwkTag::DELEGATOR, "get property moduleName failed"); + moduleName = ""; + } + + auto jsInteropMonitor = std::make_shared(abilityName, moduleName); + jsInteropMonitor->SetJsInteropAbilityMonitor(env, value); + auto *aniEnvVoid = AppExecFwk::AbilityDelegatorRegistry::GetAniEnv(); + if (aniEnvVoid != nullptr) { + jsInteropMonitor->SetAniEnv(aniEnvVoid); + } + monitor = std::make_shared(abilityName, moduleName, jsInteropMonitor); + + std::shared_ptr reference = nullptr; + napi_ref ref = nullptr; + napi_create_reference(env, value, 1, &ref); + reference.reset(reinterpret_cast(ref)); + g_interopMonitorRecord.emplace(reference, monitor); + + return CreateJsNull(env); +} } // namespace AbilityDelegatorJs } // namespace OHOS diff --git a/frameworks/js/napi/app/ability_delegator/js_ability_delegator.h b/frameworks/js/napi/app/ability_delegator/js_ability_delegator.h index 25cfebadce..2530bdd33f 100644 --- a/frameworks/js/napi/app/ability_delegator/js_ability_delegator.h +++ b/frameworks/js/napi/app/ability_delegator/js_ability_delegator.h @@ -22,6 +22,8 @@ #include "ability_stage_monitor.h" #include "js_ability_delegator_registry.h" #include "js_ability_monitor.h" +#include "interop_ability_monitor.h" +#include "js_interop_ability_monitor.h" #include "js_runtime_utils.h" #include "want.h" @@ -243,6 +245,24 @@ public: */ static napi_value SetMockList(napi_env env, napi_callback_info info); + /** + * Sync adds interop ability monitor. + * + * @param env Indicates the native engine. + * @param info Indicates the parameters from js. + * @return exec result. + */ + static napi_value AddInteropAbilityMonitorSync(napi_env env, napi_callback_info info); + + /** + * Sync removes interop ability monitor. + * + * @param env Indicates the native engine. + * @param info Indicates the parameters from js. + * @return exec result. + */ + static napi_value RemoveInteropAbilityMonitorSync(napi_env env, napi_callback_info info); + private: napi_value OnAddAbilityMonitor(napi_env env, NapiCallbackInfo& info); napi_value OnAddAbilityMonitorSync(napi_env env, NapiCallbackInfo& info); @@ -265,6 +285,8 @@ private: napi_value OnDoAbilityBackground(napi_env env, NapiCallbackInfo& info); napi_value OnFinishTest(napi_env env, NapiCallbackInfo& info); napi_value OnSetMockList(napi_env env, NapiCallbackInfo& info); + napi_value OnAddInteropAbilityMonitorSync(napi_env env, NapiCallbackInfo& info); + napi_value OnRemoveInteropAbilityMonitorSync(napi_env env, NapiCallbackInfo& info); private: napi_value CreateAbilityObject(napi_env env, const sptr &remoteObject); @@ -298,6 +320,8 @@ private: void AddStageMonitorRecord( napi_env env, napi_value value, const std::shared_ptr &monitor); void RemoveStageMonitorRecord(napi_env env, napi_value value); + napi_value ParseInteropMonitorPara(napi_env env, napi_value value, + std::shared_ptr &monitor); }; } // namespace AbilityDelegatorJs } // namespace OHOS diff --git a/frameworks/js/napi/app/ability_delegator/js_ability_delegator_utils.cpp b/frameworks/js/napi/app/ability_delegator/js_ability_delegator_utils.cpp index 46a03f3d6a..9194c2cbed 100644 --- a/frameworks/js/napi/app/ability_delegator/js_ability_delegator_utils.cpp +++ b/frameworks/js/napi/app/ability_delegator/js_ability_delegator_utils.cpp @@ -66,6 +66,10 @@ napi_value CreateJsAbilityDelegator(napi_env env) BindNativeFunction(env, objValue, "removeAbilityStageMonitorSync", moduleName, JSAbilityDelegator::RemoveAbilityStageMonitorSync); BindNativeFunction(env, objValue, "setMockList", moduleName, JSAbilityDelegator::SetMockList); + BindNativeFunction(env, objValue, "addInteropAbilityMonitorSync", moduleName, + JSAbilityDelegator::AddInteropAbilityMonitorSync); + BindNativeFunction(env, objValue, "removeInteropAbilityMonitorSync", moduleName, + JSAbilityDelegator::RemoveInteropAbilityMonitorSync); return handleEscape.Escape(objValue); } diff --git a/frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.cpp b/frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.cpp new file mode 100644 index 0000000000..d3ce6afb1c --- /dev/null +++ b/frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.cpp @@ -0,0 +1,174 @@ +/* + * 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 "js_interop_ability_monitor.h" + +#include "ability_delegator_infos.h" +#include "hilog_tag_wrapper.h" +#include "js_ability_delegator_utils.h" +#include "js_interop_object.h" +#include "napi/native_common.h" + +namespace OHOS { +namespace AbilityDelegatorJs { +using namespace OHOS::AbilityRuntime; + +JsInteropAbilityMonitor::JsInteropAbilityMonitor(const std::string &abilityName) : abilityName_(abilityName) +{} + +JsInteropAbilityMonitor::JsInteropAbilityMonitor(const std::string &abilityName, const std::string &moduleName) + : abilityName_(abilityName), moduleName_(moduleName) +{} + +void JsInteropAbilityMonitor::OnAbilityCreate( + const std::weak_ptr &abilityObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + CallLifecycleCBFunction("onAbilityCreate", abilityObj); +} + +void JsInteropAbilityMonitor::OnAbilityForeground( + const std::weak_ptr &abilityObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + CallLifecycleCBFunction("onAbilityForeground", abilityObj); +} + +void JsInteropAbilityMonitor::OnAbilityBackground( + const std::weak_ptr &abilityObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + CallLifecycleCBFunction("onAbilityBackground", abilityObj); +} + +void JsInteropAbilityMonitor::OnAbilityDestroy( + const std::weak_ptr &abilityObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + CallLifecycleCBFunction("onAbilityDestroy", abilityObj); +} + +void JsInteropAbilityMonitor::OnWindowStageCreate( + const std::weak_ptr &abilityObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + CallLifecycleCBFunction("onWindowStageCreate", abilityObj); +} + +void JsInteropAbilityMonitor::OnWindowStageRestore( + const std::weak_ptr &abilityObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + CallLifecycleCBFunction("onWindowStageRestore", abilityObj); +} + +void JsInteropAbilityMonitor::OnWindowStageDestroy( + const std::weak_ptr &abilityObj) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + CallLifecycleCBFunction("onWindowStageDestroy", abilityObj); +} + +void JsInteropAbilityMonitor::SetJsInteropAbilityMonitor(napi_env env, napi_value monitor) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + env_ = env; + napi_ref ref = nullptr; + napi_create_reference(env, monitor, 1, &ref); + jsInteropMonitor_ = std::unique_ptr(reinterpret_cast(ref)); +} + +void JsInteropAbilityMonitor::SetAniEnv(void *aniEnv) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + aniEnvVoid_ = aniEnv; +} + +napi_value JsInteropAbilityMonitor::ConvertAbilityToNapiValue( + const std::weak_ptr &abilityObj) +{ + if (aniEnvVoid_ == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null aniEnvVoid_, fallback to null"); + return CreateJsNull(env_); + } + + auto property = abilityObj.lock(); + if (property == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null property, fallback to null"); + return CreateJsNull(env_); + } + + auto etsProperty = std::static_pointer_cast(property); + if (etsProperty == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null etsProperty, fallback to null"); + return CreateJsNull(env_); + } + + auto etsRef = etsProperty->object_.lock(); + if (etsRef == nullptr || etsRef->aniRef == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "null etsRef, fallback to null"); + return CreateJsNull(env_); + } + + auto *aniEnv = reinterpret_cast(aniEnvVoid_); + auto interopObj = std::make_shared(aniEnv, etsRef); + if (interopObj == nullptr || !interopObj->IsFromAni()) { + TAG_LOGW(AAFwkTag::DELEGATOR, "create JsInteropObject failed, fallback to null"); + return CreateJsNull(env_); + } + + napi_value result = interopObj->GetNapiValue(env_); + if (result == nullptr) { + TAG_LOGW(AAFwkTag::DELEGATOR, "GetNapiValue failed, fallback to null"); + return CreateJsNull(env_); + } + + return result; +} + +napi_value JsInteropAbilityMonitor::CallLifecycleCBFunction(const std::string &functionName, + const std::weak_ptr &abilityObj) +{ + if (functionName.empty()) { + TAG_LOGE(AAFwkTag::DELEGATOR, "empty funcName"); + return nullptr; + } + + if (!jsInteropMonitor_) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null jsInteropMonitor"); + return nullptr; + } + + napi_value obj = jsInteropMonitor_->GetNapiValue(); + if (obj == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null obj"); + return nullptr; + } + + napi_value method = nullptr; + napi_get_named_property(env_, obj, functionName.data(), &method); + if (method == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null method: %{public}s", functionName.data()); + return nullptr; + } + + napi_value abilityValue = ConvertAbilityToNapiValue(abilityObj); + napi_value argv[] = { abilityValue }; + napi_value callResult = nullptr; + napi_call_function(env_, obj, method, ArraySize(argv), argv, &callResult); + return callResult; +} +} // namespace AbilityDelegatorJs +} // namespace OHOS diff --git a/frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.h b/frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.h new file mode 100644 index 0000000000..2266f1d325 --- /dev/null +++ b/frameworks/js/napi/app/ability_delegator/js_interop_ability_monitor.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_ABILITY_RUNTIME_JS_INTEROP_ABILITY_MONITOR_H +#define OHOS_ABILITY_RUNTIME_JS_INTEROP_ABILITY_MONITOR_H + +#include +#include +#include "ability_delegator_infos.h" +#include "js_interop_object.h" +#include "native_engine/native_reference.h" + +namespace OHOS { +namespace AbilityDelegatorJs { +class JsInteropAbilityMonitor { +public: + explicit JsInteropAbilityMonitor(const std::string &abilityName); + explicit JsInteropAbilityMonitor(const std::string &abilityName, const std::string &moduleName); + ~JsInteropAbilityMonitor() = default; + + void OnAbilityCreate(const std::weak_ptr &abilityObj); + void OnAbilityForeground(const std::weak_ptr &abilityObj); + void OnAbilityBackground(const std::weak_ptr &abilityObj); + void OnAbilityDestroy(const std::weak_ptr &abilityObj); + void OnWindowStageCreate(const std::weak_ptr &abilityObj); + void OnWindowStageRestore(const std::weak_ptr &abilityObj); + void OnWindowStageDestroy(const std::weak_ptr &abilityObj); + + void SetJsInteropAbilityMonitor(napi_env env, napi_value monitor); + void SetAniEnv(void *aniEnv); + + std::unique_ptr &GetJsInteropAbilityMonitor() + { + return jsInteropMonitor_; + } + +private: + napi_value CallLifecycleCBFunction(const std::string &functionName, + const std::weak_ptr &abilityObj); + napi_value ConvertAbilityToNapiValue(const std::weak_ptr &abilityObj); + +private: + std::string abilityName_ = ""; + std::string moduleName_ = ""; + napi_env env_ = nullptr; + void *aniEnvVoid_ = nullptr; + std::unique_ptr jsInteropMonitor_ = nullptr; +}; +} // namespace AbilityDelegatorJs +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_JS_INTEROP_ABILITY_MONITOR_H diff --git a/frameworks/native/ability/native/ability_runtime/js_ui_ability.cpp b/frameworks/native/ability/native/ability_runtime/js_ui_ability.cpp index 72c349c2d7..9a55133836 100644 --- a/frameworks/native/ability/native/ability_runtime/js_ui_ability.cpp +++ b/frameworks/native/ability/native/ability_runtime/js_ui_ability.cpp @@ -554,13 +554,21 @@ void JsUIAbility::OnStart(const Want &want, sptr sessionInfo void JsUIAbility::HandleAbilityDelegatorStart() { - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { + if (!CreateProperty(abilityContext_, property)) { + return; + } + property->object_ = jsAbilityObj_; + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); + if (delegator) { TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformStart"); - property->object_ = jsAbilityObj_; delegator->PostPerformStart(property); } + auto etsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (etsDelegator && etsDelegator != delegator) { + etsDelegator->PostPerformStart(property); + } } void JsUIAbility::WriteLifecycleSwitchLog(const std::string lifecycleName) @@ -684,12 +692,19 @@ void JsUIAbility::OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> *callbackI void JsUIAbility::OnStopCallback() { - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformStop"); + if (CreateProperty(abilityContext_, property)) { property->object_ = jsAbilityObj_; - delegator->PostPerformStop(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformStop"); + delegator->PostPerformStop(property); + } + auto etsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (etsDelegator && etsDelegator != delegator) { + etsDelegator->PostPerformStop(property); + } } bool ret = ConnectionManager::GetInstance().DisconnectCaller(AbilityContext::token_); @@ -737,12 +752,19 @@ void JsUIAbility::OnSceneCreated() AddLifecycleEventAfterJSCall(FreezeUtil::TimeoutState::FOREGROUND, methodName); } - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformSceneCreated"); + if (CreateProperty(abilityContext_, property)) { property->object_ = jsAbilityObj_; - delegator->PostPerformScenceCreated(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformSceneCreated"); + delegator->PostPerformScenceCreated(property); + } + auto etsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (etsDelegator && etsDelegator != delegator) { + etsDelegator->PostPerformScenceCreated(property); + } } applicationContext = AbilityRuntime::Context::GetApplicationContext(); @@ -781,12 +803,19 @@ void JsUIAbility::OnSceneRestored() applicationContext->DispatchOnWindowStageRestore(ability, stage); } - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformScenceRestored"); + if (CreateProperty(abilityContext_, property)) { property->object_ = jsAbilityObj_; - delegator->PostPerformScenceRestored(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformScenceRestored"); + delegator->PostPerformScenceRestored(property); + } + auto etsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (etsDelegator && etsDelegator != delegator) { + etsDelegator->PostPerformScenceRestored(property); + } } } @@ -830,12 +859,19 @@ void JsUIAbility::onSceneDestroyed() } } - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformScenceDestroyed"); + if (CreateProperty(abilityContext_, property)) { property->object_ = jsAbilityObj_; - delegator->PostPerformScenceDestroyed(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformScenceDestroyed"); + delegator->PostPerformScenceDestroyed(property); + } + auto etsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (etsDelegator && etsDelegator != delegator) { + etsDelegator->PostPerformScenceDestroyed(property); + } } applicationContext = AbilityRuntime::Context::GetApplicationContext(); @@ -899,12 +935,19 @@ void JsUIAbility::CallOnForegroundFunc(const Want &want) CallObjectMethod("onForeground", &jsWant, 1); AddLifecycleEventAfterJSCall(FreezeUtil::TimeoutState::FOREGROUND, methodName); - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformForeground"); + if (CreateProperty(abilityContext_, property)) { property->object_ = jsAbilityObj_; - delegator->PostPerformForeground(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformForeground"); + delegator->PostPerformForeground(property); + } + auto etsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (etsDelegator && etsDelegator != delegator) { + etsDelegator->PostPerformForeground(property); + } } applicationContext = AbilityRuntime::Context::GetApplicationContext(); @@ -934,12 +977,19 @@ void JsUIAbility::OnBackground() UIAbility::OnBackground(); - auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); auto property = std::make_shared(); - if (delegator && CreateProperty(abilityContext_, property)) { - TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformBackground"); + if (CreateProperty(abilityContext_, property)) { property->object_ = jsAbilityObj_; - delegator->PostPerformBackground(property); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(); + if (delegator) { + TAG_LOGD(AAFwkTag::UIABILITY, "call PostPerformBackground"); + delegator->PostPerformBackground(property); + } + auto etsDelegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator( + AbilityRuntime::Runtime::Language::ETS); + if (etsDelegator && etsDelegator != delegator) { + etsDelegator->PostPerformBackground(property); + } } applicationContext = AbilityRuntime::Context::GetApplicationContext(); diff --git a/frameworks/native/appkit/BUILD.gn b/frameworks/native/appkit/BUILD.gn index 55470d28ba..f850043604 100644 --- a/frameworks/native/appkit/BUILD.gn +++ b/frameworks/native/appkit/BUILD.gn @@ -627,6 +627,7 @@ ohos_shared_library("appkit_delegator") { "${ability_runtime_native_path}/appkit/ability_delegator/delegator_thread.cpp", "${ability_runtime_native_path}/appkit/ability_delegator/iability_delegator.cpp", "${ability_runtime_native_path}/appkit/ability_delegator/iability_monitor.cpp", + "${ability_runtime_native_path}/appkit/ability_delegator/iinterop_ability_monitor.cpp", "${ability_runtime_native_path}/appkit/ability_delegator/iability_stage_monitor.cpp", "${ability_runtime_native_path}/appkit/ability_delegator/runner_runtime/ets_test_runner_instance.cpp", "${ability_runtime_native_path}/appkit/ability_delegator/runner_runtime/js_test_runner.cpp", diff --git a/frameworks/native/appkit/ability_delegator/ability_delegator.cpp b/frameworks/native/appkit/ability_delegator/ability_delegator.cpp index 860ffd3170..9c41b9e9eb 100644 --- a/frameworks/native/appkit/ability_delegator/ability_delegator.cpp +++ b/frameworks/native/appkit/ability_delegator/ability_delegator.cpp @@ -54,6 +54,23 @@ void AbilityDelegator::AddAbilityMonitor(const std::shared_ptr abilityMonitors_.emplace_back(monitor); } +void AbilityDelegator::AddInteropAbilityMonitor(const std::shared_ptr &monitor) +{ + if (!monitor) { + TAG_LOGW(AAFwkTag::DELEGATOR, "invalid params"); + return; + } + + std::unique_lock lck(mutexMonitor_); + auto pos = std::find(interopAbilityMonitors_.begin(), interopAbilityMonitors_.end(), monitor); + if (pos != interopAbilityMonitors_.end()) { + TAG_LOGW(AAFwkTag::DELEGATOR, "interop monitor added"); + return; + } + + interopAbilityMonitors_.emplace_back(monitor); +} + void AbilityDelegator::AddAbilityStageMonitor(const std::shared_ptr &monitor) { if (!monitor) { @@ -83,6 +100,20 @@ void AbilityDelegator::RemoveAbilityMonitor(const std::shared_ptr &monitor) +{ + if (!monitor) { + TAG_LOGW(AAFwkTag::DELEGATOR, "invalid params"); + return; + } + + std::unique_lock lck(mutexMonitor_); + auto pos = std::find(interopAbilityMonitors_.begin(), interopAbilityMonitors_.end(), monitor); + if (pos != interopAbilityMonitors_.end()) { + interopAbilityMonitors_.erase(pos); + } +} + void AbilityDelegator::RemoveAbilityStageMonitor(const std::shared_ptr &monitor) { if (!monitor) { @@ -100,6 +131,7 @@ void AbilityDelegator::ClearAllMonitors() { std::unique_lock lck(mutexMonitor_); abilityMonitors_.clear(); + interopAbilityMonitors_.clear(); } size_t AbilityDelegator::GetMonitorsNum() @@ -379,11 +411,6 @@ void AbilityDelegator::PostPerformStart(const std::shared_ptr lck(mutexMonitor_); - if (abilityMonitors_.empty()) { - TAG_LOGW(AAFwkTag::DELEGATOR, "empty abilityMonitors"); - return; - } - for (auto &monitor : abilityMonitors_) { if (!monitor) { continue; @@ -392,6 +419,15 @@ void AbilityDelegator::PostPerformStart(const std::shared_ptrOnAbilityStart(ability); } } + + for (auto &monitor : interopAbilityMonitors_) { + if (!monitor) { + continue; + } + if (IsFromOtherRuntime(monitor, ability) && monitor->Match(ability, true)) { + monitor->OnAbilityStart(ability); + } + } } void AbilityDelegator::PostPerformStageStart(const std::shared_ptr &abilityStage) @@ -428,11 +464,6 @@ void AbilityDelegator::PostPerformScenceCreated(const std::shared_ptr lck(mutexMonitor_); - if (abilityMonitors_.empty()) { - TAG_LOGW(AAFwkTag::DELEGATOR, "invalid abilityMonitors"); - return; - } - for (auto &monitor : abilityMonitors_) { if (!monitor) { continue; @@ -441,6 +472,15 @@ void AbilityDelegator::PostPerformScenceCreated(const std::shared_ptrOnWindowStageCreate(ability); } } + + for (auto &monitor : interopAbilityMonitors_) { + if (!monitor) { + continue; + } + if (IsFromOtherRuntime(monitor, ability) && monitor->Match(ability, true)) { + monitor->OnWindowStageCreate(ability); + } + } } void AbilityDelegator::PostPerformScenceRestored(const std::shared_ptr &ability) @@ -455,11 +495,6 @@ void AbilityDelegator::PostPerformScenceRestored(const std::shared_ptr lck(mutexMonitor_); - if (abilityMonitors_.empty()) { - TAG_LOGW(AAFwkTag::DELEGATOR, "null abilityMonitors"); - return; - } - for (auto &monitor : abilityMonitors_) { if (!monitor) { continue; @@ -468,6 +503,15 @@ void AbilityDelegator::PostPerformScenceRestored(const std::shared_ptrOnWindowStageRestore(ability); } } + + for (auto &monitor : interopAbilityMonitors_) { + if (!monitor) { + continue; + } + if (IsFromOtherRuntime(monitor, ability) && monitor->Match(ability, true)) { + monitor->OnWindowStageRestore(ability); + } + } } void AbilityDelegator::PostPerformScenceDestroyed(const std::shared_ptr &ability) @@ -482,11 +526,6 @@ void AbilityDelegator::PostPerformScenceDestroyed(const std::shared_ptr lck(mutexMonitor_); - if (abilityMonitors_.empty()) { - TAG_LOGW(AAFwkTag::DELEGATOR, "null abilityMonitors"); - return; - } - for (auto &monitor : abilityMonitors_) { if (!monitor) { continue; @@ -495,6 +534,15 @@ void AbilityDelegator::PostPerformScenceDestroyed(const std::shared_ptrOnWindowStageDestroy(ability); } } + + for (auto &monitor : interopAbilityMonitors_) { + if (!monitor) { + continue; + } + if (IsFromOtherRuntime(monitor, ability) && monitor->Match(ability, true)) { + monitor->OnWindowStageDestroy(ability); + } + } } void AbilityDelegator::PostPerformForeground(const std::shared_ptr &ability) @@ -509,11 +557,6 @@ void AbilityDelegator::PostPerformForeground(const std::shared_ptr lck(mutexMonitor_); - if (abilityMonitors_.empty()) { - TAG_LOGW(AAFwkTag::DELEGATOR, "invalid abilityMonitors"); - return; - } - for (auto &monitor : abilityMonitors_) { if (!monitor) { continue; @@ -522,6 +565,15 @@ void AbilityDelegator::PostPerformForeground(const std::shared_ptrOnAbilityForeground(ability); } } + + for (auto &monitor : interopAbilityMonitors_) { + if (!monitor) { + continue; + } + if (IsFromOtherRuntime(monitor, ability) && monitor->Match(ability, true)) { + monitor->OnAbilityForeground(ability); + } + } } void AbilityDelegator::PostPerformBackground(const std::shared_ptr &ability) @@ -536,11 +588,6 @@ void AbilityDelegator::PostPerformBackground(const std::shared_ptr lck(mutexMonitor_); - if (abilityMonitors_.empty()) { - TAG_LOGW(AAFwkTag::DELEGATOR, "invalid abilityMonitors"); - return; - } - for (auto &monitor : abilityMonitors_) { if (!monitor) { continue; @@ -549,6 +596,15 @@ void AbilityDelegator::PostPerformBackground(const std::shared_ptrOnAbilityBackground(ability); } } + + for (auto &monitor : interopAbilityMonitors_) { + if (!monitor) { + continue; + } + if (IsFromOtherRuntime(monitor, ability) && monitor->Match(ability, true)) { + monitor->OnAbilityBackground(ability); + } + } } void AbilityDelegator::PostPerformStop(const std::shared_ptr &ability) @@ -563,11 +619,6 @@ void AbilityDelegator::PostPerformStop(const std::shared_ptr lck(mutexMonitor_); - if (abilityMonitors_.empty()) { - TAG_LOGW(AAFwkTag::DELEGATOR, "invalid abilityMonitors"); - return; - } - for (auto &monitor : abilityMonitors_) { if (!monitor) { continue; @@ -577,6 +628,15 @@ void AbilityDelegator::PostPerformStop(const std::shared_ptrMatch(ability, true)) { + monitor->OnAbilityStop(ability); + } + } + RemoveAbilityProperty(ability); CallClearFunc(ability); } @@ -760,5 +820,14 @@ inline void AbilityDelegator::CallClearFunc(const std::shared_ptr &monitor, + const std::shared_ptr &ability) +{ + if (!monitor || !ability) { + return false; + } + return monitor->GetLanguage() != ability->language_; +} } // namespace AppExecFwk } // namespace OHOS diff --git a/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp b/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp index bfdc3298b9..9672858540 100644 --- a/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp +++ b/frameworks/native/appkit/ability_delegator/ability_delegator_registry.cpp @@ -20,6 +20,8 @@ namespace AppExecFwk { std::map> AbilityDelegatorRegistry::abilityDelegator_ {}; std::shared_ptr AbilityDelegatorRegistry::abilityDelegatorArgs_ {}; +void *AbilityDelegatorRegistry::napiEnv_ = nullptr; +void *AbilityDelegatorRegistry::aniEnv_ = nullptr; std::shared_ptr AbilityDelegatorRegistry::GetAbilityDelegator( const AbilityRuntime::Runtime::Language &language) @@ -55,5 +57,21 @@ void AbilityDelegatorRegistry::RegisterInstance(const std::shared_ptr +#include "hilog_tag_wrapper.h" +#include "iinterop_ability_monitor.h" + +using namespace std::chrono_literals; + +namespace OHOS { +namespace AppExecFwk { +IInteropAbilityMonitor::IInteropAbilityMonitor(const std::string &abilityName) : abilityName_(abilityName) +{} + +IInteropAbilityMonitor::IInteropAbilityMonitor(const std::string &abilityName, + const std::string &moduleName) : abilityName_(abilityName), moduleName_(moduleName) +{} + +bool IInteropAbilityMonitor::Match(const std::shared_ptr &ability, bool isNotify) +{ + if (!ability) { + TAG_LOGW(AAFwkTag::DELEGATOR, "invalid ability property"); + return false; + } + + const auto &aName = ability->name_; + + if (abilityName_.empty() || aName.empty()) { + TAG_LOGW(AAFwkTag::DELEGATOR, "invalid name"); + return false; + } + + if (abilityName_.compare(aName)) { + TAG_LOGW(AAFwkTag::DELEGATOR, "different name"); + return false; + } + + const auto &aModuleName = ability->moduleName_; + + if (!moduleName_.empty() && moduleName_.compare(aModuleName) != 0) { + TAG_LOGE(AAFwkTag::DELEGATOR, "different moduleName, %{public}s and %{public}s", + moduleName_.c_str(), aModuleName.c_str()); + return false; + } + + TAG_LOGI(AAFwkTag::DELEGATOR, "ability name : %{public}s, isNotify : %{public}s", + abilityName_.data(), (isNotify ? "true" : "false")); + + if (isNotify) { + TAG_LOGI(AAFwkTag::DELEGATOR, "notify ability matched"); + { + std::lock_guard matchLock(mMatch_); + matchedAbility_ = ability; + } + cvMatch_.notify_one(); + } + + return true; +} + +std::shared_ptr IInteropAbilityMonitor::WaitForAbility() +{ + return WaitForAbility(MAX_TIME_OUT); +} + +std::shared_ptr IInteropAbilityMonitor::WaitForAbility(const int64_t timeoutMs) +{ + auto realTime = timeoutMs; + if (timeoutMs <= 0) { + TAG_LOGW(AAFwkTag::DELEGATOR, "timeout should not number"); + realTime = MAX_TIME_OUT; + } + + std::unique_lock matchLock(mMatch_); + + auto condition = [this] { return this->matchedAbility_ != nullptr; }; + if (!cvMatch_.wait_for(matchLock, realTime * 1ms, condition)) { + TAG_LOGW(AAFwkTag::DELEGATOR, "wait ability timeout"); + } + + return matchedAbility_; +} + +void IInteropAbilityMonitor::OnAbilityStart(const std::weak_ptr &abilityObj) +{} + +void IInteropAbilityMonitor::OnAbilityForeground(const std::weak_ptr &abilityObj) +{} + +void IInteropAbilityMonitor::OnAbilityBackground(const std::weak_ptr &abilityObj) +{} + +void IInteropAbilityMonitor::OnAbilityStop(const std::weak_ptr &abilityObj) +{} + +void IInteropAbilityMonitor::OnWindowStageCreate(const std::weak_ptr &abilityObj) +{} + +void IInteropAbilityMonitor::OnWindowStageRestore(const std::weak_ptr &abilityObj) +{} + +void IInteropAbilityMonitor::OnWindowStageDestroy(const std::weak_ptr &abilityObj) +{} + +void IInteropAbilityMonitor::SetLanguage(const AbilityRuntime::Runtime::Language &language) +{ + language_ = language; +} + +AbilityRuntime::Runtime::Language IInteropAbilityMonitor::GetLanguage() const +{ + return language_; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/frameworks/native/appkit/app/main_thread.cpp b/frameworks/native/appkit/app/main_thread.cpp index db5924fbbc..677ef6ec13 100644 --- a/frameworks/native/appkit/app/main_thread.cpp +++ b/frameworks/native/appkit/app/main_thread.cpp @@ -2650,8 +2650,44 @@ bool MainThread::PrepareAbilityDelegator(const std::shared_ptr & auto delegator = IAbilityDelegator::Create(application_->GetRuntime(), application_->GetAppContext(), std::move(testRunner), record->observer); AbilityDelegatorRegistry::RegisterInstance(delegator, args, application_->GetRuntime()->GetLanguage()); + { + void *napiEnvVoid = nullptr; + void *aniVmVoid = nullptr; + auto &curRuntime = application_->GetRuntime(); + bool isHybrid = applicationInfo_ && + applicationInfo_->arkTSMode == AbilityRuntime::CODE_LANGUAGE_ARKTS_HYBRID; + if (isHybrid && curRuntime->GetLanguage() == AbilityRuntime::Runtime::Language::ETS) { + auto &etsRuntime = static_cast(*curRuntime); + auto aniEnv = etsRuntime.GetAniEnv(); + if (aniEnv != nullptr) { + aniVmVoid = reinterpret_cast(aniEnv); + } + const auto &jsRuntime = etsRuntime.GetJsRuntime(); + if (jsRuntime) { + napiEnvVoid = reinterpret_cast( + static_cast(*jsRuntime).GetNapiEnv()); + } + } else if (isHybrid && curRuntime->GetLanguage() == AbilityRuntime::Runtime::Language::JS) { + napiEnvVoid = reinterpret_cast( + static_cast(*curRuntime).GetNapiEnv()); + } + AbilityDelegatorRegistry::SetRuntimeEnvs(napiEnvVoid, aniVmVoid); + } delegator->SetApiTargetVersion(targetVersion); delegator->Prepare(); + if (applicationInfo_ && applicationInfo_->arkTSMode == AbilityRuntime::CODE_LANGUAGE_ARKTS_HYBRID) { + auto currentLanguage = application_->GetRuntime()->GetLanguage(); + auto targetLanguage = AbilityRuntime::Runtime::Language::JS; + if (currentLanguage == AbilityRuntime::Runtime::Language::JS) { + targetLanguage = AbilityRuntime::Runtime::Language::ETS; + } + auto interopTestRunner = TestRunner::Create(application_->GetRuntime(), args, false); + auto interopDelegator = IAbilityDelegator::Create(application_->GetRuntime(), + application_->GetAppContext(), std::move(interopTestRunner), record->observer); + AbilityDelegatorRegistry::RegisterInstance(interopDelegator, args, targetLanguage); + interopDelegator->SetApiTargetVersion(targetVersion); + interopDelegator->Prepare(); + } } else { // FA model TAG_LOGD(AAFwkTag::APPKIT, "FA model"); AbilityRuntime::Runtime::Options options; diff --git a/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h b/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h index c2d91630e5..dbb619b2e9 100644 --- a/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h +++ b/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h @@ -33,6 +33,7 @@ #include "context.h" #include "delegator_thread.h" #include "iability_monitor.h" +#include "iinterop_ability_monitor.h" #include "iability_stage_monitor.h" #include "shell_cmd_result.h" #include "test_runner.h" @@ -97,6 +98,13 @@ public: */ void AddAbilityMonitor(const std::shared_ptr &monitor); + /** + * Adds interop monitor for monitoring the lifecycle state changes of the ability. + * + * @param monitor, Indicates the interop monitor object. + */ + void AddInteropAbilityMonitor(const std::shared_ptr &monitor); + /** * Adds monitor for monitoring the lifecycle state changes of the abilityStage. * @@ -111,6 +119,13 @@ public: */ void RemoveAbilityMonitor(const std::shared_ptr &monitor); + /** + * Removes interop ability monitor. + * + * @param monitor, Indicates the specified interop monitor object. + */ + void RemoveInteropAbilityMonitor(const std::shared_ptr &monitor); + /** * Removes abilityStage monitor. * @@ -333,6 +348,8 @@ private: std::shared_ptr FindPropertyByToken(const sptr &token); std::shared_ptr FindPropertyByName(const std::string &name); inline void CallClearFunc(const std::shared_ptr &ability); + bool IsFromOtherRuntime(const std::shared_ptr &monitor, + const std::shared_ptr &ability); private: static constexpr size_t INFORMATION_MAX_LENGTH {1000}; @@ -347,6 +364,7 @@ private: std::unique_ptr delegatorThread_; std::list> abilityProperties_; std::vector> abilityMonitors_; + std::vector> interopAbilityMonitors_; std::vector> abilityStageMonitors_; ClearFunc clearFunc_; diff --git a/interfaces/kits/native/appkit/ability_delegator/ability_delegator_infos.h b/interfaces/kits/native/appkit/ability_delegator/ability_delegator_infos.h index 8d123da831..35dfd08b6b 100644 --- a/interfaces/kits/native/appkit/ability_delegator/ability_delegator_infos.h +++ b/interfaces/kits/native/appkit/ability_delegator/ability_delegator_infos.h @@ -19,6 +19,7 @@ #include #include "ability_lifecycle_executor.h" #include "iremote_object.h" +#include "runtime.h" class NativeReference; @@ -36,6 +37,8 @@ struct BaseDelegatorAbilityProperty { std::string fullName_; // lifecycle state of ability AbilityLifecycleExecutor::LifecycleState lifecycleState_ {AbilityLifecycleExecutor::LifecycleState::UNINITIALIZED}; + // runtime language source of ability + AbilityRuntime::Runtime::Language language_ {AbilityRuntime::Runtime::Language::JS}; }; struct ADelegatorAbilityProperty : public BaseDelegatorAbilityProperty { std::weak_ptr object_; diff --git a/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h b/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h index 57f9c383be..b69c2d8f98 100644 --- a/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h +++ b/interfaces/kits/native/appkit/ability_delegator/ability_delegator_registry.h @@ -65,9 +65,15 @@ public: const std::shared_ptr &delegator, const std::shared_ptr &args, const AbilityRuntime::Runtime::Language &language); + static void SetRuntimeEnvs(void *napiEnv, void *aniEnv); + static void *GetNapiEnv(); + static void *GetAniEnv(); + private: static std::map> abilityDelegator_; static std::shared_ptr abilityDelegatorArgs_; + static void *napiEnv_; + static void *aniEnv_; }; } // namespace AppExecFwk } // namespace OHOS diff --git a/interfaces/kits/native/appkit/ability_delegator/iinterop_ability_monitor.h b/interfaces/kits/native/appkit/ability_delegator/iinterop_ability_monitor.h new file mode 100644 index 0000000000..daeb874ef6 --- /dev/null +++ b/interfaces/kits/native/appkit/ability_delegator/iinterop_ability_monitor.h @@ -0,0 +1,165 @@ +/* + * 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_IINTEROP_ABILITY_MONITOR_H +#define OHOS_ABILITY_RUNTIME_IINTEROP_ABILITY_MONITOR_H + +#include +#include +#include +#include + +#include "ability_delegator_infos.h" +#include "runtime.h" + +namespace OHOS { +namespace AppExecFwk { +class IInteropAbilityMonitor { +public: + /** + * Indicates that the default timeout is 5 seconds. + */ + static constexpr int64_t MAX_TIME_OUT {5000}; + +public: + /** + * A constructor used to create a IInteropAbilityMonitor instance with the input parameter passed. + * + * @param abilityName Indicates the specified ability name for monitoring the lifecycle state changes + * of the ability. + */ + explicit IInteropAbilityMonitor(const std::string &abilityName); + + /** + * A constructor used to create a IInteropAbilityMonitor instance with the input parameter passed. + * + * @param abilityName Indicates the specified ability name for monitoring the lifecycle state changes + * @param moduleName Indicates the specified ability moduleName for monitoring the lifecycle state changes + * of the ability. + */ + explicit IInteropAbilityMonitor(const std::string &abilityName, const std::string &moduleName); + + /** + * Sets the runtime language source of this interop monitor. + * + * @param language Indicates the runtime language. + */ + void SetLanguage(const AbilityRuntime::Runtime::Language &language); + + /** + * Gets the runtime language source of this interop monitor. + * + * @return the runtime language. + */ + AbilityRuntime::Runtime::Language GetLanguage() const; + + /** + * Default deconstructor used to deconstruct. + */ + virtual ~IInteropAbilityMonitor() = default; + + /** + * Match the monitored Ability objects when newAbility objects are started or + * the lifecycle states of monitored abilities have changed. + * + * @param ability Indicates the ability. + * @param isNotify Indicates whether to notify the matched ability to the object who waited. + * @return true if match is successful; returns false otherwise. + */ + virtual bool Match(const std::shared_ptr &ability, bool isNotify = false); + + /** + * Waits for and returns the started Ability object that matches the conditions specified in this monitor + * within 5 seconds. + * The current thread will be blocked until the 5-second default timer expires. + * + * @return the Ability object if any object has started is matched within 5 seconds; returns null otherwise. + */ + virtual std::shared_ptr WaitForAbility(); + + /** + * Waits for and returns the started Ability object that matches the conditions specified in this monitor + * within the specified time. + * The current thread will be blocked until the timer specified by timeoutMillisecond expires. + * + * @param timeoutMs Indicates the maximum amount of time to wait, in milliseconds. + * The value must be a positive integer. + * @return the Ability object if any object has started is matched within the specified time; + * returns null otherwise. + */ + virtual std::shared_ptr WaitForAbility(const int64_t timeoutMs); + + /** + * Called when ability is started. + * + * @param abilityObj Indicates the ability object. + */ + virtual void OnAbilityStart(const std::weak_ptr &abilityObj); + + /** + * Called when ability is in foreground. + * + * @param abilityObj Indicates the ability object. + */ + virtual void OnAbilityForeground(const std::weak_ptr &abilityObj); + + /** + * Called when ability is in background. + * + * @param abilityObj Indicates the ability object. + */ + virtual void OnAbilityBackground(const std::weak_ptr &abilityObj); + + /** + * Called when ability is stopped. + * + * @param abilityObj Indicates the ability object. + */ + virtual void OnAbilityStop(const std::weak_ptr &abilityObj); + + /** + * Called when window stage is created. + * + * @param abilityObj Indicates the ability object. + */ + virtual void OnWindowStageCreate(const std::weak_ptr &abilityObj); + + /** + * Called when window stage is restored. + * + * @param abilityObj Indicates the ability object. + */ + virtual void OnWindowStageRestore(const std::weak_ptr &abilityObj); + + /** + * Called when window stage is destroyed. + * + * @param abilityObj Indicates the ability object. + */ + virtual void OnWindowStageDestroy(const std::weak_ptr &abilityObj); + +private: + std::string abilityName_; + std::string moduleName_; + std::shared_ptr matchedAbility_; + AbilityRuntime::Runtime::Language language_ {AbilityRuntime::Runtime::Language::JS}; + + std::condition_variable cvMatch_; + std::mutex mMatch_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_IINTEROP_ABILITY_MONITOR_H