From f3e064b03f518977d009027f309e670ab97f4d96 Mon Sep 17 00:00:00 2001 From: wangzhen Date: Thu, 26 Jun 2025 14:44:42 +0800 Subject: [PATCH] Add caller/callee Signed-off-by: wangzhen Change-Id: Id03d633663771a29a026a32e68f14b3b17491473 --- .../ets/ets/@ohos.app.ability.UIAbility.ets | 14 + frameworks/ets/ets/BUILD.gn | 21 ++ frameworks/ets/ets/application/Callee.ets | 81 ++++++ frameworks/ets/ets/application/Caller.ets | 96 +++++++ .../ets/ets/application/UIAbilityContext.ets | 9 + frameworks/native/ability/native/BUILD.gn | 3 + .../ability_runtime/ets_ability_context.cpp | 93 +++++++ .../ability_runtime/ets_caller_complex.cpp | 246 ++++++++++++++++++ .../native/ability_runtime/ets_ui_ability.cpp | 28 ++ .../ability_runtime/js_ability_context.cpp | 2 +- .../ability/ability_runtime/caller_callback.h | 2 + .../ability_runtime/ets_ability_context.h | 1 + .../ability_runtime/ets_caller_complex.h | 32 +++ .../native/ability_runtime/ets_ui_ability.h | 2 + .../ability_runtime/js_caller_complex.h | 2 - 15 files changed, 629 insertions(+), 3 deletions(-) create mode 100644 frameworks/ets/ets/application/Callee.ets create mode 100644 frameworks/ets/ets/application/Caller.ets create mode 100644 frameworks/native/ability/native/ability_runtime/ets_caller_complex.cpp create mode 100644 interfaces/kits/native/ability/native/ability_runtime/ets_caller_complex.h diff --git a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets index 63fd48d05b8..252a8151144 100644 --- a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets +++ b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets @@ -17,10 +17,24 @@ import AbilityConstant from '@ohos.app.ability.AbilityConstant'; import UIAbilityContext from 'application.UIAbilityContext'; import Want from '@ohos.app.ability.Want'; import window from '@ohos.window'; +import rpc from '@ohos.rpc'; import { AbilityUtils } from './utils/AbilityUtils'; +import { CalleeImpl } from './application/Callee'; + +export type OnReleaseCallback = (msg: string) => void; +export type CalleeCallback = (indata: rpc.MessageSequence) => rpc.Parcelable; +export interface Caller { + call(method: string, data: rpc.Parcelable): Promise; + onRelease(callback: OnReleaseCallback): void; + release(): void; +} +export interface Callee { + on(method: string, callback: CalleeCallback): void; +} export default class UIAbility { private destroyCallbackPoint: long; + callee: Callee = new CalleeImpl() as Callee; private native nativeOnDestroyCallback(): void; diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index 799dbd505d4..41135e36189 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -454,6 +454,26 @@ ohos_prebuilt_etc("ability_runtime_ability_stage_context_abc_etc") { deps = [ ":ability_runtime_ability_stage_context_abc" ] } +generate_static_abc("ability_runtime_caller_callee_abc") { + base_url = "./" + files = [ + "./application/Callee.ets", + "./application/Caller.ets", + ] + + is_boot_abc = "True" + device_dst_file = + "/system/framework/ability_runtime_caller_callee_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_caller_callee_abc_etc") { + source = "$target_out_dir/ability_runtime_caller_callee_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_caller_callee_abc" ] +} + group("ets_packages") { deps = [ ":ability_delegator_abc_etc", @@ -470,6 +490,7 @@ group("ets_packages") { ":ability_runtime_ability_utils_abc_etc", ":ability_runtime_application_context_abc_etc", ":ability_runtime_base_context_abc_etc", + ":ability_runtime_caller_callee_abc_etc", ":ability_runtime_configuration_abc_etc", ":ability_runtime_configuration_constant_abc_etc", ":ability_runtime_context_abc_etc", diff --git a/frameworks/ets/ets/application/Callee.ets b/frameworks/ets/ets/application/Callee.ets new file mode 100644 index 00000000000..4196d418823 --- /dev/null +++ b/frameworks/ets/ets/application/Callee.ets @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; +import rpc from '@ohos.rpc'; +import { BusinessError } from '@ohos.base'; +import { Callee, CalleeCallback } from '@ohos.app.ability.UIAbility'; + +const domainID = 0x0000; +const TAG = 'UIAbility'; + +const ERROR_CODE_INVALID_PARAM = 401; +const ERROR_CODE_FUNC_REGISTERED = 16200004; +const ERROR_CODE_FUNC_NOT_EXIST = 16200005; +const ERROR_CODE_INNER_ERROR = 16000050; + +const ERROR_MSG_INVALID_PARAM = 'Invalid input parameter.'; +const ERROR_MSG_FUNC_REGISTERED = 'Method registered. The method has registered.'; +const ERROR_MSG_FUNC_NOT_EXIST = 'The method has not been registered.'; +const ERROR_MSG_INNER_ERROR = 'Inner Error.'; + +let errMap = new Map(); +errMap.set(ERROR_CODE_INVALID_PARAM, ERROR_MSG_INVALID_PARAM); +errMap.set(ERROR_CODE_FUNC_REGISTERED, ERROR_MSG_FUNC_REGISTERED); +errMap.set(ERROR_CODE_FUNC_NOT_EXIST, ERROR_MSG_FUNC_NOT_EXIST); +errMap.set(ERROR_CODE_INNER_ERROR, ERROR_MSG_INNER_ERROR); + +function buildError(code: number): BusinessError { + return new BusinessError(code, new Error(errMap.get(code) as string)); +} + +export class CalleeImpl extends rpc.RemoteObject implements Callee { + private callList = new Map(); + private startUpNewRule = false; + constructor() { + super('rpc.application.callee'); + hilog.info(domainID, TAG, 'Callee constructor is OK'); + } + + setNewRuleFlag(flag: boolean): void { + this.startUpNewRule = flag; + } + + onRemoteMessageRequest(code: number, data: rpc.MessageSequence, reply: rpc.MessageSequence, + option: rpc.MessageOption): Boolean|Promise { + hilog.info(domainID, TAG, 'Callee onRemoteMessageRequest code [' + code + ']'); + return true; + } + + on(method: string, callback: CalleeCallback): void { + if (this.callList.has(method)) { + hilog.info(domainID, TAG, 'Callee on error, [' + method + '] has registered'); + throw buildError(ERROR_CODE_FUNC_REGISTERED); + } + + this.callList.set(method, callback); + hilog.info(domainID, TAG, 'Callee on method [' + method + ']'); + } + + off(method: string): void { + if (!this.callList.has(method)) { + hilog.info(domainID, TAG, 'Callee off error, this.callList not found ' + method); + throw buildError(ERROR_CODE_FUNC_NOT_EXIST); + } + + this.callList.delete(method); + hilog.info(domainID, TAG, 'Callee off method [' + method + ']'); + } +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/Caller.ets b/frameworks/ets/ets/application/Caller.ets new file mode 100644 index 00000000000..00473f24570 --- /dev/null +++ b/frameworks/ets/ets/application/Caller.ets @@ -0,0 +1,96 @@ +/* + * 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 hilog from '@ohos.hilog'; +import rpc from '@ohos.rpc'; +import { BusinessError } from '@ohos.base'; +import { Caller, OnReleaseCallback, OnRemoteStateChangeCallback } from '@ohos.app.ability.UIAbility'; + +const domainID = 0x0000; +const TAG = 'UIAbility'; + +const ERROR_CODE_INVALID_PARAM = 401; +const ERROR_CODE_CALLER_RELEASED = 16200001; +const ERROR_CODE_CLAAEE_INVALID = 16200002; +const ERROR_CODE_INNER_ERROR = 16000050; + +const ERROR_MSG_INVALID_PARAM = 'Invalid input parameter.'; +const ERROR_MSG_CALLER_RELEASED = 'Caller released. The caller has been released.'; +const ERROR_MSG_CLAAEE_INVALID = 'The callee does not exist.'; +const ERROR_MSG_INNER_ERROR = 'Inner Error.'; + +let errMap = new Map(); +errMap.set(ERROR_CODE_INVALID_PARAM, ERROR_MSG_INVALID_PARAM); +errMap.set(ERROR_CODE_CALLER_RELEASED, ERROR_MSG_CALLER_RELEASED); +errMap.set(ERROR_CODE_CLAAEE_INVALID, ERROR_MSG_CLAAEE_INVALID); +errMap.set(ERROR_CODE_INNER_ERROR, ERROR_MSG_INNER_ERROR); + +function buildError(code: number): BusinessError { + return new BusinessError(code, new Error(errMap.get(code) as string)); +} + +export class ReleaseCallback { + private myFun_: OnReleaseCallback = (msg: string) => {} + constructor(myFun: OnReleaseCallback) { + this.myFun_ = myFun; + } + invoke(msg: string): void { + this.myFun_(msg); + } +} + +export class CallerImpl implements Caller { + nativeCaller: long; + private callee: rpc.IRemoteObject | null = null; + private releaseState = false; + + native nativeReleaseSync(): void; + native nativeOnReleaseSync(callback: ReleaseCallback): void; + native nativeOnRemoteStateChangeSync(callback: OnRemoteStateChangeCallback): void; + + constructor() { + hilog.info(domainID, TAG, 'Caller::constructor'); + } + + call(method: string, data: rpc.Parcelable): Promise { + return new Promise((resolve: (data: undefined)=>void, reject: (error: Error) => void): void => { + hilog.info(domainID, TAG, 'Caller call'); + resolve(undefined); + return; + }); + } + + release(): void { + hilog.info(domainID, TAG, 'Caller release called.'); + if (this.releaseState === true) { + hilog.info(domainID, TAG, 'Caller release remoteObj releaseState is true'); + throw buildError(ERROR_CODE_CALLER_RELEASED); + } + + if (this.callee == null) { + hilog.info(domainID, TAG, 'Caller release call remoteObj is released'); + throw buildError(ERROR_CODE_CLAAEE_INVALID); + } + + this.releaseState = true; + this.callee = null; + this.nativeReleaseSync(); + } + + onRelease(callback: OnReleaseCallback): void { + hilog.info(domainID, TAG, 'onRelease called'); + this.nativeOnReleaseSync(new ReleaseCallback(callback)); + } +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/UIAbilityContext.ets b/frameworks/ets/ets/application/UIAbilityContext.ets index 4c515cb3f6a..be667707bcf 100644 --- a/frameworks/ets/ets/application/UIAbilityContext.ets +++ b/frameworks/ets/ets/application/UIAbilityContext.ets @@ -16,6 +16,7 @@ import { AbilityInfo } from 'bundleManager.AbilityInfo'; import Want from '@ohos.app.ability.Want'; import StartOptions from '@ohos.app.ability.StartOptions'; +import { Caller } from '@ohos.app.ability.UIAbility'; import { BusinessError, AsyncCallback } from '@ohos.base'; import { AbilityResult } from 'ability.abilityResult'; import { Configuration } from '@ohos.app.ability.Configuration'; @@ -63,6 +64,8 @@ export default class UIAbilityContext extends Context { private native nativeStartAbilityForResult(want: Want, startOptions: StartOptions, callback: AsyncCallbackWrapper): void; + private native nativeStartAbilityByCallSync(want: Want): Caller; + private native nativeTerminateSelfSync(callback: AsyncCallbackWrapper): void; private native nativeTerminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallbackWrapper): void; @@ -165,6 +168,12 @@ export default class UIAbilityContext extends Context { return p; } + startAbilityByCall(want: Want): Promise { + return taskpool.execute((): Caller => { + return this.nativeStartAbilityByCallSync(want); + }) as Promise; + } + terminateSelf(callback: AsyncCallback): void { let myCall = new AsyncCallbackWrapper(callback); taskpool.execute((): void => { diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index e68e098980d..4e1a7c7ccc4 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -298,6 +298,7 @@ ohos_shared_library("abilitykit_native") { "${ability_runtime_native_path}/ability/native/ability_post_event_timeout.cpp", "${ability_runtime_native_path}/ability/native/ability_process.cpp", "${ability_runtime_native_path}/ability/native/ability_runtime/ets_ability_context.cpp", + "${ability_runtime_native_path}/ability/native/ability_runtime/ets_caller_complex.cpp", "${ability_runtime_native_path}/ability/native/ability_runtime/js_ability.cpp", "${ability_runtime_native_path}/ability/native/ability_runtime/js_ability_context.cpp", "${ability_runtime_native_path}/ability/native/ability_runtime/js_caller_complex.cpp", @@ -383,6 +384,7 @@ ohos_shared_library("abilitykit_native") { "ipc:ipc_core", "ipc:ipc_napi", "ipc:rpc", + "ipc:rpc_ani", "napi:ace_napi", "resource_management:global_resmgr", "runtime_core:ani", @@ -875,6 +877,7 @@ ohos_shared_library("uiabilitykit_native") { "hitrace:hitrace_meter", "ipc:ipc_core", "ipc:ipc_napi", + "ipc:rpc_ani", "resource_management:global_resmgr", "runtime_core:ani", "samgr:samgr_proxy", diff --git a/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp b/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp index 216a08b9cc8..0dce7b36625 100644 --- a/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp +++ b/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp @@ -23,6 +23,7 @@ #include "common_fun_ani.h" #include "hilog_tag_wrapper.h" #include "hitrace_meter.h" +#include "ets_caller_complex.h" #include "ets_context_utils.h" #include "ets_error_utils.h" #include "want.h" @@ -34,6 +35,51 @@ namespace { static std::once_flag g_bindNativeMethodsFlag; constexpr const char *UI_ABILITY_CONTEXT_CLASS_NAME = "Lapplication/UIAbilityContext/UIAbilityContext;"; constexpr const char *CLASSNAME_ASYNC_CALLBACK_WRAPPER = "Lutils/AbilityUtils/AsyncCallbackWrapper;"; + +constexpr int32_t CALLER_TIME_OUT = 10; // 10s +struct StartAbilityByCallData { + sptr remoteCallee; + std::mutex mutexlock; + std::condition_variable condition; +}; + +void GenerateCallerCallBack(std::shared_ptr calls, + std::shared_ptr callerCallBack) +{ + if (calls == nullptr || callerCallBack == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null calls or null callerCallBack"); + return; + } + auto callBackDone = [weakData = std::weak_ptr(calls)] (const sptr &obj) { + TAG_LOGI(AAFwkTag::UIABILITY, "callBackDone called start"); + auto calldata = weakData.lock(); + if (calldata == nullptr) { + TAG_LOGW(AAFwkTag::UIABILITY, "calldata released"); + return; + } + std::lock_guard lock(calldata->mutexlock); + calldata->remoteCallee = obj; + calldata->condition.notify_all(); + }; + + callerCallBack->SetCallBack(callBackDone); +} + +void WaitForCalleeObj(std::shared_ptr callData) +{ + if (callData == nullptr) { + return; + } + if (callData->remoteCallee == nullptr) { + std::unique_lock lock(callData->mutexlock); + if (callData->remoteCallee != nullptr) { + return; + } + if (callData->condition.wait_for(lock, std::chrono::seconds(CALLER_TIME_OUT)) == std::cv_status::timeout) { + TAG_LOGE(AAFwkTag::UIABILITY, "callExecute waiting callee timeout"); + } + } +} } // namespace std::shared_ptr EtsAbilityContext::GetAbilityContext(ani_env *env, ani_object aniObj) @@ -121,6 +167,53 @@ void EtsAbilityContext::StartAbilityForResultWithOptions( GetInstance().OnStartAbilityForResult(env, aniObj, wantObj, startOptionsObj, callback); } +ani_object EtsAbilityContext::StartAbilityByCall(ani_env *env, ani_object aniObj, ani_object wantObj) +{ + TAG_LOGI(AAFwkTag::UIABILITY, "StartAbilityByCall"); + auto context = GetAbilityContext(env, aniObj); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "GetAbilityContext is nullptr"); + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return nullptr; + } + + AAFwk::Want want; + if (!AppExecFwk::UnwrapWant(env, wantObj, want)) { + TAG_LOGE(AAFwkTag::UIABILITY, "parse want failed"); + EtsErrorUtil::ThrowInvalidParamError(env, "Parse param want failed, want must be Want."); + return nullptr; + } + auto callData = std::make_shared(); + auto callerCallBack = std::make_shared(); + GenerateCallerCallBack(callData, callerCallBack); + auto ret = context->StartAbilityByCall(want, callerCallBack, -1); + if (ret != 0) { + TAG_LOGE(AAFwkTag::UIABILITY, "startAbility failed"); + EtsErrorUtil::ThrowErrorByNativeErr(env, ret); + return nullptr; + } + WaitForCalleeObj(callData); + + if (callData->remoteCallee == nullptr) { + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER); + return nullptr; + } + + std::weak_ptr abilityContext(context); + auto releaseCallFunc = [abilityContext] (std::shared_ptr callback) -> ErrCode { + auto contextForRelease = abilityContext.lock(); + if (contextForRelease == nullptr) { + return -1; + } + return contextForRelease->ReleaseCall(callback); + }; + auto caller = CreateEtsCaller(env, releaseCallFunc, callData->remoteCallee, callerCallBack); + if (caller == nullptr) { + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER); + } + return caller; +} + void EtsAbilityContext::TerminateSelf(ani_env *env, ani_object aniObj, ani_object callback) { TAG_LOGD(AAFwkTag::CONTEXT, "TerminateSelf called"); diff --git a/frameworks/native/ability/native/ability_runtime/ets_caller_complex.cpp b/frameworks/native/ability/native/ability_runtime/ets_caller_complex.cpp new file mode 100644 index 00000000000..20b56d5a058 --- /dev/null +++ b/frameworks/native/ability/native/ability_runtime/ets_caller_complex.cpp @@ -0,0 +1,246 @@ +/* + * 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_caller_complex.h" + +#include + +#include "ability_business_error.h" +#include "ani_remote_object.h" +#include "hilog_tag_wrapper.h" +#include "ets_error_utils.h" + +namespace { // nameless +using namespace OHOS; +using namespace OHOS::AbilityRuntime; +class EtsCallerComplex; + +static std::once_flag g_bindNativeMethodsFlag; + +EtsCallerComplex *GetComplexPtrFrom(ani_env *env, ani_object aniObj) +{ + ani_long nativeCaller; + ani_status status = ANI_ERROR; + if (env == nullptr) { + TAG_LOGE(AAFwkTag::ABILITY, "null env"); + return nullptr; + } + if ((status = env->Object_GetFieldByName_Long(aniObj, "nativeCaller", &nativeCaller)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status : %{public}d", status); + return nullptr; + } + return reinterpret_cast(nativeCaller); +} + +ani_ref GetEtsRemoteObj(ani_env *env, ani_object aniObj) +{ + ani_ref etsRemoteObj = nullptr; + ani_status status = ANI_ERROR; + if (env == nullptr) { + TAG_LOGE(AAFwkTag::ABILITY, "null env"); + return nullptr; + } + if ((status = env->Object_GetFieldByName_Ref(aniObj, "callee", &etsRemoteObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status : %{public}d", status); + return nullptr; + } + return etsRemoteObj; +} + +void ReleaseNativeRemote(ani_env *env, ani_ref aniObj) +{ + TAG_LOGI(AAFwkTag::ABILITY, "ReleaseNativeRemote"); +} + +class EtsCallerComplex { +public: + EtsCallerComplex(ReleaseCallFunc releaseCallFunc, std::shared_ptr callerCallBack) + : releaseCallFunc_(releaseCallFunc), callerCallBack_(callerCallBack) {} + ~EtsCallerComplex() = default; + + static void ReleaseCall(ani_env *env, ani_object aniObj) + { + TAG_LOGI(AAFwkTag::ABILITY, "ReleaseCall"); + auto ptr = GetComplexPtrFrom(env, aniObj); + if (ptr == nullptr) { + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER); + return; + } + ptr->ReleaseCallInner(env); + + auto etsRemoteObj = GetEtsRemoteObj(env, aniObj); + ReleaseNativeRemote(env, etsRemoteObj); + } + + static void SetOnRelease(ani_env *env, ani_object aniObj, ani_object callback) + { + TAG_LOGI(AAFwkTag::ABILITY, "SetOnRelease"); + auto ptr = GetComplexPtrFrom(env, aniObj); + if (ptr == nullptr || ptr->callerCallBack_ == nullptr) { + TAG_LOGE(AAFwkTag::ABILITY, "SetOnRelease null"); + return; + } + ani_vm *aniVM = nullptr; + if (env->GetVM(&aniVM) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "get aniVM failed"); + return; + } + ani_ref callbackRef = nullptr; + ani_status status = ANI_ERROR; + if ((status = env->GlobalReference_Create(callback, &callbackRef)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "callbackRef: %{public}d", status); + return; + } + ptr->callerCallBack_->SetOnRelease([aniVM, callbackRef](const std::string &msg) { + ani_string aniMsg = nullptr; + ani_status status = ANI_ERROR; + ani_env *aniEnv = nullptr; + if ((status = aniVM->GetEnv(ANI_VERSION_1, &aniEnv)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "GetEnv failed, status : %{public}d", status); + return; + } + if ((status = aniEnv->String_NewUTF8(msg.c_str(), msg.size(), &aniMsg)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "String_NewUTF8 failed %{public}d", status); + return; + } + status = aniEnv->Object_CallMethodByName_Void(reinterpret_cast(callbackRef), "invoke", + "Lstd/core/String;:V", aniMsg); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "OnRelease call failed %{public}d", status); + } + aniEnv->GlobalReference_Delete(callbackRef); + }); + } + + static void SetOnRemoteStateChange(ani_env *env, ani_object aniObj, ani_object callback) + { + TAG_LOGI(AAFwkTag::ABILITY, "SetOnRemoteStateChange"); + } + +private: + void ReleaseCallInner(ani_env *env) + { + TAG_LOGD(AAFwkTag::ABILITY, "called"); + if (callerCallBack_ == nullptr) { + TAG_LOGE(AAFwkTag::ABILITY, "null CallBacker"); + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER); + return; + } + + if (!releaseCallFunc_) { + TAG_LOGE(AAFwkTag::ABILITY, "null releaseFunc"); + EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER); + return; + } + + callerCallBack_->SetCallBack(nullptr); + int32_t innerErrorCode = releaseCallFunc_(callerCallBack_); + if (innerErrorCode != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "ReleaseAbility failed %{public}d", static_cast(innerErrorCode)); + EtsErrorUtil::ThrowError(env, innerErrorCode); + } + } + +private: + ReleaseCallFunc releaseCallFunc_; + std::shared_ptr callerCallBack_; +}; + +bool BindNativeMethods(ani_env *env, ani_class &cls) +{ + if (cls == nullptr) { + TAG_LOGE(AAFwkTag::ABILITY, "cls null"); + return false; + } + ani_status status = ANI_OK; + std::call_once(g_bindNativeMethodsFlag, [&status, env, cls]() { + std::array functions = { + ani_native_function { "nativeReleaseSync", nullptr, + reinterpret_cast(EtsCallerComplex::ReleaseCall) }, + }; + + status = env->Class_BindNativeMethods(cls, functions.data(), functions.size()); + }); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status: %{public}d", status); + return false; + } + return true; +} +} // nameless + +namespace OHOS { +namespace AbilityRuntime { +ani_object CreateEtsCaller(ani_env *env, ReleaseCallFunc releaseCallFunc, + sptr callee, std::shared_ptr callback) +{ + ani_class cls {}; + ani_status status = ANI_ERROR; + ani_object callerObj = nullptr; + ani_method method {}; + + if ((status = env->FindClass("Lcaller/Caller/CallerImpl;", &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status : %{public}d", status); + return nullptr; + } + if (!BindNativeMethods(env, cls)) { + return nullptr; + } + if ((status = env->Class_FindMethod(cls, "", ":V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status : %{public}d", status); + return nullptr; + } + if ((status = env->Object_New(cls, method, &callerObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status : %{public}d", status); + return nullptr; + } + auto etsCaller = std::make_unique(releaseCallFunc, callback); + ani_long nativeCaller = (ani_long)(etsCaller.get()); + if ((status = env->Object_SetFieldByName_Long(callerObj, "nativeCaller", nativeCaller)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status : %{public}d", status); + return nullptr; + } + auto remoteObj = ANI_ohos_rpc_CreateJsRemoteObject(env, callee); + if ((status = env->Object_SetFieldByName_Ref(callerObj, "callee", remoteObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "status : %{public}d", status); + return nullptr; + } + etsCaller.release(); + return callerObj; +} + +ani_object CreateEtsCallee(ani_env *env) +{ + ani_class cls {}; + ani_status status = ANI_ERROR; + ani_object calleeObj = nullptr; + ani_method method {}; + + if ((status = env->FindClass("Lcallee/Callee/CalleeImpl;", &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "CalleeImpl: %{public}d", status); + return nullptr; + } + if ((status = env->Class_FindMethod(cls, "", ":V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "callee ctor : %{public}d", status); + return nullptr; + } + if ((status = env->Object_New(cls, method, &calleeObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITY, "create callee: %{public}d", status); + return nullptr; + } + return calleeObj; +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/ability/native/ability_runtime/ets_ui_ability.cpp b/frameworks/native/ability/native/ability_runtime/ets_ui_ability.cpp index a2c11640acf..14c18609a90 100644 --- a/frameworks/native/ability/native/ability_runtime/ets_ui_ability.cpp +++ b/frameworks/native/ability/native/ability_runtime/ets_ui_ability.cpp @@ -703,6 +703,34 @@ void EtsUIAbility::OnAbilityResult(int requestCode, int resultCode, const Want & TAG_LOGD(AAFwkTag::UIABILITY, "OnAbilityResult end"); } +sptr EtsUIAbility::CallRequest() +{ + TAG_LOGI(AAFwkTag::UIABILITY, "CallRequest"); + if (etsAbilityObj_ == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null abilityContext_"); + return nullptr; + } + + auto env = stsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null env"); + return nullptr; + } + auto obj = etsAbilityObj_->aniObj; + ani_status status = ANI_ERROR; + ani_ref calleeRef = nullptr; + status = env->Object_GetFieldByName_Ref(obj, "callee", &calleeRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "get callee: %{public}d", status); + return nullptr; + } + auto remoteObj = AniGetNativeRemoteObject(env, reinterpret_cast(calleeRef)); + if (remoteObj == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "AniGetNativeRemoteObject null"); + } + return remoteObj; +} + bool EtsUIAbility::CallObjectMethod(bool withResult, const char *name, const char *signature, ...) { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, std::string("CallObjectMethod:") + name); diff --git a/frameworks/native/ability/native/ability_runtime/js_ability_context.cpp b/frameworks/native/ability/native/ability_runtime/js_ability_context.cpp index 023ae218260..4856b49581c 100644 --- a/frameworks/native/ability/native/ability_runtime/js_ability_context.cpp +++ b/frameworks/native/ability/native/ability_runtime/js_ability_context.cpp @@ -225,7 +225,7 @@ void StartAbilityByCallComplete(napi_env env, NapiAsyncTask& task, std::weak_ptr TAG_LOGD(AAFwkTag::CONTEXT, "callComplete end"); return; } - auto releaseCallAbilityFunc = [abilityContext] (const std::shared_ptr &callback) -> ErrCode { + auto releaseCallAbilityFunc = [abilityContext] (const std::shared_ptr callback) -> ErrCode { auto contextForRelease = abilityContext.lock(); if (contextForRelease == nullptr) { TAG_LOGE(AAFwkTag::CONTEXT, "null releaseCallAbilityFunction"); diff --git a/interfaces/kits/native/ability/ability_runtime/caller_callback.h b/interfaces/kits/native/ability/ability_runtime/caller_callback.h index c1ce7dadf36..111fb18de22 100644 --- a/interfaces/kits/native/ability/ability_runtime/caller_callback.h +++ b/interfaces/kits/native/ability/ability_runtime/caller_callback.h @@ -90,6 +90,8 @@ private: bool isCallBack_ = false; std::weak_ptr localCallRecord_; }; + +using ReleaseCallFunc = std::function)>; } // namespace AbilityRuntime } // namespace OHOS #endif // OHOS_ABILITY_RUNTIME_CALLER_CALLBACK_H diff --git a/interfaces/kits/native/ability/native/ability_runtime/ets_ability_context.h b/interfaces/kits/native/ability/native/ability_runtime/ets_ability_context.h index 61850588338..d6c53389fd9 100644 --- a/interfaces/kits/native/ability/native/ability_runtime/ets_ability_context.h +++ b/interfaces/kits/native/ability/native/ability_runtime/ets_ability_context.h @@ -37,6 +37,7 @@ public: static void StartAbilityForResult(ani_env *env, ani_object aniObj, ani_object wantObj, ani_object callback); static void StartAbilityForResultWithOptions( ani_env *env, ani_object aniObj, ani_object wantObj, ani_object startOptionsObj, ani_object callback); + static ani_object StartAbilityByCall(ani_env *env, ani_object aniObj, ani_object wantObj); static void TerminateSelf(ani_env *env, ani_object aniObj, ani_object callback); static void TerminateSelfWithResult(ani_env *env, ani_object aniObj, ani_object abilityResult, ani_object callback); static void ReportDrawnCompleted(ani_env *env, ani_object aniObj, ani_object call); diff --git a/interfaces/kits/native/ability/native/ability_runtime/ets_caller_complex.h b/interfaces/kits/native/ability/native/ability_runtime/ets_caller_complex.h new file mode 100644 index 00000000000..fdcf2d4737d --- /dev/null +++ b/interfaces/kits/native/ability/native/ability_runtime/ets_caller_complex.h @@ -0,0 +1,32 @@ +/* + * 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_SIMULATOR_STS_CALLER_COMPLEX_H +#define OHOS_ABILITY_RUNTIME_SIMULATOR_STS_CALLER_COMPLEX_H + +#include +#include + +#include "caller_callback.h" +#include "ets_runtime.h" + +namespace OHOS { +namespace AbilityRuntime { +ani_object CreateEtsCaller(ani_env *env, ReleaseCallFunc releaseCallFunc, + sptr callee, std::shared_ptr callback); +ani_object CreateEtsCallee(ani_env *env); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_SIMULATOR_STS_CALLER_COMPLEX_H \ No newline at end of file diff --git a/interfaces/kits/native/ability/native/ability_runtime/ets_ui_ability.h b/interfaces/kits/native/ability/native/ability_runtime/ets_ui_ability.h index fc559230dfd..800eb38a937 100644 --- a/interfaces/kits/native/ability/native/ability_runtime/ets_ui_ability.h +++ b/interfaces/kits/native/ability/native/ability_runtime/ets_ui_ability.h @@ -99,6 +99,8 @@ public: */ void OnAbilityResult(int requestCode, int resultCode, const Want &resultData) override; + sptr CallRequest() override; + #ifdef SUPPORT_SCREEN public: /** diff --git a/interfaces/kits/native/ability/native/ability_runtime/js_caller_complex.h b/interfaces/kits/native/ability/native/ability_runtime/js_caller_complex.h index 3ee04a43e1a..9e33f52ef24 100644 --- a/interfaces/kits/native/ability/native/ability_runtime/js_caller_complex.h +++ b/interfaces/kits/native/ability/native/ability_runtime/js_caller_complex.h @@ -24,8 +24,6 @@ namespace OHOS { namespace AbilityRuntime { -using ReleaseCallFunc = std::function&)>; - napi_value CreateJsCallerComplex( napi_env env, ReleaseCallFunc releaseCallFunc, sptr callee, std::shared_ptr callerCallBack); -- Gitee