diff --git a/frameworks/native/ability/native/ui_extension_ability/js_ui_extension.cpp b/frameworks/native/ability/native/ui_extension_ability/js_ui_extension.cpp index 68d34fb5e5..c84d18eea8 100755 --- a/frameworks/native/ability/native/ui_extension_ability/js_ui_extension.cpp +++ b/frameworks/native/ability/native/ui_extension_ability/js_ui_extension.cpp @@ -359,6 +359,7 @@ bool JsUIExtension::CheckPromise(napi_value result) return true; } +namespace { napi_value PromiseCallback(napi_env env, napi_callback_info info) { void *data = nullptr; @@ -373,6 +374,7 @@ napi_value PromiseCallback(napi_env env, napi_callback_info info) data = nullptr; return nullptr; } +} bool JsUIExtension::CallPromise(napi_value result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo) { diff --git a/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp b/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp index b927505abe..d67caba6dd 100644 --- a/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp +++ b/frameworks/native/ability/native/ui_extension_ability/js_ui_extension_base.cpp @@ -21,7 +21,10 @@ #include "ability_info.h" #include "ability_manager_client.h" #include "configuration_utils.h" +#include "connection_manager.h" +#include "context.h" #include "hilog_tag_wrapper.h" +#include "hilog_wrapper.h" #include "hitrace_meter.h" #include "insight_intent_executor_info.h" #include "insight_intent_executor_mgr.h" @@ -244,6 +247,131 @@ void JsUIExtensionBase::OnStop() #ifdef SUPPORT_GRAPHICS UnregisterDisplayInfoChangedListener(); #endif // SUPPORT_GRAPHICS + + OnStopCallBack(); + TAG_LOGD(AAFwkTag::UI_EXT, "end"); +} + +void JsUIExtensionBase::OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback) +{ + if (callbackInfo == nullptr) { + isAsyncCallback = false; + OnStop(); + return; + } + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::UI_EXT, "begin"); + HandleScope handleScope(jsRuntime_); + napi_value result = CallObjectMethod("onDestroy", nullptr, 0, true); + if (!CheckPromise(result)) { + OnStopCallBack(); + isAsyncCallback = false; + return; + } + + auto asyncCallback = [extensionWeakPtr = weak_from_this()]() { + auto jsUIExtensionBase = extensionWeakPtr.lock(); + if (jsUIExtensionBase == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "extension is nullptr"); + return; + } + jsUIExtensionBase->OnStopCallBack(); + }; + callbackInfo->Push(asyncCallback); + isAsyncCallback = CallPromise(result, callbackInfo); + if (!isAsyncCallback) { + TAG_LOGE(AAFwkTag::UI_EXT, "Failed to call promise"); + OnStopCallBack(); + } + TAG_LOGD(AAFwkTag::UI_EXT, "end"); +} + +void JsUIExtensionBase::OnStopCallBack() +{ + if (context_ == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "Failed to get context"); + return; + } + auto ret = ConnectionManager::GetInstance().DisconnectCaller(context_->GetToken()); + if (ret) { + ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid()); + TAG_LOGD(AAFwkTag::UI_EXT, "service connection not disconnected"); + } + + auto applicationContext = Context::GetApplicationContext(); + if (applicationContext != nullptr) { + applicationContext->DispatchOnAbilityDestroy(jsObj_); + } +} + +bool JsUIExtensionBase::CheckPromise(napi_value result) +{ + if (result == nullptr) { + TAG_LOGD(AAFwkTag::UI_EXT, "result is nullptr"); + return false; + } + napi_env env = jsRuntime_.GetNapiEnv(); + bool isPromise = false; + napi_is_promise(env, result, &isPromise); + if (!isPromise) { + TAG_LOGD(AAFwkTag::UI_EXT, "result isn't promise"); + return false; + } + return true; +} + +namespace { +napi_value PromiseCallback(napi_env env, napi_callback_info info) +{ + void *data = nullptr; + NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data), nullptr); + auto *callbackInfo = static_cast *>(data); + if (callbackInfo == nullptr) { + TAG_LOGD(AAFwkTag::UI_EXT, "Invalid input"); + return nullptr; + } + callbackInfo->Call(); + AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo); + data = nullptr; + return nullptr; +} +} + +bool JsUIExtensionBase::CallPromise(napi_value result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo) +{ + auto env = jsRuntime_.GetNapiEnv(); + if (!CheckTypeForNapiValue(env, result, napi_object)) { + TAG_LOGE(AAFwkTag::UI_EXT, "Failed to convert native value to NativeObject"); + return false; + } + napi_value then = nullptr; + napi_get_named_property(env, result, "then", &then); + if (then == nullptr) { + TAG_LOGE(AAFwkTag::UI_EXT, "Failed to get property: then"); + return false; + } + bool isCallable = false; + napi_is_callable(env, then, &isCallable); + if (!isCallable) { + TAG_LOGE(AAFwkTag::UI_EXT, "property then is not callable"); + return false; + } + HandleScope handleScope(jsRuntime_); + napi_value promiseCallback = nullptr; + napi_status createStatus = napi_create_function(env, "promiseCallback", strlen("promiseCallback"), PromiseCallback, + callbackInfo, &promiseCallback); + if (createStatus != napi_ok) { + TAG_LOGE(AAFwkTag::UI_EXT, "Failed to create promiseCallback, %{public}d", createStatus); + return false; + } + napi_value argv[1] = { promiseCallback }; + napi_status callStatus = napi_call_function(env, result, then, 1, argv, nullptr); + if (callStatus != napi_ok) { + TAG_LOGE(AAFwkTag::UI_EXT, "Failed to call promiseCallback, %{public}d", callStatus); + return false; + } + TAG_LOGD(AAFwkTag::UI_EXT, "exit"); + return true; } void JsUIExtensionBase::OnCommandWindow( @@ -611,7 +739,7 @@ void JsUIExtensionBase::DestroyWindow(const sptr &sessionInf } } -napi_value JsUIExtensionBase::CallObjectMethod(const char *name, napi_value const *argv, size_t argc) +napi_value JsUIExtensionBase::CallObjectMethod(const char *name, napi_value const *argv, size_t argc, bool withResult) { TAG_LOGD(AAFwkTag::UI_EXT, "CallObjectMethod(%{public}s), begin", name); if (!jsObj_) { @@ -624,13 +752,18 @@ napi_value JsUIExtensionBase::CallObjectMethod(const char *name, napi_value cons TAG_LOGE(AAFwkTag::UI_EXT, "Failed to get object"); return nullptr; } - + HandleEscape handleEscape(jsRuntime_); napi_value method = nullptr; napi_get_named_property(env, obj, name, &method); if (!CheckTypeForNapiValue(env, method, napi_function)) { TAG_LOGE(AAFwkTag::UI_EXT, "Failed to get '%{public}s' object", name); return nullptr; } + if (withResult) { + napi_value result = nullptr; + napi_call_function(env, obj, method, argc, argv, &result); + return handleEscape.Escape(result); + } TAG_LOGD(AAFwkTag::UI_EXT, "CallFunction(%{public}s), success", name); napi_value result = nullptr; napi_call_function(env, obj, method, argc, argv, &result); diff --git a/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h b/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h index 2f6d85c78d..2a3d2d2951 100644 --- a/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h +++ b/interfaces/kits/native/ability/native/ui_extension_ability/js_ui_extension_base.h @@ -24,7 +24,7 @@ #include "native_engine/native_engine.h" #include "ohos_application.h" #include "session_info.h" -#include "ui_extension_base.h" +#include "ui_extension_base_impl.h" #include "ui_extension_context.h" #include "ui_extension_window_command.h" #include "want.h" @@ -101,6 +101,11 @@ public: * You can override this function to implement your own processing logic. */ void OnStop() override; + virtual void OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback); + /** + * @brief The callback of OnStop. + */ + virtual void OnStopCallBack(); /** * @brief Called when the system configuration is updated. @@ -165,7 +170,10 @@ public: void ConfigurationUpdated(); protected: - napi_value CallObjectMethod(const char *name, napi_value const *argv = nullptr, size_t argc = 0); + napi_value CallObjectMethod(const char *name, napi_value const *argv = nullptr, size_t argc = 0, + bool withResult = false); + bool CheckPromise(napi_value result); + bool CallPromise(napi_value result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo); void ForegroundWindow(const AAFwk::Want &want, const sptr &sessionInfo); void BackgroundWindow(const sptr &sessionInfo); void DestroyWindow(const sptr &sessionInfo); @@ -183,7 +191,7 @@ protected: protected: JsRuntime &jsRuntime_; std::shared_ptr shellContextRef_; - std::unique_ptr jsObj_; + std::shared_ptr jsObj_; std::shared_ptr context_; std::map> uiWindowMap_; std::set foregroundWindows_;