diff --git a/frameworks/ets/ani/service_extension_ability/src/ets_service_extension.cpp b/frameworks/ets/ani/service_extension_ability/src/ets_service_extension.cpp index 099d12a309a6e7509b40bfae7926f04fb7b11620..166300fbc9d931f8fa7cbc4917f562112d3916a3 100644 --- a/frameworks/ets/ani/service_extension_ability/src/ets_service_extension.cpp +++ b/frameworks/ets/ani/service_extension_ability/src/ets_service_extension.cpp @@ -28,14 +28,13 @@ namespace OHOS { namespace AbilityRuntime { using namespace OHOS::AppExecFwk; namespace { -constexpr const char *CLASSNAME_SERVICE_ABILITY = - "L@ohos/app/ability/ServiceExtensionAbility/ServiceExtensionAbility;"; +constexpr const char *CLASSNAME_SERVICE_ABILITY = "L@ohos/app/ability/ServiceExtensionAbility/ServiceExtensionAbility;"; constexpr const char *NATIVE_ONCONNECT_CALLBACK_SIGNATURE = "L@ohos/rpc/rpc/RemoteObject;:Z"; constexpr const char *ON_CREATE_SIGNATURE = "L@ohos/app/ability/Want/Want;:V"; constexpr const char *VOID_SIGNATURE = ":V"; constexpr const char *ON_CONNECT_SIGNATURE = "L@ohos/app/ability/Want/Want;:Lstd/core/Object;"; constexpr const char *CHECK_PROMISE_SIGNATURE = "Lstd/core/Object;:Z"; -constexpr const char *CALL_PROMISE_SIGNATURE = "Lstd/core/Object;:Z"; +constexpr const char *CALL_PROMISE_SIGNATURE = "Lstd/core/Promise;:Z"; constexpr const char *ON_DISCONNECT_SIGNATURE = "L@ohos/app/ability/Want/Want;:V"; constexpr const char *ON_REQUEST_SIGNATURE = "L@ohos/app/ability/Want/Want;D:V"; @@ -46,14 +45,13 @@ void DisconnectPromiseCallback(ani_env *env, ani_object aniObj) TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); return; } - ani_long disconnectCallbackPoint = 0; + ani_long disconnectCallback = 0; ani_status status = ANI_ERROR; - if ((status = env->Object_GetFieldByName_Long(aniObj, "disconnectCallbackPoint", &disconnectCallbackPoint)) != - ANI_OK) { + if ((status = env->Object_GetFieldByName_Long(aniObj, "disconnectCallback", &disconnectCallback)) != ANI_OK) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return; } - auto *callbackInfo = reinterpret_cast *>(disconnectCallbackPoint); + auto *callbackInfo = reinterpret_cast *>(disconnectCallback); if (callbackInfo == nullptr) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "null callbackInfo"); return; @@ -69,9 +67,9 @@ void ConnectPromiseCallback(ani_env *env, ani_object aniObj, ani_object obj) TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); return; } - ani_long connectCallbackPoint = 0; + ani_long connectCallback = 0; ani_status status = ANI_ERROR; - if ((status = env->Object_GetFieldByName_Long(aniObj, "connectCallbackPoint", &connectCallbackPoint)) != ANI_OK) { + if ((status = env->Object_GetFieldByName_Long(aniObj, "connectCallback", &connectCallback)) != ANI_OK) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return; } @@ -80,7 +78,7 @@ void ConnectPromiseCallback(ani_env *env, ani_object aniObj, ani_object obj) TAG_LOGE(AAFwkTag::SERVICE_EXT, "null remoteObject"); } auto *callbackInfo = - reinterpret_cast> *>(connectCallbackPoint); + reinterpret_cast> *>(connectCallback); if (callbackInfo == nullptr) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "null callbackInfo"); return; @@ -93,7 +91,7 @@ void ConnectPromiseCallback(ani_env *env, ani_object aniObj, ani_object obj) EtsServiceExtension *EtsServiceExtension::Create(const std::unique_ptr &runtime) { - return new EtsServiceExtension(static_cast(*runtime)); + return new (std::nothrow) EtsServiceExtension(static_cast(*runtime)); } EtsServiceExtension::EtsServiceExtension(ETSRuntime &etsRuntime) : etsRuntime_(etsRuntime) {} @@ -228,14 +226,14 @@ sptr EtsServiceExtension::OnConnect(const AAFwk::Want &want, TAG_LOGE(AAFwkTag::SERVICE_EXT, "null wantRef"); return nullptr; } - ani_long connectCallbackPoint = (ani_long)callbackInfo; + ani_long connectCallback = (ani_long)callbackInfo; ani_status status = ANI_ERROR; ani_field callbackField = nullptr; - if ((status = env->Class_FindField(etsObj_->aniCls, "connectCallbackPoint", &callbackField)) != ANI_OK) { + if ((status = env->Class_FindField(etsObj_->aniCls, "connectCallback", &callbackField)) != ANI_OK) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return nullptr; } - if ((status = env->Object_SetField_Long(etsObj_->aniObj, callbackField, connectCallbackPoint)) != ANI_OK) { + if ((status = env->Object_SetField_Long(etsObj_->aniObj, callbackField, connectCallback)) != ANI_OK) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return nullptr; } @@ -270,7 +268,7 @@ sptr EtsServiceExtension::OnConnectInner(ani_env *env, ani_object TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return nullptr; } - ani_boolean callResult = false; + ani_boolean callResult = ANI_FALSE; if ((status = env->Object_CallMethod_Boolean(etsObj_->aniObj, method, &callResult, aniRemoteobj)) != ANI_OK) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return nullptr; @@ -317,18 +315,25 @@ void EtsServiceExtension::OnDisconnect( OnDisconnect(want); return; } - ani_long disconnectCallbackPoint = (ani_long)callbackInfo; - ani_status status = ANI_ERROR; + ani_long disconnectCallback = (ani_long)callbackInfo; + ani_field field = nullptr; - if ((status = env->Class_FindField(etsObj_->aniCls, "disconnectCallbackPoint", &field)) != ANI_OK) { + ani_status status = env->Class_FindField(etsObj_->aniCls, "disconnectCallback", &field); + if (status != ANI_OK) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return; } - if ((status = env->Object_SetField_Long(etsObj_->aniObj, field, disconnectCallbackPoint)) != ANI_OK) { + if (field == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null field"); + return; + } + if ((status = env->Object_SetField_Long(etsObj_->aniObj, field, disconnectCallback)) != ANI_OK) { TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); return; } - CallObjectMethod(false, "callOnDisconnect", ON_DISCONNECT_SIGNATURE, wantRef); + ani_boolean callResult = ANI_FALSE; + CallObjectMethod(true, "callOnDisconnect", ON_DISCONNECT_SIGNATURE, &callResult, wantRef); + isAsyncCallback = callResult; } void EtsServiceExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId) diff --git a/frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets b/frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets index c17298b63ebf2e620d569f7140218d4929ee888b..d682398fc09868bfbdb843ee2a56f8df2f1344e3 100644 --- a/frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets +++ b/frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets @@ -18,6 +18,7 @@ import Want from '@ohos.app.ability.Want'; import ServiceExtensionContext from 'application.ServiceExtensionContext'; import { Configuration } from '@ohos.app.ability.Configuration' import hilog from '@ohos.hilog'; +import { AbilityUtils } from './utils/AbilityUtils'; class MyService extends rpc.RemoteObject { constructor(descriptor: string) { @@ -35,7 +36,7 @@ class MyService extends rpc.RemoteObject { } export default class ServiceExtensionAbility { - private connectCallbackPoint: long; + private connectCallback: long; private native nativeOnConnectCallback(service: rpc.RemoteObject): boolean; @@ -51,20 +52,28 @@ export default class ServiceExtensionAbility { return this.nativeOnConnectCallback(remoteObj); } - private isOnDisconnectAsync: boolean = true; - private disconnectCallbackPoint: long; + private disconnectCallback: long; private native nativeOnDisconnectCallback(): void; - private callOnDisconnect(want: Want): void { - let p = this.onDisconnectAsync(want); - if (this.isOnDisconnectAsync) { - p.then((a: undefined): void => { - this.nativeOnDisconnectCallback(); - }); - } else { + private callOnDisconnect(want: Want): boolean { + const derivedClassType = AbilityUtils.getClassType(this); + if (derivedClassType === undefined) { this.onDisconnect(want); + return false; } + const serviceExtensionClassType = AbilityUtils.getClassType(new ServiceExtensionAbility()); + if (serviceExtensionClassType === undefined) { + this.onDisconnect(want); + return false; + } + const isOverride = AbilityUtils.isOverride(derivedClassType, "onDisconnectAsync", serviceExtensionClassType); + if (isOverride) { + this.onDisconnectAsync(want).then(() => this.nativeOnDisconnectCallback()); + return true; + } + this.onDisconnect(want); + return false; } launchWant: Want = new Want(); @@ -89,9 +98,6 @@ export default class ServiceExtensionAbility { } onDisconnectAsync(want: Want): Promise { - console.log("onDisconnectAsync"); - this.isOnDisconnectAsync = false; - return new Promise((resolve: (a: undefined) => void, reject: (err: Error) => void): void => { - }); + return new Promise((resolve: (a: undefined) => void, reject: (err: Error) => void): void => {}); } } \ No newline at end of file diff --git a/frameworks/native/ability/ability_runtime/ets_extension_context.cpp b/frameworks/native/ability/ability_runtime/ets_extension_context.cpp index cdeb556cd9cdf56b998c5209175e334b012cc624..008cfc12993cabbc5a41d58bfe1198affe90991e 100644 --- a/frameworks/native/ability/ability_runtime/ets_extension_context.cpp +++ b/frameworks/native/ability/ability_runtime/ets_extension_context.cpp @@ -24,46 +24,46 @@ namespace AbilityRuntime { bool SetExtensionAbilityInfo(ani_env *aniEnv, ani_class contextClass, ani_object contextObj, std::shared_ptr context, std::shared_ptr abilityInfo) { - bool iRet = false; if (aniEnv == nullptr || context == nullptr || abilityInfo == nullptr) { TAG_LOGE(AAFwkTag::CONTEXT, "aniEnv or context or abilityInfo is nullptr"); - return iRet; + return false; } auto hapModuleInfo = context->GetHapModuleInfo(); + if (hapModuleInfo == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null hapModuleInfo"); + return false; + } ani_status status = ANI_OK; - if (abilityInfo && hapModuleInfo) { - auto isExist = [&abilityInfo](const AppExecFwk::ExtensionAbilityInfo &info) { - TAG_LOGD(AAFwkTag::CONTEXT, "%{public}s, %{public}s", info.bundleName.c_str(), info.name.c_str()); - return info.bundleName == abilityInfo->bundleName && info.name == abilityInfo->name; - }; - auto infoIter = - std::find_if(hapModuleInfo->extensionInfos.begin(), hapModuleInfo->extensionInfos.end(), isExist); - if (infoIter == hapModuleInfo->extensionInfos.end()) { - TAG_LOGE(AAFwkTag::CONTEXT, "set extensionAbilityInfo fail"); - return iRet; - } - ani_field extensionAbilityInfoField; - status = aniEnv->Class_FindField(contextClass, "extensionAbilityInfo", &extensionAbilityInfoField); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); - return iRet; - } - ani_object extAbilityInfoObj = AppExecFwk::CommonFunAni::ConvertExtensionInfo(aniEnv, *infoIter); - status = aniEnv->Object_SetField_Ref( - contextObj, extensionAbilityInfoField, reinterpret_cast(extAbilityInfoObj)); - if (status != ANI_OK) { - TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); - return iRet; - } - iRet = true; + auto isExist = [&abilityInfo](const AppExecFwk::ExtensionAbilityInfo &info) { + TAG_LOGD(AAFwkTag::CONTEXT, "%{public}s, %{public}s", info.bundleName.c_str(), info.name.c_str()); + return info.bundleName == abilityInfo->bundleName && info.name == abilityInfo->name; + }; + ani_field extensionAbilityInfoField = nullptr; + status = aniEnv->Class_FindField(contextClass, "extensionAbilityInfo", &extensionAbilityInfoField); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); + return false; + } + auto infoIter = + std::find_if(hapModuleInfo->extensionInfos.begin(), hapModuleInfo->extensionInfos.end(), isExist); + if (infoIter == hapModuleInfo->extensionInfos.end()) { + TAG_LOGE(AAFwkTag::CONTEXT, "set extensionAbilityInfo fail"); + return false; + } + ani_object extAbilityInfoObj = AppExecFwk::CommonFunAni::ConvertExtensionInfo(aniEnv, *infoIter); + status = aniEnv->Object_SetField_Ref( + contextObj, extensionAbilityInfoField, reinterpret_cast(extAbilityInfoObj)); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); + return false; } - return iRet; + return true; } -void CreatEtsExtensionContext(ani_env *aniEnv, ani_class contextClass, ani_object contextObj, +void CreateEtsExtensionContext(ani_env *aniEnv, ani_class contextClass, ani_object &contextObj, std::shared_ptr context, std::shared_ptr abilityInfo) { - TAG_LOGD(AAFwkTag::CONTEXT, "CreatEtsExtensionContext Call"); + TAG_LOGD(AAFwkTag::CONTEXT, "CreateEtsExtensionContext Call"); if (aniEnv == nullptr || context == nullptr) { TAG_LOGE(AAFwkTag::CONTEXT, "aniEnv or context is nullptr"); return; diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index d74769b20b175e496d97098d1ad261ef911b9f3f..07536e93d89f9e2a29e851a4e501b443858cf3eb 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -314,6 +314,7 @@ ohos_shared_library("abilitykit_native") { "${ability_runtime_native_path}/ability/native/data_ability_impl.cpp", "${ability_runtime_native_path}/ability/native/data_uri_utils.cpp", "${ability_runtime_native_path}/ability/native/distributed_ability_runtime/distributed_client.cpp", + "${ability_runtime_native_path}/ability/native/ets_free_install_observer.cpp", "${ability_runtime_native_path}/ability/native/free_install_observer_proxy.cpp", "${ability_runtime_native_path}/ability/native/free_install_observer_stub.cpp", "${ability_runtime_native_path}/ability/native/insight_intent_host_client.cpp", 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 1e8f211e7276e6c3ab4c77c99f115b72ff63b60c..796a0f9fd0892074a4dfe0fb7e1dfdd3d46d3d12 100644 --- a/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp +++ b/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp @@ -224,6 +224,7 @@ void EtsAbilityContext::OnStartAbility( std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) .count()); want.SetParam(AAFwk::Want::PARAM_RESV_START_TIME, startTime); + AddFreeInstallObserver(env, want, call, context); } ErrCode innerErrCode = ERR_OK; if (opt != nullptr) { @@ -241,14 +242,17 @@ void EtsAbilityContext::OnStartAbility( if (innerErrCode != ERR_OK) { aniObject = CreateEtsErrorByNativeErr(env, innerErrCode); } - if ((want.GetFlags() & AAFwk::Want::FLAG_INSTALL_ON_DEMAND) == AAFwk::Want::FLAG_INSTALL_ON_DEMAND) { - // to be done: free install + if ((want.GetFlags() & AAFwk::Want::FLAG_INSTALL_ON_DEMAND) == AAFwk::Want::FLAG_INSTALL_ON_DEMAND && + freeInstallObserver_ != nullptr) { + std::string bundleName = want.GetElement().GetBundleName(); + std::string abilityName = want.GetElement().GetAbilityName(); + std::string startTime = want.GetStringParam(AAFwk::Want::PARAM_RESV_START_TIME); + freeInstallObserver_->OnInstallFinished(bundleName, abilityName, startTime, innerErrCode); } else { AsyncCallback(env, call, aniObject, nullptr); } } -// to be done: free install void EtsAbilityContext::OnStartAbilityForResult( ani_env *env, ani_object aniObj, ani_object wantObj, ani_object startOptionsObj, ani_object callback) { @@ -265,6 +269,12 @@ void EtsAbilityContext::OnStartAbilityForResult( OHOS::AppExecFwk::UnwrapStartOptions(env, startOptionsObj, startOptions); } TAG_LOGE(AAFwkTag::CONTEXT, "displayId:%{public}d", startOptions.GetDisplayID()); + StartAbilityForResultInner(env, startOptions, want, context, startOptionsObj, callback); +} + +void EtsAbilityContext::StartAbilityForResultInner(ani_env *env, const AAFwk::StartOptions &startOptions, + AAFwk::Want &want, std::shared_ptr context, ani_object startOptionsObj, ani_object callback) +{ std::string startTime = std::to_string( std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) .count()); @@ -276,8 +286,12 @@ void EtsAbilityContext::OnStartAbilityForResult( TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); return; } - RuntimeTask task = [etsVm, callbackRef, element = want.GetElement(), flags = want.GetFlags(), startTime]( - int resultCode, const AAFwk::Want &want, bool isInner) { + if ((want.GetFlags() & AAFwk::Want::FLAG_INSTALL_ON_DEMAND) == AAFwk::Want::FLAG_INSTALL_ON_DEMAND) { + want.SetParam(AAFwk::Want::PARAM_RESV_START_TIME, startTime); + AddFreeInstallObserver(env, want, callback, context, true); + } + RuntimeTask task = [etsVm, callbackRef, element = want.GetElement(), flags = want.GetFlags(), startTime, + &observer = freeInstallObserver_](int resultCode, const AAFwk::Want &want, bool isInner) { TAG_LOGD(AAFwkTag::CONTEXT, "start async callback"); ani_status status = ANI_ERROR; ani_env *env = nullptr; @@ -293,6 +307,13 @@ void EtsAbilityContext::OnStartAbilityForResult( isInner = true; resultCode = ERR_INVALID_VALUE; } + bool freeInstallEnable = + (flags & AAFwk::Want::FLAG_INSTALL_ON_DEMAND) == AAFwk::Want::FLAG_INSTALL_ON_DEMAND && observer != nullptr; + if (freeInstallEnable) { + isInner ? observer->OnInstallFinished(bundleName, abilityName, startTime, resultCode) + : observer->OnInstallFinished(bundleName, abilityName, startTime, abilityResult); + return; + } auto errCode = isInner ? resultCode : 0; AsyncCallback(env, reinterpret_cast(callbackRef), OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, errCode), abilityResult); @@ -383,6 +404,45 @@ void EtsAbilityContext::OnReportDrawnCompleted(ani_env *env, ani_object aniObj, AsyncCallback(env, callback, aniObject, nullptr); } +void EtsAbilityContext::AddFreeInstallObserver(ani_env *env, const AAFwk::Want &want, ani_object callback, + const std::shared_ptr &context, bool isAbilityResult, bool isOpenLink) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "AddFreeInstallObserver"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null env"); + return; + } + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null context"); + return; + } + if (freeInstallObserver_ == nullptr) { + ani_vm *etsVm = nullptr; + ani_status status = ANI_ERROR; + if ((status = env->GetVM(&etsVm)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); + } + if (etsVm == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null etsVm"); + return; + } + freeInstallObserver_ = new (std::nothrow) EtsFreeInstallObserver(etsVm); + if (context->AddFreeInstallObserver(freeInstallObserver_) != ERR_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "addFreeInstallObserver error"); + return; + } + } + std::string startTime = want.GetStringParam(AAFwk::Want::PARAM_RESV_START_TIME); + if (isOpenLink) { + std::string url = want.GetUriString(); + freeInstallObserver_->AddEtsObserverObject(env, startTime, url, callback, isAbilityResult); + return; + } + std::string bundleName = want.GetElement().GetBundleName(); + std::string abilityName = want.GetElement().GetAbilityName(); + freeInstallObserver_->AddEtsObserverObject(env, bundleName, abilityName, startTime, callback, isAbilityResult); +} + namespace { bool BindNativeMethods(ani_env *env, ani_class &cls) { diff --git a/frameworks/native/ability/native/ets_free_install_observer.cpp b/frameworks/native/ability/native/ets_free_install_observer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8956e4432aad5fd99474bf622a7dc70d68083c3f --- /dev/null +++ b/frameworks/native/ability/native/ets_free_install_observer.cpp @@ -0,0 +1,275 @@ +/* + * 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_free_install_observer.h" + +#include "ability_business_error.h" +#include "ani_common_ability_result.h" +#include "ani_common_configuration.h" +#include "ani_common_start_options.h" +#include "ani_common_util.h" +#include "ani_common_want.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" + +namespace OHOS { +namespace AbilityRuntime { +EtsFreeInstallObserver::EtsFreeInstallObserver(ani_vm *etsVm) : etsVm_(etsVm) {} + +EtsFreeInstallObserver::~EtsFreeInstallObserver() +{ + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + ani_option interopEnabled { "--interop=disable", nullptr }; + ani_options aniArgs { 1, &interopEnabled }; + if ((etsVm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env)) != ANI_OK) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "status : %{public}d", status); + } + if (env == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null env"); + return; + } + for (auto it = etsObserverObjectList_.begin(); it != etsObserverObjectList_.end();) { + env->GlobalReference_Delete(it->callback); + } + if ((status = etsVm_->DetachCurrentThread()) != ANI_OK) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "status: %{public}d", status); + } +} + +void EtsFreeInstallObserver::OnInstallFinished( + const std::string &bundleName, const std::string &abilityName, const std::string &startTime, const int &resultCode) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "OnInstallFinished"); + HandleOnInstallFinished(bundleName, abilityName, startTime, resultCode); +} + +void EtsFreeInstallObserver::OnInstallFinished(const std::string &bundleName, const std::string &abilityName, + const std::string &startTime, ani_object abilityResult) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "OnInstallFinished"); + std::vector callbacks; + { + std::unique_lock lock(etsObserverObjectListLock_); + for (auto it = etsObserverObjectList_.begin(); it != etsObserverObjectList_.end();) { + if ((it->bundleName != bundleName) || (it->abilityName != abilityName) || (it->startTime != startTime)) { + it++; + continue; + } + if (it->callback == nullptr) { + it++; + continue; + } + if (!it->isAbilityResult) { + it++; + continue; + } + callbacks.emplace_back(it->callback); + it = etsObserverObjectList_.erase(it); + TAG_LOGD(AAFwkTag::FREE_INSTALL, "etsObserverObjectList_ size:%{public}zu", etsObserverObjectList_.size()); + } + } + + for (auto callback : callbacks) { + CallCallback(callback, abilityResult); + FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str())); + } +} + +void EtsFreeInstallObserver::OnInstallFinishedByUrl( + const std::string &startTime, const std::string &url, const int &resultCode) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "OnInstallFinishedByUrl"); + HandleOnInstallFinishedByUrl(startTime, url, resultCode); +} + +void EtsFreeInstallObserver::HandleOnInstallFinished( + const std::string &bundleName, const std::string &abilityName, const std::string &startTime, const int &resultCode) +{ + std::vector callbacks; + { + std::unique_lock lock(etsObserverObjectListLock_); + for (auto it = etsObserverObjectList_.begin(); it != etsObserverObjectList_.end();) { + if ((it->bundleName != bundleName) || (it->abilityName != abilityName) || (it->startTime != startTime)) { + it++; + continue; + } + if (it->callback == nullptr) { + it++; + continue; + } + callbacks.emplace_back(it->callback); + it = etsObserverObjectList_.erase(it); + } + } + + for (auto callback : callbacks) { + CallCallback(callback, resultCode); + FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str())); + } +} + +void EtsFreeInstallObserver::HandleOnInstallFinishedByUrl( + const std::string &startTime, const std::string &url, const int &resultCode) +{ + std::vector callbacks; + { + std::unique_lock lock(etsObserverObjectListLock_); + for (auto it = etsObserverObjectList_.begin(); it != etsObserverObjectList_.end();) { + if ((it->startTime != startTime) || (it->url != url)) { + it++; + continue; + } + if (it->callback == nullptr) { + it++; + continue; + } + callbacks.emplace_back(it->callback); + it = etsObserverObjectList_.erase(it); + } + } + + for (auto callback : callbacks) { + CallCallback(callback, resultCode); + FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str())); + } +} + +void EtsFreeInstallObserver::CallCallback(ani_object callback, int32_t resultCode) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "CallCallback"); + if (callback == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null callback"); + return; + } + if (etsVm_ == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null etsVm"); + return; + } + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + ani_option interopEnabled { "--interop=disable", nullptr }; + ani_options aniArgs { 1, &interopEnabled }; + if ((etsVm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env)) != ANI_OK) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "status : %{public}d", status); + } + if (env == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null env"); + return; + } + ani_object aniObject = CreateEtsError(env, AbilityErrorCode::ERROR_OK); + if (resultCode != ERR_OK) { + aniObject = CreateEtsErrorByNativeErr(env, resultCode); + } + AppExecFwk::AsyncCallback(env, callback, aniObject, nullptr); + env->GlobalReference_Delete(callback); + if ((status = etsVm_->DetachCurrentThread()) != ANI_OK) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "status: %{public}d", status); + } +} + +void EtsFreeInstallObserver::CallCallback(ani_object callback, ani_object abilityResult) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "CallCallback"); + if (abilityResult == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null abilityResult"); + return; + } + if (callback == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null callback"); + return; + } + if (etsVm_ == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null etsVm"); + return; + } + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + ani_option interopEnabled { "--interop=disable", nullptr }; + ani_options aniArgs { 1, &interopEnabled }; + if ((etsVm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env)) != ANI_OK) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "status : %{public}d", status); + } + if (env == nullptr) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "null env"); + return; + } + ani_object aniObject = CreateEtsError(env, AbilityErrorCode::ERROR_OK); + AppExecFwk::AsyncCallback(env, callback, aniObject, abilityResult); + env->GlobalReference_Delete(callback); + if ((status = etsVm_->DetachCurrentThread()) != ANI_OK) { + TAG_LOGE(AAFwkTag::FREE_INSTALL, "status: %{public}d", status); + } +} + +void EtsFreeInstallObserver::AddEtsObserverObject(ani_env *env, const std::string &bundleName, + const std::string &abilityName, const std::string &startTime, ani_object callback, bool isAbilityResult) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "AddEtsObserverObject"); + { + std::unique_lock lock(etsObserverObjectListLock_); + for (auto it = etsObserverObjectList_.begin(); it != etsObserverObjectList_.end(); ++it) { + if (it->bundleName == bundleName && it->abilityName == abilityName && it->startTime == startTime) { + TAG_LOGW(AAFwkTag::FREE_INSTALL, "The EtsFreeInstallObserverObject has been added"); + return; + } + } + } + StartAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str())); + EtsFreeInstallObserverObject object; + object.bundleName = bundleName; + object.abilityName = abilityName; + object.startTime = startTime; + object.isAbilityResult = isAbilityResult; + AddEtsObserverCommon(env, object, callback); +} + +void EtsFreeInstallObserver::AddEtsObserverObject( + ani_env *env, const std::string &startTime, const std::string &url, ani_object callback, bool isAbilityResult) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "AddEtsObserverObject"); + { + std::unique_lock lock(etsObserverObjectListLock_); + for (auto it = etsObserverObjectList_.begin(); it != etsObserverObjectList_.end(); ++it) { + if (it->startTime == startTime && it->url == url) { + TAG_LOGW(AAFwkTag::FREE_INSTALL, "add etsObject"); + return; + } + } + } + StartAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str())); + EtsFreeInstallObserverObject object; + object.url = url; + object.startTime = startTime; + object.isAbilityResult = isAbilityResult; + AddEtsObserverCommon(env, object, callback); +} + +void EtsFreeInstallObserver::AddEtsObserverCommon( + ani_env *env, EtsFreeInstallObserverObject &object, ani_object callback) +{ + TAG_LOGD(AAFwkTag::FREE_INSTALL, "AddEtsObserverCommon"); + std::unique_lock lock(etsObserverObjectListLock_); + ani_ref global = nullptr; + ani_status status = ANI_ERROR; + if ((status = env->GlobalReference_Create(callback, &global)) != ANI_OK) { + TAG_LOGE(AAFwkTag::UI_EXT, "status : %{public}d", status); + return; + } + object.callback = reinterpret_cast(global); + etsObserverObjectList_.emplace_back(object); +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/native/ability/ability_runtime/ets_extension_context.h b/interfaces/kits/native/ability/ability_runtime/ets_extension_context.h index 12c99e56649b81514866e0d1a59a8d4f1fe8e590..1a2d6155dd078956b9a367ff53c7416768eb7a16 100644 --- a/interfaces/kits/native/ability/ability_runtime/ets_extension_context.h +++ b/interfaces/kits/native/ability/ability_runtime/ets_extension_context.h @@ -13,17 +13,16 @@ * limitations under the License. */ -#ifndef OHOS_ABILITY_RUNTIME_STS_EXTENSION_CONTEXT_H -#define OHOS_ABILITY_RUNTIME_STS_EXTENSION_CONTEXT_H - -#include "extension_context.h" +#ifndef OHOS_ABILITY_RUNTIME_ETS_EXTENSION_CONTEXT_H +#define OHOS_ABILITY_RUNTIME_ETS_EXTENSION_CONTEXT_H + #include "ani.h" +#include "extension_context.h" namespace OHOS { namespace AbilityRuntime { -void CreatEtsExtensionContext(ani_env* aniEnv, ani_class contextClass, ani_object contextObj, - std::shared_ptr context, - std::shared_ptr abilityInfo); +void CreateEtsExtensionContext(ani_env *aniEnv, ani_class contextClass, ani_object &contextObj, + std::shared_ptr context, std::shared_ptr abilityInfo); } // namespace AbilityRuntime } // namespace OHOS -#endif // OHOS_ABILITY_RUNTIME_STS_EXTENSION_CONTEXT_H \ No newline at end of file +#endif // OHOS_ABILITY_RUNTIME_ETS_EXTENSION_CONTEXT_H \ No newline at end of file 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 6185058833858447880719f9e8f0f76f8aa8ba8f..532b43be490702a074232d91fac95fae9793ee70 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 @@ -18,6 +18,7 @@ #include "ability_context.h" #include "configuration.h" +#include "ets_free_install_observer.h" #include "ets_runtime.h" #include "ohos_application.h" @@ -53,9 +54,14 @@ private: void OnTerminateSelf(ani_env *env, ani_object aniObj, ani_object callback); void OnTerminateSelfWithResult(ani_env *env, ani_object aniObj, ani_object abilityResult, ani_object callback); void OnReportDrawnCompleted(ani_env *env, ani_object aniObj, ani_object call); + void AddFreeInstallObserver(ani_env *env, const AAFwk::Want &want, ani_object callback, + const std::shared_ptr &context, bool isAbilityResult = false, bool isOpenLink = false); + void StartAbilityForResultInner(ani_env *env, const AAFwk::StartOptions &startOptions, AAFwk::Want &want, + std::shared_ptr context, ani_object startOptionsObj, ani_object callback); int32_t GenerateRequestCode(); static std::mutex requestCodeMutex_; + sptr freeInstallObserver_ = nullptr; }; ani_object CreateEtsAbilityContext( diff --git a/interfaces/kits/native/ability/native/ets_free_install_observer.h b/interfaces/kits/native/ability/native/ets_free_install_observer.h new file mode 100644 index 0000000000000000000000000000000000000000..5a02b078022294e5273d8d1bd9888d84441a6d61 --- /dev/null +++ b/interfaces/kits/native/ability/native/ets_free_install_observer.h @@ -0,0 +1,68 @@ +/* + * 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_FREE_INSTALL_OBSERVER_H +#define OHOS_ABILITY_RUNTIME_ETS_FREE_INSTALL_OBSERVER_H + +#include +#include +#include + +#include "ets_error_utils.h" +#include "ets_runtime.h" +#include "free_install_observer_stub.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AbilityRuntime { +struct EtsFreeInstallObserverObject { + std::string bundleName; + std::string abilityName; + std::string startTime; + std::string url; + ani_object callback = nullptr; + bool isAbilityResult = false; +}; + +class EtsFreeInstallObserver : public FreeInstallObserverStub { +public: + explicit EtsFreeInstallObserver(ani_vm *etsVm); + virtual ~EtsFreeInstallObserver(); + + void OnInstallFinished(const std::string &bundleName, const std::string &abilityName, const std::string &startTime, + const int &resultCode) override; + void OnInstallFinished(const std::string &bundleName, const std::string &abilityName, const std::string &startTime, + ani_object abilityResult); + void OnInstallFinishedByUrl(const std::string &startTime, const std::string &url, const int &resultCode) override; + void AddEtsObserverObject(ani_env *env, const std::string &bundleName, const std::string &abilityName, + const std::string &startTime, ani_object callback, bool isAbilityResult); + void AddEtsObserverObject( + ani_env *env, const std::string &startTime, const std::string &url, ani_object callback, bool isAbilityResult); + +private: + void CallCallback(ani_object callback, int32_t resultCode); + void CallCallback(ani_object callback, ani_object abilityResult); + void HandleOnInstallFinished(const std::string &bundleName, const std::string &abilityName, + const std::string &startTime, const int &resultCode); + void HandleOnInstallFinishedByUrl(const std::string &startTime, const std::string &url, const int &resultCode); + void AddEtsObserverCommon(ani_env *env, EtsFreeInstallObserverObject &object, ani_object callback); + + ani_vm *etsVm_; + std::mutex etsObserverObjectListLock_; + std::vector etsObserverObjectList_; +}; +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_ETS_FREE_INSTALL_OBSERVER_H \ No newline at end of file