From a37cfb7064ad4693b95100a2f4f4ad49ba154a60 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Thu, 5 Jun 2025 22:00:46 +0800 Subject: [PATCH] add ets onPrepareToTerminateAsync Signed-off-by: zhangzezhong --- .../ets/ets/@ohos.app.ability.UIAbility.ets | 24 ++++++ .../native/ability_runtime/sts_ui_ability.cpp | 86 ++++++++++++++++++- .../native/ability_runtime/sts_ui_ability.h | 7 ++ 3 files changed, 116 insertions(+), 1 deletion(-) diff --git a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets index dee014b5f1c..954129be499 100644 --- a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets +++ b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets @@ -33,7 +33,9 @@ export interface Callee { export default class UIAbility { private destroyCallbackPoint: long; + private prepareToTerminateCallbackPoint: long; private native nativeOnDestroyCallback(): void; + private native nativeOnPrepareToTerminateCallback(prepareTermination: boolean): void; private callOnDestroy(): boolean { const derivedClassType = AbilityUtils.getClassType(this); if (derivedClassType === undefined) { @@ -54,6 +56,24 @@ export default class UIAbility { return false; } + private callOnPrepareToTerminate(): boolean { + const derivedClassType = AbilityUtils.getClassType(this); + if (derivedClassType === undefined) { + return false; + } + const uiAbilityClassType = AbilityUtils.getClassType(new UIAbility()); + if (uiAbilityClassType === undefined) { + return false; + } + const isOverride = AbilityUtils.isOverride(derivedClassType, "onPrepareToTerminateAsync", uiAbilityClassType); + if (isOverride) { + this.onPrepareToTerminateAsync().then((prepareTermination: boolean) => this.nativeOnPrepareToTerminateCallback(prepareTermination)); + return true; + } + return false; + } + + context: UIAbilityContext = new UIAbilityContext(); launchWant: Want = new Want(); lastRequestWant: Want = new Want(); @@ -71,4 +91,8 @@ export default class UIAbility { onForeground(): void {} onBackground(): void {} onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {} + onPrepareToTerminateAsync(): Promise { + return new Promise((resolve: (a: boolean) => void, + reject: (err: Error) => void): boolean => {}); + } } diff --git a/frameworks/native/ability/native/ability_runtime/sts_ui_ability.cpp b/frameworks/native/ability/native/ability_runtime/sts_ui_ability.cpp index 7c028130760..0881fdab0fe 100644 --- a/frameworks/native/ability/native/ability_runtime/sts_ui_ability.cpp +++ b/frameworks/native/ability/native/ability_runtime/sts_ui_ability.cpp @@ -79,7 +79,7 @@ constexpr const int32_t API_VERSION_MOD = 100; constexpr const char* UI_ABILITY_CONTEXT_CLASS_NAME = "Lapplication/UIAbilityContext/UIAbilityContext;"; constexpr const char* UI_ABILITY_CLASS_NAME = "L@ohos/app/ability/UIAbility/UIAbility;"; -void OnDestroyPromiseCallback(ani_env* env, ani_object aniObj) +void OnDestroyPromiseCallback(ani_env *env, ani_object aniObj) { TAG_LOGI(AAFwkTag::UIABILITY, "OnDestroyPromiseCallback"); if (env == nullptr) { @@ -99,6 +99,41 @@ void OnDestroyPromiseCallback(ani_env* env, ani_object aniObj) } callbackInfo->Call(); AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo); + if ((status = env->Object_SetFieldByName_Long(aniObj, "destroyCallbackPoint", 0)) != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_SetFieldByName_Long status: %{public}d", status); + return; + } +} + +void OnPrepareTerminatePromiseCallback(ani_env *env, ani_object aniObj, ani_boolean aniPrepareTermination) +{ + TAG_LOGI(AAFwkTag::UIABILITY, "OnPrepareTerminatePromiseCallback begin"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null env"); + return; + } + ani_long prepareToTerminateCallbackPoint = 0; + ani_status status = + env->Object_GetFieldByName_Long(aniObj, "prepareToTerminateCallbackPoint", &prepareToTerminateCallbackPoint); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_GetFieldByName_Long status: %{public}d", status); + return; + } + auto *callbackInfo = + reinterpret_cast *>(prepareToTerminateCallbackPoint); + if (callbackInfo == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null callbackInfo"); + return; + } + bool prepareTermination = aniPrepareTermination; + callbackInfo->Call(prepareTermination); + AppExecFwk::AbilityTransactionCallbackInfo::Destroy(callbackInfo); + if ((status = env->Object_SetFieldByName_Long(aniObj, "prepareToTerminateCallbackPoint", 0)) != + ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_SetFieldByName_Long status: %{public}d", status); + return; + } + TAG_LOGI(AAFwkTag::UIABILITY, "OnPrepareTerminatePromiseCallback end"); } } // namespace @@ -186,6 +221,7 @@ bool StsUIAbility::BindNativeMethods() std::call_once(singletonFlag_, [&status, env, cls]() { std::array functions = { ani_native_function { "nativeOnDestroyCallback", ":V", reinterpret_cast(OnDestroyPromiseCallback) }, + ani_native_function { "nativeOnPrepareToTerminateCallback", nullptr, reinterpret_cast(OnPrepareTerminatePromiseCallback) }, }; status = env->Class_BindNativeMethods(cls, functions.data(), functions.size()); }); @@ -722,6 +758,54 @@ bool StsUIAbility::OnBackPress() return ret; } +void StsUIAbility::OnPrepareTerminate(AppExecFwk::AbilityTransactionCallbackInfo *callbackInfo, bool &isAsync) +{ + TAG_LOGE(AAFwkTag::UIABILITY, "OnPrepareTerminate"); + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::UIABILITY, "ability: %{public}s", GetAbilityName().c_str()); + UIAbility::OnPrepareTerminate(callbackInfo, isAsync); + auto env = stsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null env"); + return; + } + if (stsAbilityObj_ == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null stsAbilityObj"); + return; + } + ani_long prepareToTerminateCallbackPoint = (ani_long)callbackInfo; + ani_status status = ANI_ERROR; + if ((status = env->Object_SetFieldByName_Long( + stsAbilityObj_->aniObj, "prepareToTerminateCallbackPoint", prepareToTerminateCallbackPoint)) != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_SetFieldByName_Long status: %{public}d", status); + return; + } + bool onPrepareToTerminateAsyncResult = false; + onPrepareToTerminateAsyncResult = CallObjectMethod(true, "callOnPrepareToTerminate", nullptr); + if (onPrepareToTerminateAsyncResult) { + TAG_LOGI(AAFwkTag::UIABILITY, "async call"); + isAsync = true; + return; + } + TAG_LOGI(AAFwkTag::UIABILITY, "onPrepareToTerminateAsync not implemented, call onPrepareToTerminate"); + ani_method method {}; + if ((status = env->Class_FindMethod(stsAbilityObj_->aniCls, "onPrepareToTerminate", nullptr, &method)) != ANI_OK) { + if (status != ANI_PENDING_ERROR) { + TAG_LOGE(AAFwkTag::UIABILITY, "Class_FindMethod status: %{public}d", status); + } + TAG_LOGW(AAFwkTag::UIABILITY, "neither is implemented"); + env->ResetError(); + return; + } + ani_boolean isTerminateAni = false; + if ((status = env->Object_CallMethod_Boolean(stsAbilityObj_->aniObj, method, &isTerminateAni)) != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_CallMethod_Boolean status: %{public}d", status); + return; + } + bool isTerminate = isTerminateAni; + callbackInfo->Call(isTerminate); +} + ani_object StsUIAbility::CreateAppWindowStage() { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); diff --git a/interfaces/kits/native/ability/native/ability_runtime/sts_ui_ability.h b/interfaces/kits/native/ability/native/ability_runtime/sts_ui_ability.h index c3019ded152..f9985a5e5cd 100644 --- a/interfaces/kits/native/ability/native/ability_runtime/sts_ui_ability.h +++ b/interfaces/kits/native/ability/native/ability_runtime/sts_ui_ability.h @@ -235,6 +235,13 @@ public: */ bool OnBackPress() override; + /** + * @brief Called when ability prepare terminate. + * @param callbackInfo The callbackInfo is used when onPrepareToTerminateAsync is implemented. + * @param isAsync The returned flag indicates if onPrepareToTerminateAsync is implemented. + */ + void OnPrepareTerminate(AppExecFwk::AbilityTransactionCallbackInfo *callbackInfo, bool &isAsync) override; + /** * @brief Get JsWindow Stage * @return Returns the current STSNativeReference -- Gitee