From 843b85040aa1c8ed7c76414e26231ffc9f67f87d Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Mon, 9 Jun 2025 23:36:45 +0800 Subject: [PATCH 1/2] add ets uiabilitycontext Signed-off-by: zhangzezhong --- .../ets/ets/@ohos.app.ability.UIAbility.ets | 2 + frameworks/ets/ets/BUILD.gn | 18 + .../ets/ets/application/UIAbilityContext.ets | 222 ++++++++ frameworks/native/ability/native/BUILD.gn | 5 + .../ability_runtime/ets_ability_context.cpp | 473 ++++++++++++++++++ .../native/ability_runtime/ets_ui_ability.cpp | 30 ++ .../ability_runtime/ets_ability_context.h | 65 +++ .../native/ability_runtime/ets_ui_ability.h | 1 + 8 files changed, 816 insertions(+) create mode 100644 frameworks/ets/ets/application/UIAbilityContext.ets create mode 100644 frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp create mode 100644 interfaces/kits/native/ability/native/ability_runtime/ets_ability_context.h diff --git a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets index f53af8d5f3a..63fd48d05b8 100644 --- a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets +++ b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets @@ -14,6 +14,7 @@ */ 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 { AbilityUtils } from './utils/AbilityUtils'; @@ -43,6 +44,7 @@ export default class UIAbility { return false; } + context: UIAbilityContext = new UIAbilityContext(); launchWant: Want = new Want(); lastRequestWant: Want = new Want(); diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index 8326af80f8c..fe486b15d54 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -226,6 +226,23 @@ ohos_prebuilt_etc("ability_runtime_ui_ability_abc_etc") { deps = [ ":ability_runtime_ui_ability_abc" ] } +generate_static_abc("ability_runtime_ui_ability_context_abc") { + base_url = "./" + files = [ "./application/UIAbilityContext.ets" ] + + is_boot_abc = "True" + device_dst_file = + "/system/framework/ability_runtime_ui_ability_context_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_ui_ability_context_abc_etc") { + source = "$target_out_dir/ability_runtime_ui_ability_context_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_ui_ability_context_abc" ] +} + group("ets_packages") { deps = [ ":ability_runtime_ability_result_abc_etc", @@ -241,5 +258,6 @@ group("ets_packages") { ":ability_runtime_want_constant_abc_etc", ":ability_runtime_extension_context_abc_etc", ":ability_runtime_ui_ability_abc_etc", + ":ability_runtime_ui_ability_context_abc_etc", ] } diff --git a/frameworks/ets/ets/application/UIAbilityContext.ets b/frameworks/ets/ets/application/UIAbilityContext.ets new file mode 100644 index 00000000000..4c515cb3f6a --- /dev/null +++ b/frameworks/ets/ets/application/UIAbilityContext.ets @@ -0,0 +1,222 @@ +/* + * 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 { AbilityInfo } from 'bundleManager.AbilityInfo'; +import Want from '@ohos.app.ability.Want'; +import StartOptions from '@ohos.app.ability.StartOptions'; +import { BusinessError, AsyncCallback } from '@ohos.base'; +import { AbilityResult } from 'ability.abilityResult'; +import { Configuration } from '@ohos.app.ability.Configuration'; +import Context from 'application.Context'; +import window from '@ohos.window'; + +export class AsyncCallbackWrapper { + myFun_: AsyncCallback = (err: BusinessError, data: T) => { + } + + constructor(myFun: AsyncCallback) { + console.log("AsyncCallbackWrapper"); + this.myFun_ = myFun; + } + + invoke(err: BusinessError, data: T): void { + this.myFun_(err, data); + } +} + +export default class UIAbilityContext extends Context { + static { + loadLibrary("context_ani"); + } + + config: Configuration; + abilityInfo: AbilityInfo; + windowStage: window.WindowStage; + + native constructor(); + + constructor(config: Configuration, abilityInfo: AbilityInfo, windowStage: window.WindowStage) { + super(); + this.config = config; + this.abilityInfo = abilityInfo; + this.windowStage = windowStage; + } + + private native nativeStartAbilitySync(want: Want, callback: AsyncCallbackWrapper): void; + + private native nativeStartAbilitySync(want: Want, options: StartOptions, callback: AsyncCallbackWrapper): void; + + private native nativeStartAbilityForResult(want: Want, callback: AsyncCallbackWrapper): void; + + private native nativeStartAbilityForResult(want: Want, startOptions: StartOptions, + callback: AsyncCallbackWrapper): void; + + private native nativeTerminateSelfSync(callback: AsyncCallbackWrapper): void; + + private native nativeTerminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallbackWrapper): void; + + private native nativeReportDrawnCompletedSync(callback: AsyncCallbackWrapper): void; + + startAbility(want: Want, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeStartAbilitySync(want, myCall); + }); + } + + startAbility(want: Want, options: StartOptions, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeStartAbilitySync(want, options, myCall); + }); + } + + startAbility(want: Want): Promise { + let p: Promise = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError) => { + if (err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartAbilitySync(want, myCall); + }); + }); + return p; + } + + startAbility(want: Want, options: StartOptions): Promise { + let p = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError) => { + if (err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartAbilitySync(want, options, myCall); + }); + }); + return p; + } + + startAbilityForResult(want: Want, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeStartAbilityForResult(want, myCall); + }); + } + + startAbilityForResult(want: Want, startOptions: StartOptions, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeStartAbilityForResult(want, startOptions, myCall); + }); + } + + startAbilityForResult(want: Want): Promise { + let p = new Promise((resolve: (data: AbilityResult) => void, + reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError, data: AbilityResult) => { + if (err.code == 0) { + resolve(data); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartAbilityForResult(want, myCall); + }); + }); + return p; + } + + startAbilityForResult(want: Want, startOptions: StartOptions): Promise { + let p = new Promise((resolve: (data: AbilityResult) => void, + reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError, data: AbilityResult) => { + if (err.code == 0) { + resolve(data); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartAbilityForResult(want, startOptions, myCall); + }); + }); + return p; + } + + terminateSelf(callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeTerminateSelfSync(myCall); + }); + } + + terminateSelf(): Promise { + let p = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError) => { + if (err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeTerminateSelfSync(myCall); + }); + }); + return p; + } + + terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeTerminateSelfWithResult(parameter, myCall); + }); + } + + terminateSelfWithResult(parameter: AbilityResult): Promise { + let p = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError) => { + if (err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeTerminateSelfWithResult(parameter, myCall); + }); + }); + return p; + } + + reportDrawnCompleted(callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeReportDrawnCompletedSync(myCall); + }); + } +} diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index 2dc9d73d532..0981fde5253 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -287,6 +287,7 @@ ohos_shared_library("abilitykit_native") { branch_protector_ret = "pac_ret" include_dirs = [ + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", "${ability_runtime_path}/utils/global/time/include", "${ability_runtime_path}/interfaces/kits/native/ability/native/ui_service_extension_ability/connection", ] @@ -302,6 +303,7 @@ ohos_shared_library("abilitykit_native") { "${ability_runtime_native_path}/ability/native/ability_loader.cpp", "${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/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", @@ -359,6 +361,7 @@ ohos_shared_library("abilitykit_native") { "${ability_runtime_native_path}/appkit:app_context_utils", "${ability_runtime_native_path}/appkit:appkit_delegator", "${ability_runtime_native_path}/appkit:appkit_manager_helper", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", "${ability_runtime_path}/utils/global/freeze:freeze_util", "${ability_runtime_services_path}/common:app_util", "${ability_runtime_services_path}/common:event_report", @@ -374,6 +377,7 @@ ohos_shared_library("abilitykit_native") { "access_token:libtoken_callback_sdk", "access_token:libtokenid_sdk", "bundle_framework:appexecfwk_base", + "bundle_framework:bms_ani_common", "c_utils:utils", "common_event_service:cesfwk_innerkits", "eventhandler:libeventhandler", @@ -387,6 +391,7 @@ ohos_shared_library("abilitykit_native") { "json:nlohmann_json_static", "napi:ace_napi", "resource_management:global_resmgr", + "runtime_core:ani", "samgr:samgr_proxy", "window_manager:windowstage_kit", ] diff --git a/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp b/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp new file mode 100644 index 00000000000..1e8f211e727 --- /dev/null +++ b/frameworks/native/ability/native/ability_runtime/ets_ability_context.cpp @@ -0,0 +1,473 @@ +/* + * 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 "ability_runtime/ets_ability_context.h" + +#include "ani_common_ability_result.h" +#include "ani_common_configuration.h" +#include "ani_common_start_options.h" +#include "ani_common_want.h" +#include "app_utils.h" +#include "common_fun_ani.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "ets_context_utils.h" +#include "ets_error_utils.h" +#include "want.h" + +namespace OHOS { +namespace AbilityRuntime { +std::mutex EtsAbilityContext::requestCodeMutex_; +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;"; +} // namespace + +std::shared_ptr EtsAbilityContext::GetAbilityContext(ani_env *env, ani_object aniObj) +{ + if (env == nullptr || aniObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null env or aniObj"); + return nullptr; + } + ani_long nativeContextLong; + ani_status status = env->Object_GetFieldByName_Long(aniObj, "nativeContext", &nativeContextLong); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Object_GetFieldByName_Long status: %{public}d", status); + return nullptr; + } + auto weakContext = reinterpret_cast *>(nativeContextLong); + return weakContext != nullptr ? weakContext->lock() : nullptr; +} + +ani_object EtsAbilityContext::SetAbilityContext(ani_env *env, const std::shared_ptr &context) +{ + if (env == nullptr || context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null env or context"); + return nullptr; + } + ani_class cls = nullptr; + ani_object contextObj = nullptr; + ani_method method = nullptr; + ani_status status = env->FindClass(UI_ABILITY_CONTEXT_CLASS_NAME, &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass status: %{public}d", status); + return nullptr; + } + if ((status = env->Class_FindMethod(cls, "", ":V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Class_FindMethod status: %{public}d", status); + return nullptr; + } + if ((status = env->Object_New(cls, method, &contextObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Object_New status: %{public}d", status); + return nullptr; + } + + auto workContext = new (std::nothrow) std::weak_ptr(context); + if (workContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "workContext nullptr"); + return nullptr; + } + ani_long nativeContextLong = (ani_long)workContext; + if ((status = env->Object_SetFieldByName_Long(contextObj, "nativeContext", nativeContextLong)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Object_SetFieldByName_Long status: %{public}d", status); + delete workContext; + workContext = nullptr; + return nullptr; + } + return contextObj; +} + +// to be done: free install +void EtsAbilityContext::StartAbility(ani_env *env, ani_object aniObj, ani_object wantObj, ani_object call) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "StartAbility called"); + GetInstance().OnStartAbility(env, aniObj, wantObj, nullptr, call); +} + +void EtsAbilityContext::StartAbilityWithOptions( + ani_env *env, ani_object aniObj, ani_object wantObj, ani_object opt, ani_object call) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::CONTEXT, "StartAbilityWithOptions called"); + GetInstance().OnStartAbility(env, aniObj, wantObj, opt, call); +} + +// to be done: free install +void EtsAbilityContext::StartAbilityForResult(ani_env *env, ani_object aniObj, ani_object wantObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "StartAbilityForResult called"); + GetInstance().OnStartAbilityForResult(env, aniObj, wantObj, nullptr, callback); +} + +// to be done: free install +void EtsAbilityContext::StartAbilityForResultWithOptions( + ani_env *env, ani_object aniObj, ani_object wantObj, ani_object startOptionsObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "StartAbilityForResultWithOptions called"); + GetInstance().OnStartAbilityForResult(env, aniObj, wantObj, startOptionsObj, callback); +} + +void EtsAbilityContext::TerminateSelf(ani_env *env, ani_object aniObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "TerminateSelf called"); + GetInstance().OnTerminateSelf(env, aniObj, callback); +} + +void EtsAbilityContext::TerminateSelfWithResult( + ani_env *env, ani_object aniObj, ani_object abilityResult, ani_object callback) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "TerminateSelfWithResult called"); + GetInstance().OnTerminateSelfWithResult(env, aniObj, abilityResult, callback); +} + +void EtsAbilityContext::ReportDrawnCompleted(ani_env *env, ani_object aniObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "ReportDrawnCompleted called"); + GetInstance().OnReportDrawnCompleted(env, aniObj, callback); +} + +int32_t EtsAbilityContext::GenerateRequestCode() +{ + static int32_t curRequestCode_ = 0; + std::lock_guard lock(requestCodeMutex_); + curRequestCode_ = (curRequestCode_ == INT_MAX) ? 0 : (curRequestCode_ + 1); + return curRequestCode_; +} + +void EtsAbilityContext::InheritWindowMode(ani_env *env, ani_object aniObj, AAFwk::Want &want) +{ + TAG_LOGD(AAFwkTag::CONTEXT, "InheritWindowMode"); +#ifdef SUPPORT_SCREEN + // only split mode need inherit + auto context = GetAbilityContext(env, aniObj); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "context null"); + return; + } + auto windowMode = context->GetCurrentWindowMode(); + if (AAFwk::AppUtils::GetInstance().IsInheritWindowSplitScreenMode() && + (windowMode == AAFwk::AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_PRIMARY || + windowMode == AAFwk::AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_SECONDARY)) { + want.SetParam(AAFwk::Want::PARAM_RESV_WINDOW_MODE, windowMode); + } + TAG_LOGD(AAFwkTag::CONTEXT, "window mode is %{public}d", windowMode); +#endif +} + +bool EtsAbilityContext::AsyncCallback(ani_env *env, ani_object call, ani_object error, ani_object result) +{ + if (env == nullptr || call == nullptr) { + TAG_LOGE(AAFwkTag::JSNAPI, "env or call is nullptr"); + return false; + } + ani_class clsCall = nullptr; + ani_status status = env->FindClass(CLASSNAME_ASYNC_CALLBACK_WRAPPER, &clsCall); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass status: %{public}d", status); + return false; + } + ani_method method = nullptr; + if ((status = env->Class_FindMethod(clsCall, "invoke", "L@ohos/base/BusinessError;Lstd/core/Object;:V", &method)) != + ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Class_FindMethod status: %{public}d", status); + return false; + } + if (error == nullptr) { + ani_ref nullRef = nullptr; + env->GetNull(&nullRef); + error = reinterpret_cast(nullRef); + } + if (result == nullptr) { + ani_ref undefinedRef = nullptr; + env->GetUndefined(&undefinedRef); + result = reinterpret_cast(undefinedRef); + } + if ((status = env->Object_CallMethod_Void(call, method, error, result)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); + return false; + } + return true; +} + +void EtsAbilityContext::OnStartAbility( + ani_env *env, ani_object aniObj, ani_object wantObj, ani_object opt, ani_object call) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + AAFwk::Want want; + if (!OHOS::AppExecFwk::UnwrapWant(env, wantObj, want)) { + ThrowEtsInvalidParamError(env, "Parse param want failed, must be a Want"); + return; + } + InheritWindowMode(env, aniObj, want); + auto context = EtsAbilityContext::GetAbilityContext(env, aniObj); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null context"); + ThrowEtsInvalidParamError(env, "null context"); + return; + } + if ((want.GetFlags() & AAFwk::Want::FLAG_INSTALL_ON_DEMAND) == AAFwk::Want::FLAG_INSTALL_ON_DEMAND) { + std::string startTime = std::to_string( + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count()); + want.SetParam(AAFwk::Want::PARAM_RESV_START_TIME, startTime); + } + ErrCode innerErrCode = ERR_OK; + if (opt != nullptr) { + AAFwk::StartOptions startOptions; + if (!OHOS::AppExecFwk::UnwrapStartOptions(env, opt, startOptions)) { + ThrowEtsInvalidParamError(env, "Parse param startOptions failed, startOptions must be StartOptions."); + TAG_LOGE(AAFwkTag::CONTEXT, "invalid options"); + return; + } + innerErrCode = context->StartAbility(want, startOptions, -1); + } else { + innerErrCode = context->StartAbility(want, -1); + } + ani_object aniObject = CreateEtsError(env, AbilityErrorCode::ERROR_OK); + 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 + } 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) +{ + auto context = EtsAbilityContext::GetAbilityContext(env, aniObj); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "GetAbilityContext is nullptr"); + ThrowEtsErrorByNativeErr(env, static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); + return; + } + AAFwk::Want want; + OHOS::AppExecFwk::UnwrapWant(env, wantObj, want); + AAFwk::StartOptions startOptions; + if (startOptionsObj) { + OHOS::AppExecFwk::UnwrapStartOptions(env, startOptionsObj, startOptions); + } + TAG_LOGE(AAFwkTag::CONTEXT, "displayId:%{public}d", startOptions.GetDisplayID()); + std::string startTime = std::to_string( + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count()); + ani_ref callbackRef = nullptr; + env->GlobalReference_Create(callback, &callbackRef); + ani_vm *etsVm = nullptr; + ani_status status = ANI_ERROR; + if ((status = env->GetVM(&etsVm)) != ANI_OK) { + 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) { + TAG_LOGD(AAFwkTag::CONTEXT, "start async callback"); + ani_status status = ANI_ERROR; + ani_env *env = nullptr; + if ((status = etsVm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "status: %{public}d", status); + return; + } + std::string bundleName = element.GetBundleName(); + std::string abilityName = element.GetAbilityName(); + ani_object abilityResult = AppExecFwk::WrapAbilityResult(env, resultCode, want); + if (abilityResult == nullptr) { + TAG_LOGW(AAFwkTag::CONTEXT, "null abilityResult"); + isInner = true; + resultCode = ERR_INVALID_VALUE; + } + auto errCode = isInner ? resultCode : 0; + AsyncCallback(env, reinterpret_cast(callbackRef), + OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, errCode), abilityResult); + }; + auto requestCode = GenerateRequestCode(); + (startOptionsObj == nullptr) ? context->StartAbilityForResult(want, requestCode, std::move(task)) + : context->StartAbilityForResult(want, startOptions, requestCode, std::move(task)); + return; +} + +void EtsAbilityContext::OnTerminateSelf(ani_env *env, ani_object aniObj, ani_object callback) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null env or aniObj"); + ani_object aniObject = CreateEtsInvalidParamError(env, "env null"); + AsyncCallback(env, callback, aniObject, nullptr); + return; + } + ani_object aniObject = nullptr; + auto context = EtsAbilityContext::GetAbilityContext(env, aniObj); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null context"); + aniObject = CreateEtsInvalidParamError(env, "context null"); + AsyncCallback(env, callback, aniObject, nullptr); + return; + } + ErrCode ret = context->TerminateSelf(); + if (ret == static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT) || ret == ERR_OK) { + aniObject = CreateEtsError(env, static_cast(ret)); + } else { + aniObject = CreateEtsErrorByNativeErr(env, static_cast(ret)); + } + AsyncCallback(env, callback, aniObject, nullptr); +} + +void EtsAbilityContext::OnTerminateSelfWithResult( + ani_env *env, ani_object aniObj, ani_object abilityResult, ani_object callback) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null env"); + ani_object aniObject = CreateEtsInvalidParamError(env, "env null"); + AsyncCallback(env, callback, aniObject, nullptr); + return; + } + ani_object aniObject = nullptr; + auto context = EtsAbilityContext::GetAbilityContext(env, aniObj); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "GetAbilityContext is nullptr"); + aniObject = CreateEtsInvalidParamError(env, "context null"); + AsyncCallback(env, callback, aniObject, nullptr); + return; + } + AAFwk::Want want; + int resultCode = 0; + OHOS::AppExecFwk::UnWrapAbilityResult(env, abilityResult, resultCode, want); + context->SetTerminating(true); + ErrCode ret = context->TerminateAbilityWithResult(want, resultCode); + if (ret == static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT) || ret == ERR_OK) { + aniObject = CreateEtsError(env, static_cast(ret)); + } else { + aniObject = CreateEtsErrorByNativeErr(env, static_cast(ret)); + } + AsyncCallback(env, callback, aniObject, nullptr); +} + +void EtsAbilityContext::OnReportDrawnCompleted(ani_env *env, ani_object aniObj, ani_object callback) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null env"); + ani_object aniObject = CreateEtsInvalidParamError(env, "env null"); + AsyncCallback(env, callback, aniObject, nullptr); + return; + } + ani_object aniObject = nullptr; + auto context = GetAbilityContext(env, aniObj); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "context null"); + aniObject = CreateEtsInvalidParamError(env, "context null"); + AsyncCallback(env, callback, aniObject, nullptr); + return; + } + ErrCode ret = context->ReportDrawnCompleted(); + if (ret == ERR_OK) { + aniObject = CreateEtsError(env, static_cast(ret)); + } else { + aniObject = CreateEtsErrorByNativeErr(env, static_cast(ret)); + } + AsyncCallback(env, callback, aniObject, nullptr); +} + +namespace { +bool BindNativeMethods(ani_env *env, ani_class &cls) +{ + ani_status status = env->FindClass(UI_ABILITY_CONTEXT_CLASS_NAME, &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "FindClass status: %{public}d", status); + return false; + } + std::call_once(g_bindNativeMethodsFlag, [&status, env, cls]() { + std::array functions = { + ani_native_function { "nativeStartAbilitySync", + "L@ohos/app/ability/Want/Want;Lapplication/UIAbilityContext/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityContext::StartAbility) }, + ani_native_function { "nativeStartAbilitySync", + "L@ohos/app/ability/Want/Want;L@ohos/app/ability/StartOptions/StartOptions;Lapplication/" + "UIAbilityContext/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityContext::StartAbilityWithOptions) }, + ani_native_function { "nativeStartAbilityForResult", + "L@ohos/app/ability/Want/Want;Lapplication/UIAbilityContext/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityContext::StartAbilityForResult) }, + ani_native_function { "nativeStartAbilityForResult", + "L@ohos/app/ability/Want/Want;L@ohos/app/ability/StartOptions/StartOptions;Lapplication/" + "UIAbilityContext/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityContext::StartAbilityForResultWithOptions) }, + ani_native_function { "nativeTerminateSelfSync", "Lapplication/UIAbilityContext/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityContext::TerminateSelf) }, + ani_native_function { "nativeTerminateSelfWithResult", + "Lability/abilityResult/AbilityResult;Lapplication/UIAbilityContext/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityContext::TerminateSelfWithResult) }, + ani_native_function { "nativeReportDrawnCompletedSync", + "Lapplication/UIAbilityContext/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityContext::ReportDrawnCompleted) }, + }; + status = env->Class_BindNativeMethods(cls, functions.data(), functions.size()); + }); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Class_BindNativeMethods status: %{public}d", status); + return false; + } + return true; +} +} // namespace + +ani_object CreateEtsAbilityContext( + ani_env *env, const std::shared_ptr &context, const std::shared_ptr &application) +{ + if (env == nullptr || context == nullptr || application == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null env or context or application"); + return nullptr; + } + ani_class cls = nullptr; + if (!BindNativeMethods(env, cls)) { + TAG_LOGE(AAFwkTag::CONTEXT, "BindNativeMethods failed"); + return nullptr; + } + ani_object contextObj = EtsAbilityContext::SetAbilityContext(env, context); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null contextObj"); + return nullptr; + } + ContextUtil::CreateEtsBaseContext(env, cls, contextObj, context); + + auto abilityInfo = context->GetAbilityInfo(); + if (abilityInfo == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null abilityInfo"); + return nullptr; + } + ani_ref abilityInfoRef = AppExecFwk::CommonFunAni::ConvertAbilityInfo(env, *abilityInfo); + ani_status status = env->Object_SetFieldByName_Ref(contextObj, "abilityInfo", abilityInfoRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Object_SetFieldByName_Ref status: %{public}d", status); + return nullptr; + } + + auto configuration = context->GetConfiguration(); + if (configuration == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null configuration"); + return nullptr; + } + ani_object configurationObj = OHOS::AppExecFwk::WrapConfiguration(env, *configuration); + if ((status = env->Object_SetFieldByName_Ref(contextObj, "config", configurationObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::CONTEXT, "Object_SetFieldByName_Ref status: %{public}d", status); + return nullptr; + } + return contextObj; +} +} // namespace AbilityRuntime +} // namespace OHOS 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 4ea83ccfef5..10bf994a197 100644 --- a/frameworks/native/ability/native/ability_runtime/ets_ui_ability.cpp +++ b/frameworks/native/ability/native/ability_runtime/ets_ui_ability.cpp @@ -21,6 +21,7 @@ #include "app_recovery.h" #include "connection_manager.h" #include "display_util.h" +#include "ets_ability_context.h" #include "ets_data_struct_converter.h" #include "hilog_tag_wrapper.h" #include "hitrace_meter.h" @@ -187,6 +188,35 @@ void EtsUIAbility::SetAbilityContext(std::shared_ptr abilityInfo, s TAG_LOGE(AAFwkTag::UIABILITY, "null etsAbilityObj_ or abilityContext_ or want"); return; } + int32_t screenMode = want->GetIntParam(AAFwk::SCREEN_MODE_KEY, AAFwk::ScreenMode::IDLE_SCREEN_MODE); + CreateEtsContext(screenMode, application); +} + +void EtsUIAbility::CreateEtsContext(int32_t screenMode, const std::shared_ptr &application) +{ + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null env"); + return; + } + if (screenMode == AAFwk::IDLE_SCREEN_MODE) { + ani_object contextObj = CreateEtsAbilityContext(env, abilityContext_, application); + if (contextObj == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null contextObj"); + return; + } + ani_ref contextGlobalRef = nullptr; + env->GlobalReference_Create(contextObj, &contextGlobalRef); + ani_status status = env->Object_SetFieldByName_Ref(etsAbilityObj_->aniObj, "context", contextGlobalRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_SetFieldByName_Ref status: %{public}d", status); + return; + } + shellContextRef_ = std::make_shared(); + shellContextRef_->aniObj = contextObj; + shellContextRef_->aniRef = contextGlobalRef; + } + // to be done: CreateAniEmbeddableUIAbilityContext } void EtsUIAbility::OnStart(const Want &want, sptr sessionInfo) 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 new file mode 100644 index 00000000000..61850588338 --- /dev/null +++ b/interfaces/kits/native/ability/native/ability_runtime/ets_ability_context.h @@ -0,0 +1,65 @@ +/* + * 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_ETS_ABILITY_CONTEXT_H +#define OHOS_ABILITY_RUNTIME_SIMULATOR_ETS_ABILITY_CONTEXT_H + +#include "ability_context.h" +#include "configuration.h" +#include "ets_runtime.h" +#include "ohos_application.h" + +namespace OHOS { +namespace AbilityRuntime { +using OHOSApplication = AppExecFwk::OHOSApplication; +class EtsAbilityContext final { +public: + static EtsAbilityContext &GetInstance() + { + static EtsAbilityContext instance; + return instance; + } + static void StartAbility(ani_env *env, ani_object aniObj, ani_object wantObj, ani_object call); + static void StartAbilityWithOptions( + ani_env *env, ani_object aniObj, ani_object wantObj, ani_object opt, ani_object call); + 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 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); + + static ani_object SetAbilityContext(ani_env *env, const std::shared_ptr &context); + static std::shared_ptr GetAbilityContext(ani_env *env, ani_object aniObj); + +private: + static bool AsyncCallback(ani_env *env, ani_object call, ani_object error, ani_object result); + void InheritWindowMode(ani_env *env, ani_object aniObj, AAFwk::Want &want); + void OnStartAbility(ani_env *env, ani_object aniObj, ani_object wantObj, ani_object opt, ani_object call); + void OnStartAbilityForResult( + ani_env *env, ani_object aniObj, ani_object wantObj, ani_object startOptionsObj, ani_object callback); + 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); + int32_t GenerateRequestCode(); + + static std::mutex requestCodeMutex_; +}; + +ani_object CreateEtsAbilityContext( + ani_env *env, const std::shared_ptr &context, const std::shared_ptr &application); +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_SIMULATOR_ETS_ABILITY_CONTEXT_H 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 cecb7e7a835..53cb348a6ef 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 @@ -156,6 +156,7 @@ private: void DoOnForegroundForSceneIsNull(const Want &want); void UpdateAbilityObj(std::shared_ptr abilityInfo, const std::string &moduleName, const std::string &srcPath); + void CreateEtsContext(int32_t screenMode, const std::shared_ptr &application); bool BindNativeMethods(); ETSRuntime &etsRuntime_; -- Gitee From a4628501983e3cc29a94a247e19a9c399337c17d Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Wed, 11 Jun 2025 01:51:07 +0800 Subject: [PATCH 2/2] add ani serviceextension Signed-off-by: zhangzezhong --- frameworks/ets/ani/BUILD.gn | 1 + frameworks/ets/ani/ability_delegator/BUILD.gn | 84 +++ .../include/ets_ability_delegator.h | 72 +++ .../include/ets_ability_delegator_registry.h | 26 + .../include/ets_ability_delegator_utils.h | 30 ++ .../include/ets_ability_monitor.h | 140 +++++ .../src/ets_ability_delegator.cpp | 510 ++++++++++++++++++ .../src/ets_ability_delegator_registry.cpp | 144 +++++ .../src/ets_ability_delegator_utils.cpp | 304 +++++++++++ .../src/ets_ability_monitor.cpp | 195 +++++++ .../ani/ani_common/include/ani_common_util.h | 2 + .../ani/ani_common/src/ani_common_util.cpp | 28 + .../context_native_constructor.cpp | 19 + .../include/ets_service_extension.h | 150 ++++++ .../src/ets_service_extension.cpp | 394 ++++++++++++++ .../include/ets_ui_extension.h | 6 +- .../ets_ui_extension_content_session.h | 4 +- .../include/ets_ui_extension_context.h | 8 +- .../src/ets_ui_extension.cpp | 15 +- .../src/ets_ui_extension_context.cpp | 26 +- ...os.app.ability.ServiceExtensionAbility.ets | 97 ++++ ...s.app.ability.abilityDelegatorRegistry.ets | 28 + .../ets/ets/@ohos.application.testRunner.ets | 19 + frameworks/ets/ets/BUILD.gn | 173 +++++- .../ets/ets/application/AbilityDelegator.ets | 165 ++++++ .../ets/ets/application/AbilityMonitor.ets | 48 ++ .../ets/ets/application/ExtensionContext.ets | 3 + .../application/ServiceExtensionContext.ets | 19 + .../ets/application/abilityDelegatorArgs.ets | 28 + .../ets/ets/application/shellCmdResult.ets | 26 + frameworks/ets/ets/utils/AbilityUtils.ets | 14 +- .../app/ability_delegator/ability_monitor.cpp | 84 ++- .../app/ability_delegator/ability_monitor.h | 14 +- .../js_ability_delegator.cpp | 21 +- frameworks/native/ability/native/BUILD.gn | 30 +- .../ability/native/service_extension.cpp | 4 +- frameworks/native/appkit/BUILD.gn | 3 + .../ability_delegator/ability_delegator.cpp | 63 +-- .../ability_delegator/iability_monitor.cpp | 20 +- .../runner_runtime/ets_test_runner.cpp | 179 ++++++ frameworks/native/appkit/app/main_thread.cpp | 21 +- .../ability_delegator/ability_delegator.h | 34 +- .../ability_delegator_infos.h | 13 +- .../ability_delegator/iability_monitor.h | 22 +- .../runner_runtime/ets_test_runner.h | 71 +++ .../mock_iability_monitor.cpp | 16 +- .../ability_delegator/mock_iability_monitor.h | 16 +- .../ability_delegator_test/BUILD.gn | 5 + test/unittest/app_recovery_test/BUILD.gn | 1 + test/unittest/cj_test_runner_test/BUILD.gn | 1 + .../ability_delegator/BUILD.gn | 4 + .../ability_delegator_test.cpp | 2 +- .../iability_monitor_test.cpp | 2 +- test/unittest/js_ui_ability_test/BUILD.gn | 1 + 54 files changed, 3223 insertions(+), 182 deletions(-) create mode 100644 frameworks/ets/ani/ability_delegator/BUILD.gn create mode 100644 frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h create mode 100644 frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_registry.h create mode 100644 frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_utils.h create mode 100644 frameworks/ets/ani/ability_delegator/include/ets_ability_monitor.h create mode 100644 frameworks/ets/ani/ability_delegator/src/ets_ability_delegator.cpp create mode 100644 frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_registry.cpp create mode 100644 frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_utils.cpp create mode 100644 frameworks/ets/ani/ability_delegator/src/ets_ability_monitor.cpp create mode 100644 frameworks/ets/ani/service_extension_ability/include/ets_service_extension.h create mode 100644 frameworks/ets/ani/service_extension_ability/src/ets_service_extension.cpp create mode 100644 frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets create mode 100644 frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets create mode 100644 frameworks/ets/ets/@ohos.application.testRunner.ets create mode 100644 frameworks/ets/ets/application/AbilityDelegator.ets create mode 100644 frameworks/ets/ets/application/AbilityMonitor.ets create mode 100644 frameworks/ets/ets/application/ServiceExtensionContext.ets create mode 100644 frameworks/ets/ets/application/abilityDelegatorArgs.ets create mode 100644 frameworks/ets/ets/application/shellCmdResult.ets create mode 100644 frameworks/native/appkit/ability_delegator/runner_runtime/ets_test_runner.cpp create mode 100644 interfaces/kits/native/appkit/ability_delegator/runner_runtime/ets_test_runner.h diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index 179317141d0..2c324d61cda 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -16,6 +16,7 @@ import("//foundation/ability/ability_runtime/ability_runtime.gni") group("ani_packages") { deps = [ + "${ability_runtime_path}/frameworks/ets/ani/ability_delegator:ability_delegator_registry_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", "${ability_runtime_path}/frameworks/ets/ani/native_constructor:context_ani", "${ability_runtime_path}/frameworks/ets/ani/uri_permission_manager:uri_permission_manager_abc_etc", diff --git a/frameworks/ets/ani/ability_delegator/BUILD.gn b/frameworks/ets/ani/ability_delegator/BUILD.gn new file mode 100644 index 00000000000..5e1733151b2 --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/BUILD.gn @@ -0,0 +1,84 @@ +# 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("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("ability_delegator_registry_ani_kit") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ + "./include", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/app", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/ability_delegator/include", + "${ability_runtime_services_path}/common/include", + "${ability_runtime_path}/interfaces/kits/native/ability/native", + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", + "${ability_runtime_path}/frameworks/ets/ani/enum_convert", + "${ability_runtime_path}/frameworks/js/napi/app/ability_delegator", + "${ability_runtime_path}/interfaces/inner_api/runtime/include", + ] + + configs = [] + + public_configs = [] + + sources = [ + "./src/ets_ability_delegator.cpp", + "./src/ets_ability_delegator_registry.cpp", + "./src/ets_ability_delegator_utils.cpp", + "./src/ets_ability_monitor.cpp", + ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + deps = [ + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/ability_manager:ability_start_options", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:app_context_utils", + "${ability_runtime_native_path}/appkit:appkit_delegator", + "${ability_runtime_native_path}/appkit:delegator_mgmt", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + external_deps = [ + "ability_base:want", + "bundle_framework:appexecfwk_base", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "eventhandler:libeventhandler", + "hilog:libhilog", + "ipc:ipc_core", + "json:nlohmann_json_static", + "napi:ace_napi", + "runtime_core:ani", + ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h new file mode 100644 index 00000000000..c1c31f62179 --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator.h @@ -0,0 +1,72 @@ +/* +* 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_ABILITY_DELEGATOR_H +#define OHOS_ABILITY_RUNTIME_ETS_ABILITY_DELEGATOR_H + +#include +#include "ability_delegator.h" +#include "context.h" +#include "ets_ability_delegator_registry.h" +#include "ets_ability_monitor.h" +#include "iability_monitor.h" +#include "ets_runtime.h" +#include "want.h" +namespace OHOS { +namespace AbilityDelegatorEts { +using namespace OHOS::AbilityRuntime; +class EtsAbilityDelegator { +public: + static EtsAbilityDelegator& GetInstance() + { + static EtsAbilityDelegator instance; + return instance; + } + EtsAbilityDelegator(); + ~EtsAbilityDelegator(); + static void ExecuteShellCommand(ani_env* env, [[maybe_unused]]ani_object object, + ani_string cmd, ani_double timeoutSecs, ani_object callback); + + static void FinishTest(ani_env* env, [[maybe_unused]]ani_object object, + ani_string msg, ani_double code, ani_object callback); + + static ani_object CreateEtsBaseContext(ani_env* aniEnv, ani_class contextClass, + std::shared_ptr context); + + static ani_object GetAppContext(ani_env* env, [[maybe_unused]]ani_object object, ani_class clss); + + static void PrintSync(ani_env *env, [[maybe_unused]]ani_class aniClass, ani_string msg); + + static void AddAbilityMonitor(ani_env *env, [[maybe_unused]]ani_class aniClass, + ani_object monitorObj, ani_object callback); + + static void StartAbility(ani_env* env, [[maybe_unused]]ani_object object, ani_object wantObj, ani_object callback); + +private: + [[maybe_unused]] void RetrieveStringFromAni(ani_env *env, ani_string string, std::string &resString); + + ani_object WrapShellCmdResult(ani_env* env, std::unique_ptr result); + + bool ParseMonitorPara(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl); + + bool ParseMonitorParaInner(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl); + +}; +} // namespace AbilityDelegatorEts +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_ETS_ABILITY_DELEGATOR_H diff --git a/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_registry.h b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_registry.h new file mode 100644 index 00000000000..1b9a9dddc1a --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_registry.h @@ -0,0 +1,26 @@ +/* + * 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_ABILITY_DELEGATOR_REGISTRY_H +#define OHOS_ABILITY_RUNTIME_ETS_ABILITY_DELEGATOR_REGISTRY_H + +#include "ets_runtime.h" + +namespace OHOS { +namespace AbilityDelegatorEts { +void EtsAbilityDelegatorRegistryInit(ani_env *env); +} // namespace AbilityDelegatorEts +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_ABILITY_DELEGATOR_REGISTRY_H diff --git a/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_utils.h b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_utils.h new file mode 100644 index 00000000000..8ad04530954 --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/include/ets_ability_delegator_utils.h @@ -0,0 +1,30 @@ +/* + * 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_ABILITY_DELEGATOR_UTILS_H +#define OHOS_ABILITY_RUNTIME_ETS_ABILITY_DELEGATOR_UTILS_H + +#include "ability_delegator.h" +#include "ability_delegator_args.h" +#include "ets_runtime.h" + +namespace OHOS { +namespace AbilityDelegatorEts { +ani_object CreateEtsAbilityDelegator(ani_env *env); +ani_object CreateEtsAbilityDelegatorArguments(ani_env *env, + const std::shared_ptr abilityDelegatorArgs); +} // namespace AbilityDelegatorEts +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_ABILITY_DELEGATOR_UTILS_H diff --git a/frameworks/ets/ani/ability_delegator/include/ets_ability_monitor.h b/frameworks/ets/ani/ability_delegator/include/ets_ability_monitor.h new file mode 100644 index 00000000000..8e01944c2fa --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/include/ets_ability_monitor.h @@ -0,0 +1,140 @@ +/* + * 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_ABILITY_MONITOR_H +#define OHOS_ABILITY_RUNTIME_ETS_ABILITY_MONITOR_H + +#include +#include +#include "iability_monitor.h" +#include "ets_runtime.h" + +namespace OHOS { +namespace AbilityDelegatorEts { +class EtsAbilityMonitor : public AppExecFwk::IAbilityMonitor { +public: + /** + * A constructor used to create a EtsAbilityMonitor instance with the input parameter passed. + * + * @param abilityName Indicates the specified ability name for monitoring the lifecycle state changes + * of the ability. + */ + explicit EtsAbilityMonitor(const std::string &abilityName); + + /** + * A constructor used to create a EtsAbilityMonitor instance with the input parameter passed. + * + * @param abilityName Indicates the specified ability name for monitoring the lifecycle state changes + * of the ability. + * + * @param moduleName Indicates the specified module name for monitoring the lifecycle state changes + * of the ability. + */ + explicit EtsAbilityMonitor(const std::string &abilityName, const std::string &moduleName); + + /** + * Default deconstructor used to deconstruct. + */ + virtual ~EtsAbilityMonitor() = default; + + /** + * Called when ability is started. + * Then call the corresponding method on the ets side through the saved ets object. + * + * @param abilityObj Indicates the ability object. + */ + void OnAbilityStart(const std::weak_ptr &abilityObj) override; + + /** + * Called when ability is in foreground. + * Then call the corresponding method on the ets side through the saved ets object. + * + * @param abilityObj Indicates the ability object. + */ + void OnAbilityForeground(const std::weak_ptr &abilityObj) override; + + /** + * Called when ability is in background. + * Then call the corresponding method on the ets side through the saved ets object. + * + * @param abilityObj Indicates the ability object. + */ + void OnAbilityBackground(const std::weak_ptr &abilityObj) override; + + /** + * Called when ability is stopped. + * Then call the corresponding method on the ets side through the saved ets object. + * + * @param abilityObj Indicates the ability object. + */ + void OnAbilityStop(const std::weak_ptr &abilityObj) override; + + /** + * Called when window stage is created. + * Then call the corresponding method on the ets side through the saved ets object. + * + * @param abilityObj Indicates the ability object. + */ + void OnWindowStageCreate(const std::weak_ptr &abilityObj) override; + + /** + * Called when window stage is restored. + * Then call the corresponding method on the ets side through the saved ets object. + * + * @param abilityObj Indicates the ability object. + */ + void OnWindowStageRestore(const std::weak_ptr &abilityObj) override; + + /** + * Called when window stage is destroyed. + * Then call the corresponding method on the ets side through the saved ets object. + * + * @param abilityObj Indicates the ability object. + */ + void OnWindowStageDestroy(const std::weak_ptr &abilityObj) override; + + /** + * Sets the ets object. + * + * @param abilityMonitorObj Indicates the ets object. + */ + void SetEtsAbilityMonitor(ani_env *env, ani_object &abilityMonitorObj); + + /** + * Obtains the saved ets object. + * + * @return the saved ets object. + */ + std::unique_ptr &GetEtsAbilityMonitor() + { + return etsAbilityMonitor_; + } + +private: + void CallLifecycleCBFunction(const std::string &functionName, + const std::shared_ptr &abilityObj); + ani_env* GetAniEnv(); + std::shared_ptr GetRuntimeObject( + const std::weak_ptr &abilityObj); + +private: + ani_vm* vm_ = nullptr; + std::string abilityName_; + std::string moduleName_; + std::unique_ptr etsAbilityMonitor_; +}; +} // namespace AbilityDelegatorJs +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_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 new file mode 100644 index 00000000000..a21efe7f008 --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator.cpp @@ -0,0 +1,510 @@ +/* + * 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_ability_delegator.h" + +#include +#include +#include "ability_delegator_registry.h" +#include "ability_stage_monitor.h" +#include "ani_common_want.h" +#include "ani_enum_convert.h" +#include "ets_ability_monitor.h" +#include "ets_context_utils.h" +#include "ets_error_utils.h" +#include "hilog_tag_wrapper.h" +#include "shell_cmd_result.h" + +namespace OHOS { +namespace AbilityDelegatorEts { + +using namespace OHOS::AbilityRuntime; + +std::map, std::shared_ptr> g_monitorRecord; +std::map, sptr, std::owner_less<>> g_abilityRecord; +std::mutex g_mtxMonitorRecord; +std::mutex g_mutexAbilityRecord; + +enum ERROR_CODE { + INCORRECT_PARAMETERS = 401, +}; + +#ifdef ENABLE_ERRCODE +constexpr int COMMON_FAILED = 16000100; +#else +constexpr int COMMON_FAILED = -1; +#endif + +namespace { +constexpr const char* AREA_MODE_ENUM_NAME = "L@ohos/app/ability/contextConstant/contextConstant/AreaMode;"; +constexpr const char* CONTEXT_CLASS_NAME = "Lapplication/Context/Context;"; +constexpr const char* SHELL_CMD_RESULT_CLASS_NAME = "Lapplication/shellCmdResult/ShellCmdResultImpl;"; +constexpr const char* ABILITY_MONITOR_INNER_CLASS_NAME = "Lapplication/AbilityMonitor/AbilityMonitorInner;"; +} + +EtsAbilityDelegator::EtsAbilityDelegator() +{ + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + if (delegator) { + auto clearFunc = [](const std::shared_ptr &baseProperty) { + auto property = std::static_pointer_cast(baseProperty); + if (!property) { + TAG_LOGE(AAFwkTag::DELEGATOR, "invalid property type"); + return; + } + + std::unique_lock lck(g_mutexAbilityRecord); + for (auto it = g_abilityRecord.begin(); it != g_abilityRecord.end();) { + if (it->second == property->token_) { + it = g_abilityRecord.erase(it); + continue; + } + ++it; + } + }; + + delegator->RegisterClearFunc(clearFunc); + } +} + +EtsAbilityDelegator::~EtsAbilityDelegator() = default; + +ani_object EtsAbilityDelegator::CreateEtsBaseContext(ani_env* aniEnv, ani_class contextClass, + std::shared_ptr context) +{ + if (aniEnv == nullptr || context == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null aniEnv or context"); + return {}; + } + ani_object contextObj = nullptr; + ani_method method = nullptr; + ani_status status = aniEnv->Class_FindMethod(contextClass, "", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod ctor failed status: %{public}d", status); + return {}; + } + if ((status = aniEnv->Object_New(contextClass, method, &contextObj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_New failed status: %{public}d", status); + return {}; + } + ani_field areaField = nullptr; + if (aniEnv->Class_FindField(contextClass, "area", &areaField) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "find area failed"); + return {}; + } + ani_enum_item areaModeItem {}; + OHOS::AAFwk::AniEnumConvertUtil::EnumConvert_NativeToEts(aniEnv, + AREA_MODE_ENUM_NAME, context->GetArea(), areaModeItem); + if (aniEnv->Object_SetField_Ref(contextObj, areaField, (ani_ref)areaModeItem) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_SetField_Int failed"); + return {}; + } + ani_field filesDirField = nullptr; + if (aniEnv->Class_FindField(contextClass, "filesDir", &filesDirField) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "find filesDir failed"); + return {}; + } + auto filesDir = context->GetFilesDir(); + ani_string filesDir_string{}; + aniEnv->String_NewUTF8(filesDir.c_str(), filesDir.size(), &filesDir_string); + if (aniEnv->Object_SetField_Ref(contextObj, filesDirField, reinterpret_cast(filesDir_string)) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_SetField_Ref failed"); + return {}; + } + ani_field tempDirField = nullptr; + if (aniEnv->Class_FindField(contextClass, "tempDir", &tempDirField) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "find find tempDir failed"); + return {}; + } + auto tempDir = context->GetTempDir(); + ani_string tempDirString{}; + aniEnv->String_NewUTF8(tempDir.c_str(), tempDir.size(), &tempDirString); + if (aniEnv->Object_SetField_Ref(contextObj, tempDirField, reinterpret_cast(tempDirString)) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_SetField_Ref failed"); + return {}; + } + ContextUtil::BindApplicationInfo(aniEnv, contextClass, contextObj, context); + ContextUtil::BindResourceManager(aniEnv, contextClass, contextObj, context); + return contextObj; +} + +ani_object EtsAbilityDelegator::WrapShellCmdResult(ani_env* env, std::unique_ptr result) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "WrapShellCmdResult called"); + if (result == nullptr || env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "result or env is null"); + return {}; + } + ani_class cls = nullptr; + ani_status status = ANI_ERROR; + status = env->FindClass(SHELL_CMD_RESULT_CLASS_NAME, &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "find AbilityDelegator failed status: %{public}d", status); + return {}; + } + ani_method method = nullptr; + status = env->Class_FindMethod(cls, "", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod ctor failed status: %{public}d", status); + return {}; + } + ani_object object = nullptr; + if (env->Object_New(cls, method, &object) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_New failed status: %{public}d", status); + return {}; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Object_New success"); + ani_field filed = nullptr; + status = env->Class_FindField(cls, "stdResult", &filed); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindField failed status: %{public}d", status); + } + ani_string aniStringVal {}; + std::string strResult = result->GetStdResult(); + status = env->String_NewUTF8(strResult.c_str(), strResult.size(), &aniStringVal); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "String_NewUTF8 failed status: %{public}d", status); + } + status = env->Object_SetField_Ref(object, filed, aniStringVal); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "set strResult failed status: %{public}d", status); + } + int32_t exitCode = result->GetExitCode(); + status = env->Object_SetPropertyByName_Double(object, "exitCode", exitCode); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "set exitCode failed status: %{public}d", status); + } + return object; +} + +ani_object EtsAbilityDelegator::GetAppContext(ani_env* env, [[maybe_unused]]ani_object object, ani_class clss) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "GetAppContext call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env is nullptr"); + return {}; + } + ani_class cls; + ani_object nullobj = nullptr; + if (ANI_OK != env->FindClass(CONTEXT_CLASS_NAME, &cls)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "FindClass Context Failed"); + return nullobj; + } + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + if (!delegator) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator"); + return nullobj; + } + std::shared_ptr context = delegator->GetAppContext(); + if (!context) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null context"); + return nullobj; + } + ani_object objectContext = CreateEtsBaseContext(env, cls, context); + TAG_LOGD(AAFwkTag::DELEGATOR, "GetAppContext end"); + return objectContext; +} + +void EtsAbilityDelegator::ExecuteShellCommand(ani_env *env, [[maybe_unused]]ani_object object, + ani_string cmd, ani_double timeoutSecs, ani_object callback) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "ExecuteShellCommand called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + std::string stdCmd = ""; + if (!OHOS::AppExecFwk::GetStdString(env, cmd, stdCmd)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GetStdString Failed"); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return; + } + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + if (!delegator) { + TAG_LOGE(AAFwkTag::DELEGATOR, "delegator is nullptr"); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER); + return; + } + int resultCode = 0; + auto result = delegator->ExecuteShellCommand(stdCmd, static_cast(timeoutSecs)); + ani_object objValue = GetInstance().WrapShellCmdResult(env, std::move(result)); + if (objValue == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null objValue"); + resultCode = COMMON_FAILED; + ani_class cls = nullptr; + ani_status status = env->FindClass(SHELL_CMD_RESULT_CLASS_NAME, &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "find AbilityDelegator failed status: %{public}d", status); + } + ani_method method = nullptr; + status = env->Class_FindMethod(cls, "", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod ctor failed status: %{public}d", status); + } + if (env->Object_New(cls, method, &objValue) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_New failed status: %{public}d", status); + } + } + ani_ref callbackRef = nullptr; + ani_status createStatus = env->GlobalReference_Create(callback, &callbackRef); + if (createStatus != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Create Gloabl ref for delegator failed %{public}d", createStatus); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER); + return; + } + OHOS::AppExecFwk::AsyncCallback(env, reinterpret_cast(callbackRef), + OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, resultCode), + objValue); + return; +} + +void EtsAbilityDelegator::FinishTest(ani_env* env, [[maybe_unused]]ani_object object, + ani_string msg, ani_double code, ani_object callback) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + std::string stdMsg = ""; + if (!OHOS::AppExecFwk::GetStdString(env, msg, stdMsg)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GetStdString Failed"); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return; + } + int resultCode = 0; + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + if (!delegator) { + TAG_LOGE(AAFwkTag::DELEGATOR, "FinishTest delegator is null"); + resultCode = COMMON_FAILED; + } else { + delegator->FinishUserTest(stdMsg, static_cast(code)); + } + ani_ref callbackRef = nullptr; + auto status = env->GlobalReference_Create(callback, &callbackRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Create Gloabl ref for delegator failed %{public}d", status); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER); + return; + } + OHOS::AppExecFwk::AsyncCallback(env, reinterpret_cast(callbackRef), + OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, resultCode), + nullptr); + TAG_LOGD(AAFwkTag::DELEGATOR, "FinishTest END"); + return; +} + +void EtsAbilityDelegator::PrintSync(ani_env *env, [[maybe_unused]]ani_class aniClass, ani_string msg) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "PrintSync"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env is nullptr"); + return; + } + std::string msgStr; + ani_size sz {}; + env->String_GetUTF8Size(msg, &sz); + msgStr.resize(sz + 1); + env->String_GetUTF8SubString(msg, 0, sz, msgStr.data(), msgStr.size(), &sz); + TAG_LOGD(AAFwkTag::DELEGATOR, "PrintSync %{public}s", msgStr.c_str()); + + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + if (delegator == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator"); + return; + } + + delegator->Print(msgStr); + return; +} + +void EtsAbilityDelegator::RetrieveStringFromAni(ani_env *env, ani_string str, std::string &res) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env is nullptr"); + return; + } + ani_size sz {}; + ani_status status = ANI_ERROR; + if ((status = env->String_GetUTF8Size(str, &sz)) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "status: %{public}d", status); + return; + } + res.resize(sz + 1); + if ((status = env->String_GetUTF8SubString(str, 0, sz, res.data(), res.size(), &sz)) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "status: %{public}d", status); + return; + } + res.resize(sz); +} + +void EtsAbilityDelegator::AddAbilityMonitor(ani_env *env, [[maybe_unused]]ani_class aniClass, + ani_object monitorObj, ani_object callback) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env is nullptr"); + return; + } + std::shared_ptr monitorImpl = nullptr; + if (!GetInstance().ParseMonitorPara(env, monitorObj, monitorImpl)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "ParseMonitorPara failed"); + AbilityRuntime::ThrowEtsError(env, INCORRECT_PARAMETERS, + "Parse param monitor failed, monitor must be Monitor."); + return; + } + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + int resultCode = 0; + if (delegator == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator"); + resultCode = COMMON_FAILED; + } else { + delegator->AddAbilityMonitor(monitorImpl); + } + ani_ref callbackRef = nullptr; + ani_status status = env->GlobalReference_Create(callback, &callbackRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "Create Gloabl ref for delegator failed %{public}d", status); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER); + return; + } + OHOS::AppExecFwk::AsyncCallback(env, reinterpret_cast(callbackRef), + OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, resultCode), + nullptr); + return; +} +void EtsAbilityDelegator::StartAbility(ani_env* env, [[maybe_unused]]ani_object object, + ani_object wantObj, ani_object callback) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "StartAbility"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env is nullptr"); + return; + } + AAFwk::Want want; + if (!AppExecFwk::UnwrapWant(env, wantObj, want)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "UnwrapWant failed"); + AbilityRuntime::ThrowEtsError(env, (int32_t)AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM, + "Parse want failed, want must be Want."); + return; + } + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + if (delegator == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator"); + AbilityRuntime::ThrowEtsError(env, COMMON_FAILED); + return; + } + int resultCode = 0; + int result = delegator->StartAbility(want); + if (result != ERR_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "start ability failed: %{public}d", result); + resultCode = result; + } + ani_ref callbackRef = nullptr; + auto status = env->GlobalReference_Create(callback, &callbackRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Create Gloabl ref for delegator failed %{public}d", status); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER); + return; + } + OHOS::AppExecFwk::AsyncCallback(env, reinterpret_cast(callbackRef), + OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, resultCode), + nullptr); + return; +} +bool EtsAbilityDelegator::ParseMonitorPara(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "monitorRecord size: %{public}zu", g_monitorRecord.size()); + if (env == nullptr || monitorObj == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env or monitorObj is nullptr"); + return false; + } + { + std::unique_lock lck(g_mtxMonitorRecord); + for (auto iter = g_monitorRecord.begin(); iter != g_monitorRecord.end(); ++iter) { + std::shared_ptr etsMonitor = iter->first; + ani_boolean result = false; + ani_status status = env->Reference_StrictEquals(reinterpret_cast(monitorObj), + reinterpret_cast(etsMonitor->aniObj), &result); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Reference_StrictEquals failed status: %{public}d", status); + } + if (result) { + monitorImpl = iter->second; + return monitorImpl ? true : false; + } + } + } + if (!ParseMonitorParaInner(env, monitorObj, monitorImpl)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "ParseMonitorParaInner failed"); + return false; + } + return true; +} + +bool EtsAbilityDelegator::ParseMonitorParaInner(ani_env *env, ani_object monitorObj, + std::shared_ptr &monitorImpl) +{ + if (env == nullptr || monitorObj == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "env or monitorObj is nullptr"); + return false; + } + ani_class monitorCls; + ani_status status = env->FindClass(ABILITY_MONITOR_INNER_CLASS_NAME, &monitorCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "FindClass failed status: %{public}d", status); + return false; + } + ani_ref moduleNameRef; + status = env->Object_GetPropertyByName_Ref(monitorObj, "moduleName", &moduleNameRef); + if (ANI_OK != status) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_GetField_Ref "); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER); + return false; + } + std::string strModuleName; + ani_string aniModuleString = static_cast(moduleNameRef); + GetInstance().RetrieveStringFromAni(env, aniModuleString, strModuleName); + ani_ref abilityNameRef; + status = env->Object_GetPropertyByName_Ref(monitorObj, "abilityName", &abilityNameRef); + if (ANI_OK != status) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_GetField_Ref "); + AbilityRuntime::ThrowEtsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER); + return false; + } + std::string strAbilityName; + ani_string aniAbilityName = static_cast(abilityNameRef); + GetInstance().RetrieveStringFromAni(env, aniAbilityName, strAbilityName); + + std::shared_ptr abilityMonitor = nullptr; + if (strModuleName.empty()) { + abilityMonitor = std::make_shared(strAbilityName); + abilityMonitor->SetEtsAbilityMonitor(env, monitorObj); + } else { + abilityMonitor = std::make_shared(strAbilityName, strModuleName); + abilityMonitor->SetEtsAbilityMonitor(env, monitorObj); + } + monitorImpl = abilityMonitor; + std::shared_ptr reference = std::make_shared(); + if (reference != nullptr) { + reference->aniObj = monitorObj; + } + std::unique_lock lck(g_mtxMonitorRecord); + g_monitorRecord.emplace(reference, monitorImpl); + return true; +} + +} // namespace AbilityDelegatorEts +} // namespace OHOS diff --git a/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_registry.cpp b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_registry.cpp new file mode 100644 index 00000000000..da840f60a1a --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_registry.cpp @@ -0,0 +1,144 @@ +/* + * 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_ability_delegator_registry.h" + +#include +#include "ability_delegator.h" +#include "ability_delegator_registry.h" +#include "ets_ability_delegator.h" +#include "ets_ability_delegator_utils.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AbilityDelegatorEts { +std::unique_ptr etsReference; +std::mutex etsReferenceMutex; + +static ani_object GetAbilityDelegator(ani_env *env, [[maybe_unused]]ani_class aniClass) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return {}; + } + + std::lock_guard lock(etsReferenceMutex); + auto delegator = AppExecFwk::AbilityDelegatorRegistry::GetAbilityDelegator(AbilityRuntime::Runtime::Language::ETS); + if (delegator == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator"); + return {}; + } + + if (etsReference == nullptr) { + ani_object value = CreateEtsAbilityDelegator(env); + if (value == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "value is nullptr"); + return {}; + } + ani_boolean isValue; + env->Reference_IsNullishValue(value, &isValue); + if (isValue) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Reference_IsNullishValue"); + return {}; + } + etsReference = std::make_unique(); + ani_ref result; + auto status = env->GlobalReference_Create(value, &(result)); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Create Gloabl ref for delegator failed %{public}d", status); + return {}; + } + etsReference->aniObj = static_cast(result); + return etsReference->aniObj; + } else { + return etsReference->aniObj; + } +} + +static ani_object GetArguments(ani_env *env, [[maybe_unused]]ani_class aniClass) +{ + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return {}; + } + + auto abilityDelegatorArgs = AppExecFwk::AbilityDelegatorRegistry::GetArguments(); + if (abilityDelegatorArgs == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "get argument failed"); + return {}; + } + + return CreateEtsAbilityDelegatorArguments(env, abilityDelegatorArgs); +} + +void EtsAbilityDelegatorRegistryInit(ani_env *env) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "EtsAbilityDelegatorRegistryInit call"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + ani_status status = ANI_ERROR; + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "ResetError failed"); + } + + ani_namespace ns; + status = env->FindNamespace("L@ohos/app/ability/abilityDelegatorRegistry/abilityDelegatorRegistry;", &ns); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "FindNamespace abilityDelegatorRegistry failed status: %{public}d", status); + return; + } + + std::array kitFunctions = { + ani_native_function {"getAbilityDelegator", nullptr, reinterpret_cast(GetAbilityDelegator)}, + ani_native_function {"getArguments", nullptr, reinterpret_cast(GetArguments)}, + }; + + status = env->Namespace_BindNativeFunctions(ns, kitFunctions.data(), kitFunctions.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Namespace_BindNativeFunctions failed status: %{public}d", status); + } + + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "ResetError failed"); + } + TAG_LOGD(AAFwkTag::DELEGATOR, "EtsAbilityDelegatorRegistryInit end"); +} + +extern "C" { +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "ANI_Constructor"); + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null vm"); + return ANI_ERROR; + } + status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "GetEnv failed status: %{public}d", status); + return ANI_NOT_FOUND; + } + + EtsAbilityDelegatorRegistryInit(env); + *result = ANI_VERSION_1; + TAG_LOGD(AAFwkTag::DELEGATOR, "ANI_Constructor finish"); + return ANI_OK; +} +} +} // 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 new file mode 100644 index 00000000000..6d7aed80ad5 --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/src/ets_ability_delegator_utils.cpp @@ -0,0 +1,304 @@ +/* + * 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_ability_delegator_utils.h" + +#include +#include "ets_ability_delegator.h" +#include "hilog_tag_wrapper.h" + + +namespace OHOS { +namespace AbilityDelegatorEts { +namespace { +constexpr const char* ABILITY_DELEGATOR_CLASS_NAME = "Lapplication/AbilityDelegator/AbilityDelegatorInner;"; +constexpr const char* RECORD_CLASS_NAME = "Lescompat/Record;"; +constexpr const char* ARGS_ABILITY_DELEGATOR_CLASS_NAME = + "Lapplication/abilityDelegatorArgs/AbilityDelegatorArgsInner;"; +} + +bool BindFunctions(ani_env *aniEnv, ani_class abilityDelegator) +{ + if (aniEnv == nullptr) { + return false; + } + std::array functions = { + ani_native_function {"getAppContext", nullptr, reinterpret_cast(EtsAbilityDelegator::GetAppContext)}, + ani_native_function {"nativeExecuteShellCommand", nullptr, + reinterpret_cast(EtsAbilityDelegator::ExecuteShellCommand)}, + ani_native_function {"nativeFinishTest", nullptr, reinterpret_cast(EtsAbilityDelegator::FinishTest)}, + ani_native_function {"printSync", nullptr, reinterpret_cast(EtsAbilityDelegator::PrintSync)}, + ani_native_function {"nativeAddAbilityMonitor", nullptr, + reinterpret_cast(EtsAbilityDelegator::AddAbilityMonitor)}, + ani_native_function {"nativeStartAbility", + "L@ohos/app/ability/Want/Want;Lutils/AbilityUtils/AsyncCallbackWrapper;:V", + reinterpret_cast(EtsAbilityDelegator::StartAbility)}, + }; + 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); + return false; + } + return true; +} + +ani_object CreateEtsAbilityDelegator(ani_env *aniEnv) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "CreateEtsAbilityDelegator"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null aniEnv"); + return {}; + } + ani_class abilityDelegator = nullptr; + ani_status status = ANI_ERROR; + status = aniEnv->FindClass(ABILITY_DELEGATOR_CLASS_NAME, &abilityDelegator); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "find AbilityDelegatorInner failed status: %{public}d", status); + return {}; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "find AbilityDelegator success"); + + if (!BindFunctions(aniEnv, abilityDelegator)) { + TAG_LOGE(AAFwkTag::DELEGATOR, "BindFunctions failed"); + return {}; + } + + ani_method method = nullptr; + status = aniEnv->Class_FindMethod(abilityDelegator, "", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod ctor failed status: %{public}d", status); + return {}; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Class_FindMethod ctor success"); + + ani_object object = nullptr; + if (aniEnv->Object_New(abilityDelegator, method, &object) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_New failed status: %{public}d", status); + return {}; + } + + TAG_LOGD(AAFwkTag::DELEGATOR, "CreateEtsAbilityDelegator success"); + return object; +} + +void SetBundleName(ani_env *aniEnv, ani_class arguments, ani_object argumentObject, const std::string &bundleName) +{ + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null aniEnv"); + return; + } + ani_status status = ANI_ERROR; + ani_string aniStr; + // Get a ani_string from std::string + status = aniEnv->String_NewUTF8(bundleName.c_str(), bundleName.length(), &aniStr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "String_NewUTF8 failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "String_NewUTF8 success"); + + // find the setter method + ani_method nameSetter; + status = aniEnv->Class_FindMethod(arguments, "bundleName", nullptr, &nameSetter); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Class_FindMethod success"); + + // call set bundleName(n:string) + status = aniEnv->Object_CallMethod_Void(argumentObject, nameSetter, aniStr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_CallMethod_Void failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Object_CallMethod_Void success"); +} + +void SetParameters(ani_env *aniEnv, ani_class arguments, ani_object argumentObject, + const std::map ¶s) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "SetParameters begin"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null aniEnv"); + return; + } + ani_status status = ANI_ERROR; + ani_class recordCls; + status = aniEnv->FindClass(RECORD_CLASS_NAME, &recordCls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "FindClass failed status: %{public}d", status); + return; + } + ani_method recordGetMethod; + status = aniEnv->Class_FindMethod(recordCls, "$_get", "Lstd/core/Object;:Lstd/core/Object;", &recordGetMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod failed status: %{public}d", status); + return; + } + ani_method recordSetMethod; + status = aniEnv->Class_FindMethod(recordCls, "$_set", "Lstd/core/Object;Lstd/core/Object;:V", &recordSetMethod); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod failed status: %{public}d", status); + return; + } + ani_ref parameterRef; + status = aniEnv->Object_CallMethodByName_Ref(argumentObject, "parameters", ":Lescompat/Record;", + ¶meterRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_CallMethodByName_Ref failed status: %{public}d", status); + return; + } + ani_object parameterObject = static_cast(parameterRef); + for (auto iter = paras.begin(); iter != paras.end(); ++iter) { + std::string key = iter->first; + std::string value = iter->second; + ani_string ani_key; + ani_string ani_value; + status = aniEnv->String_NewUTF8(key.c_str(), key.length(), &ani_key); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "String_NewUTF8 key failed status: %{public}d", status); + return; + } + status = aniEnv->String_NewUTF8(value.c_str(), value.length(), &ani_value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "String_NewUTF8 value failed status: %{public}d", status); + return; + } + status = aniEnv->Object_CallMethod_Void(parameterObject, recordSetMethod, ani_key, ani_value); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_CallMethod_Void failed status: %{public}d", status); + return; + } + } + TAG_LOGD(AAFwkTag::DELEGATOR, "SetParameters end"); +} + +void SetTestCaseNames(ani_env *aniEnv, ani_class arguments, ani_object argumentObject, const std::string &testcaseNames) +{ + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null aniEnv"); + return; + } + ani_status status = ANI_ERROR; + ani_string aniStr; + status = aniEnv->String_NewUTF8(testcaseNames.c_str(), testcaseNames.length(), &aniStr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "String_NewUTF8 failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "String_NewUTF8 success"); + + // find the setter method + ani_method nameSetter; + status = aniEnv->Class_FindMethod(arguments, "testCaseNames", nullptr, &nameSetter); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Class_FindMethod success"); + + // call set testcaseNames(n:string) + status = aniEnv->Object_CallMethod_Void(argumentObject, nameSetter, aniStr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_CallMethod_Void failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Object_CallMethod_Void success"); +} + +void SetTestRunnerClassName(ani_env *aniEnv, ani_class arguments, ani_object argumentObject, + const std::string &className) +{ + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null aniEnv"); + return; + } + ani_status status = ANI_ERROR; + ani_string aniStr; + status = aniEnv->String_NewUTF8(className.c_str(), className.length(), &aniStr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "String_NewUTF8 failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "String_NewUTF8 success"); + + // find the setter method + ani_method nameSetter; + status = aniEnv->Class_FindMethod(arguments, "testRunnerClassName", nullptr, &nameSetter); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Class_FindMethod success"); + + // call set testRunnerClassName(n:string) + status = aniEnv->Object_CallMethod_Void(argumentObject, nameSetter, aniStr); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_CallMethod_Void failed status: %{public}d", status); + return; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Object_CallMethod_Void success"); +} + +ani_object CreateEtsAbilityDelegatorArguments( + ani_env *aniEnv, const std::shared_ptr abilityDelegatorArgs) +{ + TAG_LOGD(AAFwkTag::DELEGATOR, "CreateJsAbilityDelegatorArguments"); + if (aniEnv == nullptr || abilityDelegatorArgs == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null aniEnv or abilityDelegatorArgs"); + return {}; + } + ani_class arguments = nullptr; + ani_status status = ANI_ERROR; + status = aniEnv->FindClass(ARGS_ABILITY_DELEGATOR_CLASS_NAME, &arguments); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "find abilityDelegatorArgs failed status: %{public}d", status); + return {}; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "find AbilityDelegatorArgs success"); + + ani_method method = nullptr; + status = aniEnv->Class_FindMethod(arguments, "", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Class_FindMethod ctor failed status: %{public}d", status); + return {}; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Class_FindMethod ctor success"); + + ani_object argumentObject = nullptr; + status = aniEnv->Object_New(arguments, method, &argumentObject); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_New failed status: %{public}d", status); + return {}; + } + TAG_LOGD(AAFwkTag::DELEGATOR, "Object_New success"); + + std::string bundleName = abilityDelegatorArgs->GetTestBundleName(); + SetBundleName(aniEnv, arguments, argumentObject, bundleName); + + std::string testcaseName = abilityDelegatorArgs->GetTestCaseName(); + SetTestCaseNames(aniEnv, arguments, argumentObject, testcaseName); + + std::string className = abilityDelegatorArgs->GetTestRunnerClassName(); + SetTestRunnerClassName(aniEnv, arguments, argumentObject, className); + + auto parameters = abilityDelegatorArgs->GetTestParam(); + SetParameters(aniEnv, arguments, argumentObject, parameters); + + return argumentObject; +} +} // namespace AbilityDelegatorEts +} // namespace OHOS diff --git a/frameworks/ets/ani/ability_delegator/src/ets_ability_monitor.cpp b/frameworks/ets/ani/ability_delegator/src/ets_ability_monitor.cpp new file mode 100644 index 00000000000..9ce5b78aa6d --- /dev/null +++ b/frameworks/ets/ani/ability_delegator/src/ets_ability_monitor.cpp @@ -0,0 +1,195 @@ +/* + * 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 "ability_delegator_registry.h" +#include "ets_ability_monitor.h" +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AbilityDelegatorEts { +using namespace OHOS::AbilityRuntime; +EtsAbilityMonitor::EtsAbilityMonitor(const std::string &abilityName) + : IAbilityMonitor(abilityName), abilityName_(abilityName) +{} + +EtsAbilityMonitor::EtsAbilityMonitor(const std::string &abilityName, const std::string &moduleName) + : IAbilityMonitor(abilityName), abilityName_(abilityName), moduleName_(moduleName) +{} + +void EtsAbilityMonitor::OnAbilityStart(const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityStart"); + auto runtimeObj = GetRuntimeObject(abilityObj); + if (!runtimeObj) { + return; + } + CallLifecycleCBFunction("onAbilityCreate", runtimeObj); +} + +void EtsAbilityMonitor::OnAbilityForeground(const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityForeground"); + auto runtimeObj = GetRuntimeObject(abilityObj); + if (!runtimeObj) { + return; + } + CallLifecycleCBFunction("onAbilityForeground", runtimeObj); +} + +void EtsAbilityMonitor::OnAbilityBackground(const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityBackground"); + auto runtimeObj = GetRuntimeObject(abilityObj); + if (!runtimeObj) { + return; + } + CallLifecycleCBFunction("onAbilityBackground", runtimeObj); +} + +void EtsAbilityMonitor::OnAbilityStop(const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnAbilityStop"); + auto runtimeObj = GetRuntimeObject(abilityObj); + if (!runtimeObj) { + return; + } + CallLifecycleCBFunction("onAbilityDestroy", runtimeObj); +} + +void EtsAbilityMonitor::OnWindowStageCreate(const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnWindowStageCreate"); + auto runtimeObj = GetRuntimeObject(abilityObj); + if (!runtimeObj) { + return; + } + CallLifecycleCBFunction("onWindowStageCreate", runtimeObj); +} + +void EtsAbilityMonitor::OnWindowStageRestore(const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnWindowStageRestore"); + auto runtimeObj = GetRuntimeObject(abilityObj); + if (!runtimeObj) { + return; + } + CallLifecycleCBFunction("onWindowStageRestore", runtimeObj); +} + +void EtsAbilityMonitor::OnWindowStageDestroy(const std::weak_ptr &abilityObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called OnWindowStageDestroy"); + auto runtimeObj = GetRuntimeObject(abilityObj); + if (!runtimeObj) { + return; + } + CallLifecycleCBFunction("onWindowStageDestroy", runtimeObj); +} + +void EtsAbilityMonitor::SetEtsAbilityMonitor(ani_env *env, ani_object &abilityMonitorObj) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "called SetEtsAbilityMonitor"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + etsAbilityMonitor_ = std::make_unique(); + ani_ref objRef = nullptr; + if (env->GlobalReference_Create(abilityMonitorObj, &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 (etsAbilityMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null etsAbilityMonitor_"); + return; + } + etsAbilityMonitor_->aniObj = abilityMonitorObj; + etsAbilityMonitor_->aniRef = objRef; +} + +void EtsAbilityMonitor::CallLifecycleCBFunction(const std::string &functionName, + const std::shared_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 (abilityObj == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null EtsAbilityMonitor"); + return; + } + + ani_env *env = GetAniEnv(); + if (env == nullptr || etsAbilityMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env or etsAbilityMonitor_"); + return; + } + + ani_status status = ANI_OK; + ani_object monitorObj = reinterpret_cast(etsAbilityMonitor_->aniRef); + ani_ref funRef; + status = env->Object_GetPropertyByName_Ref(monitorObj, functionName.c_str(), &funRef); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_GetField_Ref failed status: %{public}d", status); + return; + } + + ani_fn_object onFn = reinterpret_cast(funRef); + ani_ref resutlt; + std::vector argv = { abilityObj->aniRef }; + if ((status = env->FunctionalObject_Call(onFn, 1, argv.data(), &resutlt)) != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "FunctionalObject_Call failed, status: %{public}d", status); + return; + } +} + +ani_env* EtsAbilityMonitor::GetAniEnv() +{ + if (vm_ == nullptr) { + return nullptr; + } + ani_env* aniEnv = nullptr; + if (vm_->GetEnv(ANI_VERSION_1, &aniEnv) != ANI_OK) { + return nullptr; + } + return aniEnv; +} + +std::shared_ptr EtsAbilityMonitor::GetRuntimeObject( + const std::weak_ptr &abilityObj) +{ + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return nullptr; + } + auto etsbaseProperty = std::static_pointer_cast(baseProperty); + auto runtimeObj = etsbaseProperty->object_.lock(); + if (!runtimeObj) { + TAG_LOGE(AAFwkTag::DELEGATOR, "runtimeObj is nullptr"); + return nullptr; + } + return runtimeObj; +} +} // namespace AbilityDelegatorJs +} // namespace OHOS diff --git a/frameworks/ets/ani/ani_common/include/ani_common_util.h b/frameworks/ets/ani/ani_common/include/ani_common_util.h index 38d34f0a202..a601a0493a0 100644 --- a/frameworks/ets/ani/ani_common/include/ani_common_util.h +++ b/frameworks/ets/ani/ani_common/include/ani_common_util.h @@ -51,6 +51,8 @@ bool GetStringOrUndefined(ani_env *env, ani_object param, const char *name, std: ani_object CreateDouble(ani_env *env, ani_double value); ani_object CreateBoolean(ani_env *env, ani_boolean value); + +bool AsyncCallback(ani_env *env, ani_object call, ani_object error, ani_object result); } // namespace AppExecFwk } // namespace OHOS #endif // OHOS_ABILITY_RUNTIME_ANI_COMMON_UTIL_H diff --git a/frameworks/ets/ani/ani_common/src/ani_common_util.cpp b/frameworks/ets/ani/ani_common/src/ani_common_util.cpp index 85a7a6dab7d..fdadf71591c 100644 --- a/frameworks/ets/ani/ani_common/src/ani_common_util.cpp +++ b/frameworks/ets/ani/ani_common/src/ani_common_util.cpp @@ -24,6 +24,7 @@ namespace AppExecFwk { constexpr const char* CLASSNAME_DOUBLE = "Lstd/core/Double;"; constexpr const char* CLASSNAME_BOOL = "Lstd/core/Boolean;"; constexpr const char* CLASSNAME_ARRAY = "Lescompat/Array;"; +constexpr const char* CLASSNAME_ASYNC_CALLBACK_WRAPPER = "Lutils/AbilityUtils/AsyncCallbackWrapper;"; bool GetFieldDoubleByName(ani_env *env, ani_object object, const char *name, double &value) { @@ -452,6 +453,33 @@ ani_object CreateBoolean(ani_env *env, ani_boolean value) return obj; } +bool AsyncCallback(ani_env *env, ani_object call, ani_object error, ani_object result) +{ + ani_status status = ANI_ERROR; + ani_class clsCall {}; + + if ((status = env->FindClass(CLASSNAME_ASYNC_CALLBACK_WRAPPER, &clsCall)) != ANI_OK) { + TAG_LOGE(AAFwkTag::JSNAPI, "status: %{public}d", status); + return false; + } + ani_method method {}; + if ((status = env->Class_FindMethod( + clsCall, "invoke", "L@ohos/base/BusinessError;Lstd/core/Object;:V", &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::JSNAPI, "status: %{public}d", status); + return false; + } + if (result == nullptr) { + ani_ref nullRef = nullptr; + env->GetNull(&nullRef); + result = reinterpret_cast(nullRef); + } + if ((status = env->Object_CallMethod_Void(call, method, error, result)) != ANI_OK) { + TAG_LOGE(AAFwkTag::JSNAPI, "status: %{public}d", status); + return false; + } + return true; +} + bool GetDoubleOrUndefined(ani_env *env, ani_object param, const char *name, ani_double &value) { ani_ref obj = nullptr; diff --git a/frameworks/ets/ani/native_constructor/context_native_constructor.cpp b/frameworks/ets/ani/native_constructor/context_native_constructor.cpp index 79964f5e4d9..cee2ac18682 100644 --- a/frameworks/ets/ani/native_constructor/context_native_constructor.cpp +++ b/frameworks/ets/ani/native_constructor/context_native_constructor.cpp @@ -22,6 +22,10 @@ void ContextConstructor() { } +void ExtensionContextConstructor() +{ +} + extern "C" { ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) { @@ -48,6 +52,21 @@ ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) TAG_LOGE(AAFwkTag::ETSRUNTIME, "Cannot bind native ctor to class %{public}s.", contextClassName); return ANI_ERROR; }; + + ani_class extensionContextClass; + static const char *extensionContextClassName = "Lapplication/ExtensionContext/ExtensionContext;"; + if (ANI_OK != env->FindClass(extensionContextClassName, &extensionContextClass)) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Not found class %{public}s.", extensionContextClassName); + return ANI_NOT_FOUND; + } + std::array classMethods_extensionContext = { + ani_native_function {"", ":V", reinterpret_cast(ExtensionContextConstructor)}, + }; + if (ANI_OK != env->Class_BindNativeMethods(extensionContextClass, classMethods_extensionContext.data(), + classMethods_extensionContext.size())) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Cannot bind native ctor to class %{public}s.", extensionContextClassName); + return ANI_ERROR; + }; *result = ANI_VERSION_1; return ANI_OK; } diff --git a/frameworks/ets/ani/service_extension_ability/include/ets_service_extension.h b/frameworks/ets/ani/service_extension_ability/include/ets_service_extension.h new file mode 100644 index 00000000000..ee550a541b4 --- /dev/null +++ b/frameworks/ets/ani/service_extension_ability/include/ets_service_extension.h @@ -0,0 +1,150 @@ +/* + * 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_SERVICE_EXTENSION_H +#define OHOS_ABILITY_RUNTIME_ETS_SERVICE_EXTENSION_H + +#include "configuration.h" +#include "ets_runtime.h" +#include "service_extension.h" + +namespace OHOS { +namespace AbilityRuntime { +/** + * @brief Basic service components. + */ +class EtsServiceExtension : public ServiceExtension { +public: + explicit EtsServiceExtension(ETSRuntime &etsRuntime); + virtual ~EtsServiceExtension() override; + + /** + * @brief Create EtsServiceExtension. + * + * @param runtime The runtime. + * @return The EtsServiceExtension instance. + */ + static EtsServiceExtension *Create(const std::unique_ptr &runtime); + + /** + * @brief Init the extension. + * + * @param record the extension record. + * @param application the application info. + * @param handler the extension handler. + * @param token the remote token. + */ + virtual void Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, const sptr &token) override; + + /** + * @brief Called when this extension is started. You must override this function if you want to perform some + * initialization operations during extension startup. + * + * This function can be called only once in the entire lifecycle of an extension. + * @param Want Indicates the {@link Want} structure containing startup information about the extension. + */ + virtual void OnStart(const AAFwk::Want &want) override; + + /** + * @brief Called when this Service extension is connected for the first time. + * + * You can override this function to implement your own processing logic. + * + * @param want Indicates the {@link Want} structure containing connection information about the Service extension. + * @return Returns a pointer to the sid of the connected Service extension. + */ + virtual sptr OnConnect(const AAFwk::Want &want) override; + + /** + * @brief Called when this Service extension is connected for the first time. + * + * You can override this function to implement your own processing logic. + * + * @param want Indicates the {@link Want} structure containing connection information about the Service extension. + * @param callbackInfo Indicates the lifecycle transaction callback information + * @param isAsyncCallback Indicates whether it is an asynchronous lifecycle callback + * @return Returns a pointer to the sid of the connected Service extension. + */ + virtual sptr OnConnect(const AAFwk::Want &want, + AppExecFwk::AbilityTransactionCallbackInfo> *callbackInfo, bool &isAsyncCallback) override; + + /** + * @brief Called when all abilities connected to this Service extension are disconnected. + * + * You can override this function to implement your own processing logic. + * + */ + virtual void OnDisconnect(const AAFwk::Want &want) override; + + /** + * @brief Called when all abilities connected to this Service extension are disconnected. + * + * You can override this function to implement your own processing logic. + * @param callbackInfo Indicates the lifecycle transaction callback information + * @param isAsyncCallback Indicates whether it is an asynchronous lifecycle callback + */ + void OnDisconnect(const AAFwk::Want &want, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, + bool &isAsyncCallback) override; + + /** + * @brief Called back when Service is started. + * This method can be called only by Service. You can use the StartAbility(ohos.aafwk.content.Want) method to start + * Service. Then the system calls back the current method to use the transferred want parameter to execute its own + * logic. + * + * @param want Indicates the want of Service to start. + * @param restart Indicates the startup mode. The value true indicates that Service is restarted after being + * destroyed, and the value false indicates a normal startup. + * @param startId Indicates the number of times the Service extension has been started. The startId is incremented + * by 1 every time the extension is started. For example, if the extension has been started for six times, the + * value of startId is 6. + */ + virtual void OnCommand(const AAFwk::Want &want, bool restart, int startId) override; + + /** + * @brief Called when this extension enters the STATE_STOP state. + * + * The extension in the STATE_STOP is being destroyed. + * You can override this function to implement your own processing logic. + */ + virtual void OnStop() override; + + /** + * @brief Called when the system configuration is updated. + * + * @param configuration Indicates the updated configuration information. + */ + void OnConfigurationUpdated(const AppExecFwk::Configuration &configuration) override; + + /** + * @brief Called when extension need dump info. + * + * @param params The params from service. + * @param info The dump info to show. + */ + virtual void Dump(const std::vector ¶ms, std::vector &info) override; + +private: + void ConfigurationUpdated(); + ani_ref CallObjectMethod(bool withResult, const char *name, const char *signature, ...); + sptr OnConnectInner(ani_env *env, ani_object &aniRemoteobj, bool &isAsyncCallback); + + ETSRuntime &etsRuntime_; + std::unique_ptr etsObj_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_SERVICE_EXTENSION_H \ No newline at end of file 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 new file mode 100644 index 00000000000..099d12a309a --- /dev/null +++ b/frameworks/ets/ani/service_extension_ability/src/ets_service_extension.cpp @@ -0,0 +1,394 @@ +/* + * 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_service_extension.h" + +#include "ability_info.h" +#include "ability_manager_client.h" +#include "ani_common_want.h" +#include "ani_remote_object.h" +#include "configuration_utils.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" +#include "js_service_extension_context.h" + +namespace OHOS { +namespace AbilityRuntime { +using namespace OHOS::AppExecFwk; +namespace { +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 *ON_DISCONNECT_SIGNATURE = "L@ohos/app/ability/Want/Want;:V"; +constexpr const char *ON_REQUEST_SIGNATURE = "L@ohos/app/ability/Want/Want;D:V"; + +void DisconnectPromiseCallback(ani_env *env, ani_object aniObj) +{ + TAG_LOGD(AAFwkTag::SERVICE_EXT, "DisconnectPromiseCallback"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return; + } + ani_long disconnectCallbackPoint = 0; + ani_status status = ANI_ERROR; + if ((status = env->Object_GetFieldByName_Long(aniObj, "disconnectCallbackPoint", &disconnectCallbackPoint)) != + ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return; + } + auto *callbackInfo = reinterpret_cast *>(disconnectCallbackPoint); + if (callbackInfo == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null callbackInfo"); + return; + } + callbackInfo->Call(); + AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo); +} + +void ConnectPromiseCallback(ani_env *env, ani_object aniObj, ani_object obj) +{ + TAG_LOGD(AAFwkTag::SERVICE_EXT, "ConnectPromiseCallback"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return; + } + ani_long connectCallbackPoint = 0; + ani_status status = ANI_ERROR; + if ((status = env->Object_GetFieldByName_Long(aniObj, "connectCallbackPoint", &connectCallbackPoint)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return; + } + auto remoteObject = AniGetNativeRemoteObject(env, obj); + if (remoteObject == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null remoteObject"); + } + auto *callbackInfo = + reinterpret_cast> *>(connectCallbackPoint); + if (callbackInfo == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null callbackInfo"); + return; + } + + callbackInfo->Call(remoteObject); + AppExecFwk::AbilityTransactionCallbackInfo>::Destroy(callbackInfo); +} +} // namespace + +EtsServiceExtension *EtsServiceExtension::Create(const std::unique_ptr &runtime) +{ + return new EtsServiceExtension(static_cast(*runtime)); +} + +EtsServiceExtension::EtsServiceExtension(ETSRuntime &etsRuntime) : etsRuntime_(etsRuntime) {} +EtsServiceExtension::~EtsServiceExtension() +{ + TAG_LOGD(AAFwkTag::SERVICE_EXT, "EtsServiceExtension destory"); + auto context = GetContext(); + if (context) { + context->Unbind(); + } +} + +void EtsServiceExtension::Init(const std::shared_ptr &record, + const std::shared_ptr &application, std::shared_ptr &handler, + const sptr &token) +{ + TAG_LOGD(AAFwkTag::SERVICE_EXT, "EtsServiceExtension init"); + if ((token == nullptr) || (application == nullptr) || (handler == nullptr) || (record == nullptr)) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "init failed, some obj null"); + return; + } + Extension::Init(record, application, handler, token); + if (Extension::abilityInfo_ == nullptr || Extension::abilityInfo_->srcEntrance.empty()) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "EtsServiceExtension Init abilityInfo error"); + return; + } + std::string srcPath(Extension::abilityInfo_->moduleName + "/"); + srcPath.append(Extension::abilityInfo_->srcEntrance); + auto pos = srcPath.rfind("."); + if (pos != std::string::npos) { + srcPath.erase(pos); + srcPath.append(".abc"); + } + std::string moduleName(Extension::abilityInfo_->moduleName); + moduleName.append("::").append(abilityInfo_->name); + etsObj_ = etsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath, + abilityInfo_->compileMode == AppExecFwk::CompileMode::ES_MODULE, false, abilityInfo_->srcEntrance); + if (etsObj_ == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null etsObj"); + return; + } + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return; + } + std::array functions = { + ani_native_function { + "nativeOnDisconnectCallback", VOID_SIGNATURE, reinterpret_cast(DisconnectPromiseCallback) }, + ani_native_function { "nativeOnConnectCallback", NATIVE_ONCONNECT_CALLBACK_SIGNATURE, + reinterpret_cast(ConnectPromiseCallback) }, + }; + ani_class cls = nullptr; + ani_status status = ANI_ERROR; + if ((status = env->FindClass(CLASSNAME_SERVICE_ABILITY, &cls)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status: %{public}d", status); + return; + } + if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "Class_BindNativeMethods is fail %{public}d", status); + return; + } +} + +void EtsServiceExtension::OnStart(const AAFwk::Want &want) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnStart"); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "env not found Ability.ets"); + return; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + if (wantRef == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null wantRef"); + return; + } + + CallObjectMethod(false, "onCreate", ON_CREATE_SIGNATURE, wantRef); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "end"); +} + +void EtsServiceExtension::OnStop() +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnStop"); + ServiceExtension::OnStop(); + CallObjectMethod(false, "onDestroy", VOID_SIGNATURE); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "end"); +} + +sptr EtsServiceExtension::OnConnect(const AAFwk::Want &want) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnConnect"); + Extension::OnConnect(want); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return nullptr; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + if (wantRef == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null wantRef"); + return nullptr; + } + ani_ref result = CallObjectMethod(true, "onConnect", ON_CONNECT_SIGNATURE, wantRef); + auto obj = reinterpret_cast(result); + auto remoteObj = AniGetNativeRemoteObject(env, obj); + if (remoteObj == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "remoteObj null"); + return nullptr; + } + TAG_LOGD(AAFwkTag::SERVICE_EXT, "end"); + return remoteObj; +} + +sptr EtsServiceExtension::OnConnect(const AAFwk::Want &want, + AppExecFwk::AbilityTransactionCallbackInfo> *callbackInfo, bool &isAsyncCallback) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnConnect"); + Extension::OnConnect(want); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return nullptr; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + if (wantRef == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null wantRef"); + return nullptr; + } + ani_long connectCallbackPoint = (ani_long)callbackInfo; + ani_status status = ANI_ERROR; + ani_field callbackField = nullptr; + if ((status = env->Class_FindField(etsObj_->aniCls, "connectCallbackPoint", &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) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return nullptr; + } + ani_ref aniRemoteRef = CallObjectMethod(true, "onConnect", ON_CONNECT_SIGNATURE, wantRef); + auto aniRemoteobj = reinterpret_cast(aniRemoteRef); + ani_method method {}; + if ((status = env->Class_FindMethod(etsObj_->aniCls, "checkPromise", CHECK_PROMISE_SIGNATURE, &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return nullptr; + } + ani_boolean isPromise = false; + if ((status = env->Object_CallMethod_Boolean(etsObj_->aniObj, method, &isPromise, aniRemoteobj)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return nullptr; + } + if (!isPromise) { + isAsyncCallback = false; + auto remoteObj = AniGetNativeRemoteObject(env, aniRemoteobj); + if (remoteObj == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null remoteObj"); + } + return remoteObj; + } + return OnConnectInner(env, aniRemoteobj, isAsyncCallback); +} + +sptr EtsServiceExtension::OnConnectInner(ani_env *env, ani_object &aniRemoteobj, bool &isAsyncCallback) +{ + ani_status status = ANI_ERROR; + ani_method method {}; + if ((status = env->Class_FindMethod(etsObj_->aniCls, "callPromise", CALL_PROMISE_SIGNATURE, &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return nullptr; + } + ani_boolean callResult = 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; + } + isAsyncCallback = callResult; + return nullptr; +} + +void EtsServiceExtension::OnDisconnect(const AAFwk::Want &want) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnDisconnect"); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + if (wantRef == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null wantRef"); + return; + } + CallObjectMethod(false, "onDisconnect", ON_DISCONNECT_SIGNATURE, wantRef); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "end"); +} + +void EtsServiceExtension::OnDisconnect( + const AAFwk::Want &want, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnDisconnect"); + auto env = etsRuntime_.GetAniEnv(); + if (env) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + if (wantRef == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null wantRef"); + return; + } + if (callbackInfo == nullptr) { + isAsyncCallback = false; + OnDisconnect(want); + return; + } + ani_long disconnectCallbackPoint = (ani_long)callbackInfo; + ani_status status = ANI_ERROR; + ani_field field = nullptr; + if ((status = env->Class_FindField(etsObj_->aniCls, "disconnectCallbackPoint", &field)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return; + } + if ((status = env->Object_SetField_Long(etsObj_->aniObj, field, disconnectCallbackPoint)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return; + } + CallObjectMethod(false, "callOnDisconnect", ON_DISCONNECT_SIGNATURE, wantRef); +} + +void EtsServiceExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnCommand"); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return; + } + ani_ref wantRef = OHOS::AppExecFwk::WrapWant(env, want); + if (wantRef == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null wantRef"); + return; + } + ani_int iStartId = static_cast(startId); + CallObjectMethod(false, "onRequest", ON_REQUEST_SIGNATURE, wantRef, iStartId); + TAG_LOGD(AAFwkTag::SERVICE_EXT, "end"); + return; +} + +ani_ref EtsServiceExtension::CallObjectMethod(bool withResult, const char *name, const char *signature, ...) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, std::string("CallObjectMethod:") + name); + ani_status status = ANI_ERROR; + ani_method method = nullptr; + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "null env"); + return nullptr; + } + if ((status = env->Class_FindMethod(etsObj_->aniCls, name, signature, &method)) != ANI_OK) { + return nullptr; + } + if (method == nullptr) { + return nullptr; + } + ani_ref res = nullptr; + va_list args; + if (withResult) { + va_start(args, signature); + if ((status = env->Object_CallMethod_Ref_V(etsObj_->aniObj, method, &res, args)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + return nullptr; + } + va_end(args); + return res; + } + va_start(args, signature); + if ((status = env->Object_CallMethod_Void_V(etsObj_->aniObj, method, args)) != ANI_OK) { + TAG_LOGE(AAFwkTag::SERVICE_EXT, "status : %{public}d", status); + } + va_end(args); + return nullptr; +} +void EtsServiceExtension::OnConfigurationUpdated(const AppExecFwk::Configuration &configuration) {} + +void EtsServiceExtension::ConfigurationUpdated() {} + +void EtsServiceExtension::Dump(const std::vector ¶ms, std::vector &info) {} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension.h b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension.h index 113de735159..09458863ad7 100644 --- a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension.h +++ b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension.h @@ -177,10 +177,8 @@ public: void ConfigurationUpdated(); private: - virtual void BindContext(ani_env *env, std::shared_ptr want, - const std::shared_ptr &application); - ani_object CreateETSContext(ani_env *env, std::shared_ptr context, - int32_t screenMode, const std::shared_ptr &application); + virtual void BindContext(ani_env *env, std::shared_ptr want); + ani_object CreateETSContext(ani_env *env, std::shared_ptr context, int32_t screenMode); bool CallObjectMethod(bool withResult, const char* name, const char* signature, ...); diff --git a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_content_session.h b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_content_session.h index 877ccd402b5..a7828e853b5 100644 --- a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_content_session.h +++ b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_content_session.h @@ -19,7 +19,7 @@ #include "session_info.h" #include "start_options.h" #include "window.h" -#include "sts_runtime.h" +#include "ets_runtime.h" namespace OHOS { namespace AbilityRuntime { @@ -66,7 +66,7 @@ public: sptr uiWindow); virtual ~EtsUIExtensionContentSession() = default; static EtsUIExtensionContentSession* GetEtsContentSession(ani_env* env, ani_object obj); - static ani_object CreateStsUIExtensionContentSession(ani_env* env, + static ani_object CreateEtsUIExtensionContentSession(ani_env* env, sptr sessionInfo, sptr uiWindow, std::weak_ptr context, std::shared_ptr& abilityResultListeners, diff --git a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h index ef7e5f67979..802402b7b05 100644 --- a/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h +++ b/frameworks/ets/ani/ui_extension_ability/include/ets_ui_extension_context.h @@ -15,7 +15,7 @@ #ifndef OHOS_ABILITY_RUNTIME_ETS_UI_EXTENSION_CONTEXT_H #define OHOS_ABILITY_RUNTIME_ETS_UI_EXTENSION_CONTEXT_H -#include "sts_runtime.h" +#include "ets_runtime.h" #include #include #include @@ -24,9 +24,7 @@ #include "hitrace_meter.h" #include "ohos_application.h" -ani_object CreateEtsUIExtensionContext(ani_env *env, - std::shared_ptr context, - const std::shared_ptr &application); +ani_object CreateEtsUIExtensionContext(ani_env *env, std::shared_ptr context); class EtsUIExtensionContext final { public: @@ -38,7 +36,7 @@ public: static void TerminateSelfWithResultSync(ani_env *env, ani_object obj, ani_object abilityResult, ani_object callback); static void EtsCreatExtensionContext(ani_env* aniEnv, ani_class contextClass, ani_object contextObj, - void* applicationCtxRef, std::shared_ptr context); + std::shared_ptr context); private: static void BindExtensionInfo(ani_env* aniEnv, ani_class contextClass, ani_object contextObj, std::shared_ptr context, std::shared_ptr abilityInfo); diff --git a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension.cpp b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension.cpp index 0361069d854..b992ef6bff4 100644 --- a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension.cpp +++ b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension.cpp @@ -24,8 +24,6 @@ #include "context.h" #include "hitrace_meter.h" #include "hilog_tag_wrapper.h" -#include "insight_intent_executor_info.h" -#include "insight_intent_executor_mgr.h" #include "int_wrapper.h" #include "ets_runtime.h" #include "ani_common_want.h" @@ -132,19 +130,18 @@ void EtsUIExtension::Init(const std::shared_ptr &record, if ((status = env->Class_BindNativeMethods(etsObj_->aniCls, functions.data(), functions.size())) != ANI_OK) { TAG_LOGE(AAFwkTag::UI_EXT, "status: %{public}d", status); } - BindContext(env, record->GetWant(), application); + BindContext(env, record->GetWant()); RegisterDisplayInfoChangedListener(); } -ani_object EtsUIExtension::CreateETSContext(ani_env* env, std::shared_ptr context, - int32_t screenMode, const std::shared_ptr &application) +ani_object EtsUIExtension::CreateETSContext(ani_env* env, + std::shared_ptr context, int32_t screenMode) { - ani_object obj = CreateEtsUIExtensionContext(env, context, application); + ani_object obj = CreateEtsUIExtensionContext(env, context); return obj; } -void EtsUIExtension::BindContext(ani_env*env, std::shared_ptr want, - const std::shared_ptr &application) +void EtsUIExtension::BindContext(ani_env*env, std::shared_ptr want) { if (env == nullptr || want == nullptr) { TAG_LOGE(AAFwkTag::UI_EXT, "Want info is null or env is null"); @@ -158,7 +155,7 @@ void EtsUIExtension::BindContext(ani_env*env, std::shared_ptr want, } int32_t screenMode = want->GetIntParam(AAFwk::SCREEN_MODE_KEY, AAFwk::IDLE_SCREEN_MODE); - ani_object contextObj = CreateETSContext(env, context, screenMode, application); + ani_object contextObj = CreateETSContext(env, context, screenMode); if (contextObj == nullptr) { TAG_LOGE(AAFwkTag::UI_EXT, "null contextObj"); return; diff --git a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp index 44025a26d3e..34dc8e4d11d 100644 --- a/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp +++ b/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp @@ -19,7 +19,6 @@ #include "ability_manager_client.h" #include "ets_context_utils.h" #include "ets_error_utils.h" -#include "ets_ui_extension_common.h" const char *INVOKE_METHOD_NAME = "invoke"; const char *UI_EXTENSION_CONTEXT_CLASS_NAME = "Lapplication/UIExtensionContext/UIExtensionContext;"; @@ -45,8 +44,8 @@ void EtsUIExtensionContext::TerminateSelfSync(ani_env *env, ani_object obj, ani_ return; } ret = ((OHOS::AbilityRuntime::UIExtensionContext*)nativeContextLong)->TerminateSelf(); - AppExecFwk::AsyncCallback(env, callback, - CreateEtsErrorByNativeErr(env, static_cast(ret)), nullptr); + OHOS::AppExecFwk::AsyncCallback(env, callback, + OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, static_cast(ret)), nullptr); } void EtsUIExtensionContext::TerminateSelfWithResultSync(ani_env *env, ani_object obj, @@ -86,8 +85,8 @@ void EtsUIExtensionContext::TerminateSelfWithResultSync(ani_env *env, ani_objec TAG_LOGE(AAFwkTag::UI_EXT, "TerminateSelf failed, errorCode is %{public}d", ret); return; } - AppExecFwk::AsyncCallback(env, callback, - CreateEtsErrorByNativeErr(env, static_cast(ret)), nullptr); + OHOS::AppExecFwk::AsyncCallback(env, callback, + OHOS::AbilityRuntime::CreateEtsErrorByNativeErr(env, static_cast(ret)), nullptr); } void EtsUIExtensionContext::BindExtensionInfo(ani_env* aniEnv, ani_class contextClass, ani_object contextObj, @@ -124,15 +123,13 @@ void EtsUIExtensionContext::BindExtensionInfo(ani_env* aniEnv, ani_class context } void EtsUIExtensionContext::EtsCreatExtensionContext(ani_env* aniEnv, ani_class contextClass, ani_object contextObj, - void* applicationCtxRef, std::shared_ptr context) + std::shared_ptr context) { - OHOS::AbilityRuntime::ContextUtil::EtsCreatContext(aniEnv, contextClass, contextObj, applicationCtxRef, context); + OHOS::AbilityRuntime::ContextUtil::CreateEtsBaseContext(aniEnv, contextClass, contextObj, context); BindExtensionInfo(aniEnv, contextClass, contextObj, context, context->GetAbilityInfo()); } -ani_object CreateEtsUIExtensionContext(ani_env *env, - std::shared_ptr context, - const std::shared_ptr &application) +ani_object CreateEtsUIExtensionContext(ani_env *env, std::shared_ptr context) { TAG_LOGD(AAFwkTag::UI_EXT, "called"); ani_class cls = nullptr; @@ -171,13 +168,6 @@ ani_object CreateEtsUIExtensionContext(ani_env *env, TAG_LOGE(AAFwkTag::UI_EXT, "status: %{public}d", status); return nullptr; } - - // bind parent context - if (application == nullptr) { - TAG_LOGE(AAFwkTag::UI_EXT, "application null"); - return nullptr; - } - EtsUIExtensionContext::EtsCreatExtensionContext(env, cls, contextObj, - application->GetApplicationCtxObjRef(), context); + EtsUIExtensionContext::EtsCreatExtensionContext(env, cls, contextObj, context); return contextObj; } diff --git a/frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets b/frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets new file mode 100644 index 00000000000..c17298b63eb --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.ServiceExtensionAbility.ets @@ -0,0 +1,97 @@ +/* + * 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 rpc from '@ohos.rpc'; +import Want from '@ohos.app.ability.Want'; +import ServiceExtensionContext from 'application.ServiceExtensionContext'; +import { Configuration } from '@ohos.app.ability.Configuration' +import hilog from '@ohos.hilog'; + +class MyService extends rpc.RemoteObject { + constructor(descriptor: string) { + super(descriptor); + } + + public onRemoteMessageRequest( + code: number, + data: rpc.MessageSequence, + reply: rpc.MessageSequence, + options: rpc.MessageOption + ): boolean | Promise { + return false; + } +} + +export default class ServiceExtensionAbility { + private connectCallbackPoint: long; + + private native nativeOnConnectCallback(service: rpc.RemoteObject): boolean; + + private checkPromise(obj: NullishType): boolean { + if (obj instanceof Promise) { + return true; + } + return false; + } + + private callPromise(p: Promise): boolean { + let remoteObj: rpc.RemoteObject = await p; + return this.nativeOnConnectCallback(remoteObj); + } + + private isOnDisconnectAsync: boolean = true; + private disconnectCallbackPoint: 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 { + this.onDisconnect(want); + } + } + + launchWant: Want = new Want(); + lastRequestWant: Want = new Want(); + context: ServiceExtensionContext = {}; + + onCreate(want: Want): void { + } + + onDestroy(): void { + } + + onRequest(want: Want, startld: double): void { + } + + onConnect(want: Want): rpc.RemoteObject | Promise { + let myService: rpc.RemoteObject = new MyService("onConnect"); + return myService; + } + + onDisconnect(want: Want): void { + } + + onDisconnectAsync(want: Want): Promise { + console.log("onDisconnectAsync"); + this.isOnDisconnectAsync = false; + return new Promise((resolve: (a: undefined) => void, reject: (err: Error) => void): void => { + }); + } +} \ No newline at end of file diff --git a/frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets b/frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets new file mode 100644 index 00000000000..039352f8371 --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.abilityDelegatorRegistry.ets @@ -0,0 +1,28 @@ +/* + * 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 { AbilityDelegator as _AbilityDelegator } from 'application.AbilityDelegator'; +import { AbilityDelegatorArgs as _AbilityDelegatorArgs } from 'application.abilityDelegatorArgs'; + +export default namespace abilityDelegatorRegistry { + loadLibrary("ability_delegator_registry_ani_kit.z") + + export native function getAbilityDelegator(): AbilityDelegator; + + export native function getArguments(): AbilityDelegatorArgs; + + export type AbilityDelegator = _AbilityDelegator; + export type AbilityDelegatorArgs = _AbilityDelegatorArgs; +} diff --git a/frameworks/ets/ets/@ohos.application.testRunner.ets b/frameworks/ets/ets/@ohos.application.testRunner.ets new file mode 100644 index 00000000000..84c032547f1 --- /dev/null +++ b/frameworks/ets/ets/@ohos.application.testRunner.ets @@ -0,0 +1,19 @@ +/* + * 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. + */ + +export default interface TestRunner { + onPrepare(): void; + onRun(): void; +} diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index fe486b15d54..74866580771 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -210,6 +210,65 @@ ohos_prebuilt_etc("ability_runtime_ability_result_abc_etc") { deps = [ ":ability_runtime_ability_result_abc" ] } +generate_static_abc("service_extension_ability") { + base_url = "./" + files = [ + "./@ohos.app.ability.ServiceExtensionAbility.ets", + "./application/ServiceExtensionContext.ets", + ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/service_extension_ability.abc" +} + +ohos_prebuilt_etc("service_extension_ability_abc_etc") { + source = "$target_out_dir/service_extension_ability.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":service_extension_ability" ] +} + +generate_static_abc("ui_extension_ability_ani_abc") { + base_url = "./" + + files = [ + "./application/UIExtensionContext.ets", + "./@ohos.app.ability.UIExtensionAbility.ets", + "./@ohos.app.ability.UIExtensionContentSession.ets", + ] + + dst_file = "$target_out_dir/ui_extension_ability_ani.abc" + out_puts = [ "$target_out_dir/ui_extension_ability_ani.abc" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ui_extension_ability_ani.abc" +} + +ohos_prebuilt_etc("ui_extension_ability_ani_etc") { + source = "$target_out_dir/ui_extension_ability_ani.abc" + deps = [ ":ui_extension_ability_ani_abc" ] + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" +} + +generate_static_abc("ability_runtime_ability_stage_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.AbilityStage.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_runtime_ability_stage_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_ability_stage_abc_etc") { + source = "$target_out_dir/ability_runtime_ability_stage_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_ability_stage_abc" ] +} + generate_static_abc("ability_runtime_ui_ability_abc") { base_url = "./" files = [ "./@ohos.app.ability.UIAbility.ets" ] @@ -243,21 +302,129 @@ ohos_prebuilt_etc("ability_runtime_ui_ability_context_abc_etc") { deps = [ ":ability_runtime_ui_ability_context_abc" ] } +generate_static_abc("ability_delegator_application_testRunner_abc") { + base_url = "./" + files = [ "./@ohos.application.testRunner.ets" ] + + is_boot_abc = "True" + device_dst_file = + "/system/framework/ability_delegator_application_testRunner_abc.abc" +} + +ohos_prebuilt_etc("ability_delegator_application_testRunner_abc_etc") { + source = "$target_out_dir/ability_delegator_application_testRunner_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_delegator_application_testRunner_abc" ] +} + +generate_static_abc("ability_delegator_registry_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.abilityDelegatorRegistry.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_delegator_registry_abc.abc" +} + +ohos_prebuilt_etc("ability_delegator_registry_abc_etc") { + source = "$target_out_dir/ability_delegator_registry_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_delegator_registry_abc" ] +} + +generate_static_abc("ability_delegator_abc") { + base_url = "./" + files = [ "./application/AbilityDelegator.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_delegator_abc.abc" +} + +ohos_prebuilt_etc("ability_delegator_abc_etc") { + source = "$target_out_dir/ability_delegator_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_delegator_abc" ] +} + +generate_static_abc("ability_delegator_args_abc") { + base_url = "./" + files = [ "./application/abilityDelegatorArgs.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/ability_delegator_args_abc.abc" +} + +ohos_prebuilt_etc("ability_delegator_args_abc_etc") { + source = "$target_out_dir/ability_delegator_args_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_delegator_args_abc" ] +} + +generate_static_abc("ability_delegator_ability_monitor_abc") { + base_url = "." + files = [ "./application/AbilityMonitor.ets" ] + + is_boot_abc = "True" + device_dst_file = + "/system/framework/ability_delegator_ability_monitor_abc.abc" +} + +ohos_prebuilt_etc("ability_delegator_ability_monitor_abc_etc") { + source = "$target_out_dir/ability_delegator_ability_monitor_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_delegator_ability_monitor_abc" ] +} + +generate_static_abc("ability_runtime_shell_cmd_result_abc") { + base_url = "./" + files = [ "./application/shellCmdResult.ets" ] + + is_boot_abc = "True" + device_dst_file = + "/system/framework/ability_runtime_shell_cmd_result_abc.abc" +} + +ohos_prebuilt_etc("ability_runtime_shell_cmd_result_abc_etc") { + source = "$target_out_dir/ability_runtime_shell_cmd_result_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":ability_runtime_shell_cmd_result_abc" ] +} + group("ets_packages") { deps = [ - ":ability_runtime_ability_result_abc_etc", + ":ability_delegator_abc_etc", + ":ability_delegator_ability_monitor_abc_etc", + ":ability_delegator_application_testRunner_abc_etc", + ":ability_delegator_args_abc_etc", + ":ability_delegator_registry_abc_etc", + ":ability_runtime_shell_cmd_result_abc_etc", ":ability_runtime_ability_constant_abc_etc", + ":ability_runtime_ability_result_abc_etc", + ":ability_runtime_ability_stage_abc_etc", ":ability_runtime_ability_utils_abc_etc", - ":ability_runtime_base_context_abc_etc", ":ability_runtime_application_context_abc_etc", + ":ability_runtime_base_context_abc_etc", ":ability_runtime_configuration_abc_etc", ":ability_runtime_configuration_constant_abc_etc", ":ability_runtime_context_abc_etc", + ":ability_runtime_extension_context_abc_etc", ":ability_runtime_start_options_abc_etc", ":ability_runtime_want_abc_etc", ":ability_runtime_want_constant_abc_etc", - ":ability_runtime_extension_context_abc_etc", ":ability_runtime_ui_ability_abc_etc", ":ability_runtime_ui_ability_context_abc_etc", + ":service_extension_ability_abc_etc", + ":ui_extension_ability_ani_etc", ] } diff --git a/frameworks/ets/ets/application/AbilityDelegator.ets b/frameworks/ets/ets/application/AbilityDelegator.ets new file mode 100644 index 00000000000..568379f2c76 --- /dev/null +++ b/frameworks/ets/ets/application/AbilityDelegator.ets @@ -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. + */ + +import { AbilityMonitor } from 'application.AbilityMonitor'; +import Want from '@ohos.app.ability.Want'; +import Context from 'application.Context'; +import { BusinessError, AsyncCallback } from '@ohos.base'; +import { ShellCmdResult } from 'application.shellCmdResult'; +import AsyncCallbackWrapper from '../utils/AbilityUtils'; + +export interface AbilityDelegator { + printSync(msg: string): void; + + getAppContext(): Context; + + finishTest(msg: string, code: number, callback: AsyncCallback): void; + + finishTest(msg: string, code: number): Promise; + + executeShellCommand(cmd: String, callback: AsyncCallback): void; + + executeShellCommand(cmd: String, timeoutSecs: number, callback: AsyncCallback): void; + + executeShellCommand(cmd: string, timeoutSecs?: number): Promise; + + addAbilityMonitor(monitor: AbilityMonitor, callback: AsyncCallback): void; + + addAbilityMonitor(monitor: AbilityMonitor): Promise; + + startAbility(want: Want, callback: AsyncCallback): void; + + startAbility(want: Want): Promise; +} + +class AbilityDelegatorInner implements AbilityDelegator { + + public native printSync(msg: string): void; + + public native getAppContext(): Context; + + public native nativeFinishTest(msg: String, code: number, callback: AsyncCallbackWrapper): void; + + public native nativeExecuteShellCommand(cmd: string, timeoutSecs: number, + callback: AsyncCallbackWrapper): void; + + public native nativeAddAbilityMonitor(monitor: AbilityMonitor, callback: AsyncCallbackWrapper): void; + + public native nativeStartAbility(want: Want, callback: AsyncCallbackWrapper): void; + + finishTest(msg: string, code: number, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeFinishTest(msg, code, myCall); + }); + } + finishTest(msg: string, code: number): Promise { + let p: Promise = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError) => { + if (err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeFinishTest(msg, code, myCall); + }); + }); + return p; + } + + executeShellCommand(cmd: string, callback: AsyncCallback): void { + let timeoutSecs = 0; + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeExecuteShellCommand(cmd, timeoutSecs, myCall); + }); + } + executeShellCommand(cmd: string, timeoutSecs: number, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeExecuteShellCommand(cmd, timeoutSecs, myCall); + }); + } + executeShellCommand(cmd: string, timeoutSecs?: number): Promise { + let p = new Promise((resolve: (data: ShellCmdResult) => void, + reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError, data: ShellCmdResult) => { + if (err.code == 0) { + resolve(data); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + if (timeoutSecs == null) { + this.nativeExecuteShellCommand(cmd, 0, myCall); + } else { + this.nativeExecuteShellCommand(cmd, timeoutSecs as double, myCall); + } + }); + }); + return p; + } + + addAbilityMonitor(monitor: AbilityMonitor, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeAddAbilityMonitor(monitor, myCall); + }); + } + addAbilityMonitor(monitor: AbilityMonitor): Promise { + let p = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError) => { + if (err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeAddAbilityMonitor(monitor, myCall); + }); + }); + return p; + } + + startAbility(want: Want, callback: AsyncCallback): void { + let myCall = new AsyncCallbackWrapper(callback); + taskpool.execute((): void => { + this.nativeStartAbility(want, myCall); + }); + } + startAbility(want: Want): Promise { + let p: Promise = + new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let myCall = new AsyncCallbackWrapper((err: BusinessError) => { + if (err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeStartAbility(want, myCall); + }); + }); + return p; + } + +} diff --git a/frameworks/ets/ets/application/AbilityMonitor.ets b/frameworks/ets/ets/application/AbilityMonitor.ets new file mode 100644 index 00000000000..cccdd0e60f4 --- /dev/null +++ b/frameworks/ets/ets/application/AbilityMonitor.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 AbilityMonitor { + + 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 AbilityMonitorInner implements AbilityMonitor { + 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) => { + }; +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/ExtensionContext.ets b/frameworks/ets/ets/application/ExtensionContext.ets index 2d46b66d2ad..4b6cbf03130 100644 --- a/frameworks/ets/ets/application/ExtensionContext.ets +++ b/frameworks/ets/ets/application/ExtensionContext.ets @@ -17,6 +17,9 @@ import Context from 'application.Context' import {ExtensionAbilityInfo} from 'bundleManager.ExtensionAbilityInfo' export default class ExtensionContext extends Context { + static { + loadLibrary("context_ani"); + } extensionAbilityInfo: ExtensionAbilityInfo; native constructor(); constructor(extensionAbilityInfo: ExtensionAbilityInfo) { diff --git a/frameworks/ets/ets/application/ServiceExtensionContext.ets b/frameworks/ets/ets/application/ServiceExtensionContext.ets new file mode 100644 index 00000000000..8c9fe395ffa --- /dev/null +++ b/frameworks/ets/ets/application/ServiceExtensionContext.ets @@ -0,0 +1,19 @@ +/* + * 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 ExtensionContext from 'application.ExtensionContext' + +export default class ServiceExtensionContext extends ExtensionContext { + +} \ No newline at end of file diff --git a/frameworks/ets/ets/application/abilityDelegatorArgs.ets b/frameworks/ets/ets/application/abilityDelegatorArgs.ets new file mode 100644 index 00000000000..81c1bd06670 --- /dev/null +++ b/frameworks/ets/ets/application/abilityDelegatorArgs.ets @@ -0,0 +1,28 @@ +/* + * 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. + */ + +export interface AbilityDelegatorArgs { + bundleName: string; + parameters: Record; + testCaseNames: string; + testRunnerClassName: string; + } + + class AbilityDelegatorArgsInner implements AbilityDelegatorArgs { + public bundleName: string = ''; + public parameters: Record = {}; + public testCaseNames: string = ''; + public testRunnerClassName: string = ''; + } diff --git a/frameworks/ets/ets/application/shellCmdResult.ets b/frameworks/ets/ets/application/shellCmdResult.ets new file mode 100644 index 00000000000..5250b377d4d --- /dev/null +++ b/frameworks/ets/ets/application/shellCmdResult.ets @@ -0,0 +1,26 @@ +/* + * 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. + */ + +interface ShellCmdResult { + stdResult: string; + exitCode: number; + } + + class ShellCmdResultImpl implements ShellCmdResult { + public stdResult: string = ''; + public exitCode: number = 0; + } + + export default ShellCmdResult; diff --git a/frameworks/ets/ets/utils/AbilityUtils.ets b/frameworks/ets/ets/utils/AbilityUtils.ets index 573c5d3a207..989136ed5b6 100644 --- a/frameworks/ets/ets/utils/AbilityUtils.ets +++ b/frameworks/ets/ets/utils/AbilityUtils.ets @@ -12,13 +12,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { BusinessError, AsyncCallback } from '@ohos.base'; import hilog from '@ohos.hilog' const DOMAIN_ID = 0xD001300; const TAG = 'AbilityUtils'; const LEVEL = 100; +export default class AsyncCallbackWrapper { + private myFun_:AsyncCallback = (err: BusinessError, data: T) => {} + + constructor(myFun:AsyncCallback){ + this.myFun_ = myFun; + } + + invoke(err: BusinessError, data: T) : void { + this.myFun_(err, data); + } +} + export class AbilityUtils { public static getClassType(obj: Object): ClassType | undefined { try { diff --git a/frameworks/js/napi/app/ability_delegator/ability_monitor.cpp b/frameworks/js/napi/app/ability_delegator/ability_monitor.cpp index 5eab898a5a9..950c81b07a0 100644 --- a/frameworks/js/napi/app/ability_delegator/ability_monitor.cpp +++ b/frameworks/js/napi/app/ability_delegator/ability_monitor.cpp @@ -32,82 +32,138 @@ AbilityMonitor::AbilityMonitor(const std::string &name, const std::string &modul : IAbilityMonitor(name, moduleName), jsMonitor_(jsAbilityMonitor) {} -void AbilityMonitor::OnAbilityStart(const std::weak_ptr &abilityObj) +void AbilityMonitor::OnAbilityStart(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return; + } + auto jsbaseProperty = std::static_pointer_cast(baseProperty); + if (jsMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsMonitor_ is nullptr"); return; } - jsMonitor_->OnAbilityCreate(abilityObj); + jsMonitor_->OnAbilityCreate(jsbaseProperty->object_); } -void AbilityMonitor::OnAbilityForeground(const std::weak_ptr &abilityObj) +void AbilityMonitor::OnAbilityForeground(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return; + } + auto jsbaseProperty = std::static_pointer_cast(baseProperty); + if (jsMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsMonitor_ is nullptr"); return; } - jsMonitor_->OnAbilityForeground(abilityObj); + jsMonitor_->OnAbilityForeground(jsbaseProperty->object_); } -void AbilityMonitor::OnAbilityBackground(const std::weak_ptr &abilityObj) +void AbilityMonitor::OnAbilityBackground(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return; + } + auto jsbaseProperty = std::static_pointer_cast(baseProperty); + if (jsMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsMonitor_ is nullptr"); return; } - jsMonitor_->OnAbilityBackground(abilityObj); + jsMonitor_->OnAbilityBackground(jsbaseProperty->object_); } -void AbilityMonitor::OnAbilityStop(const std::weak_ptr &abilityObj) +void AbilityMonitor::OnAbilityStop(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return; + } + auto jsbaseProperty = std::static_pointer_cast(baseProperty); + if (jsMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsMonitor_ is nullptr"); return; } - jsMonitor_->OnAbilityDestroy(abilityObj); + jsMonitor_->OnAbilityDestroy(jsbaseProperty->object_); } -void AbilityMonitor::OnWindowStageCreate(const std::weak_ptr &abilityObj) +void AbilityMonitor::OnWindowStageCreate(const std::weak_ptr &abilityObj) { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return; + } + auto jsbaseProperty = std::static_pointer_cast(baseProperty); + if (jsMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsMonitor_ is nullptr"); return; } - jsMonitor_->OnWindowStageCreate(abilityObj); + jsMonitor_->OnWindowStageCreate(jsbaseProperty->object_); } -void AbilityMonitor::OnWindowStageRestore(const std::weak_ptr &abilityObj) +void AbilityMonitor::OnWindowStageRestore(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return; + } + auto jsbaseProperty = std::static_pointer_cast(baseProperty); + if (jsMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsMonitor_ is nullptr"); return; } - jsMonitor_->OnWindowStageRestore(abilityObj); + jsMonitor_->OnWindowStageRestore(jsbaseProperty->object_); } -void AbilityMonitor::OnWindowStageDestroy(const std::weak_ptr &abilityObj) +void AbilityMonitor::OnWindowStageDestroy(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); + auto baseProperty = abilityObj.lock(); + if (!baseProperty) { + TAG_LOGE(AAFwkTag::DELEGATOR, "abilityObj is expired"); + return; + } + auto jsbaseProperty = std::static_pointer_cast(baseProperty); + if (jsMonitor_ == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "jsMonitor_ is nullptr"); return; } - jsMonitor_->OnWindowStageDestroy(abilityObj); + jsMonitor_->OnWindowStageDestroy(jsbaseProperty->object_); } } // namespace AbilityDelegatorJs } // namespace OHOS diff --git a/frameworks/js/napi/app/ability_delegator/ability_monitor.h b/frameworks/js/napi/app/ability_delegator/ability_monitor.h index 433a48b4828..37bb4b5b2fb 100644 --- a/frameworks/js/napi/app/ability_delegator/ability_monitor.h +++ b/frameworks/js/napi/app/ability_delegator/ability_monitor.h @@ -56,49 +56,49 @@ public: * * @param abilityObj Indicates the ability object. */ - void OnAbilityStart(const std::weak_ptr &abilityObj) override; + void OnAbilityStart(const std::weak_ptr &abilityObj) override; /** * Called when ability is in foreground. * * @param abilityObj Indicates the ability object. */ - void OnAbilityForeground(const std::weak_ptr &abilityObj) override; + void OnAbilityForeground(const std::weak_ptr &abilityObj) override; /** * Called when ability is in background. * * @param abilityObj Indicates the ability object. */ - void OnAbilityBackground(const std::weak_ptr &abilityObj) override; + void OnAbilityBackground(const std::weak_ptr &abilityObj) override; /** * Called when ability is stopped. * * @param abilityObj Indicates the ability object. */ - void OnAbilityStop(const std::weak_ptr &abilityObj) override; + void OnAbilityStop(const std::weak_ptr &abilityObj) override; /** * Called when window stage is created. * * @param abilityObj Indicates the ability object. */ - void OnWindowStageCreate(const std::weak_ptr &abilityObj) override; + void OnWindowStageCreate(const std::weak_ptr &abilityObj) override; /** * Called when window stage is restored. * * @param abilityObj Indicates the ability object. */ - void OnWindowStageRestore(const std::weak_ptr &abilityObj) override; + void OnWindowStageRestore(const std::weak_ptr &abilityObj) override; /** * Called when window stage is destroyed. * * @param abilityObj Indicates the ability object. */ - void OnWindowStageDestroy(const std::weak_ptr &abilityObj) override; + void OnWindowStageDestroy(const std::weak_ptr &abilityObj) override; private: std::shared_ptr jsMonitor_; 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 b150907480c..34e943e9bd0 100644 --- a/frameworks/js/napi/app/ability_delegator/js_ability_delegator.cpp +++ b/frameworks/js/napi/app/ability_delegator/js_ability_delegator.cpp @@ -127,7 +127,8 @@ JSAbilityDelegator::JSAbilityDelegator() { auto delegator = AbilityDelegatorRegistry::GetAbilityDelegator(); if (delegator) { - auto clearFunc = [](const std::shared_ptr &property) { + auto clearFunc = [](const std::shared_ptr &baseProperty) { + auto property = std::static_pointer_cast(baseProperty); TAG_LOGI(AAFwkTag::DELEGATOR, "clearFunc called"); if (!property) { TAG_LOGE(AAFwkTag::DELEGATOR, "null property"); @@ -524,16 +525,17 @@ napi_value JSAbilityDelegator::OnWaitAbilityMonitor(napi_env env, NapiCallbackIn return; } - std::shared_ptr property = opt.hasTimeoutPara ? + std::shared_ptr property = opt.hasTimeoutPara ? delegator->WaitAbilityMonitor(monitor, timeout) : delegator->WaitAbilityMonitor(monitor); - if (!property || property->object_.expired()) { + auto jsProperty = std::static_pointer_cast(property); + if (!jsProperty || jsProperty->object_.expired()) { TAG_LOGE(AAFwkTag::DELEGATOR, "invalid property"); return; } - abilityObjectBox->object_ = property->object_; + abilityObjectBox->object_ = jsProperty->object_; std::unique_lock lck(g_mutexAbilityRecord); - g_abilityRecord.emplace(property->object_, property->token_); + g_abilityRecord.emplace(jsProperty->object_, jsProperty->token_); }; NapiAsyncTask::CompleteCallback complete = [abilityObjectBox](napi_env env, NapiAsyncTask &task, int32_t status) { @@ -795,15 +797,16 @@ napi_value JSAbilityDelegator::OnGetCurrentTopAbility(napi_env env, NapiCallback } auto property = delegator->GetCurrentTopAbility(); - if (!property || property->object_.expired()) { - TAG_LOGE(AAFwkTag::DELEGATOR, "invalid property"); + auto jsProperty = std::static_pointer_cast(property); + if (!jsProperty || jsProperty->object_.expired()) { + TAG_LOGE(AAFwkTag::DELEGATOR, "invalid jsProperty"); task.Reject(env, CreateJsError(env, COMMON_FAILED, "Calling GetCurrentTopAbility failed.")); } else { { std::unique_lock lck(g_mutexAbilityRecord); - g_abilityRecord.emplace(property->object_, property->token_); + g_abilityRecord.emplace(jsProperty->object_, jsProperty->token_); } - ResolveWithNoError(env, task, property->object_.lock()->GetNapiValue()); + ResolveWithNoError(env, task, jsProperty->object_.lock()->GetNapiValue()); } }; diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index 0981fde5253..fb693b45d7f 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -93,9 +93,7 @@ config("app_service_extension_public_config") { "${ability_runtime_services_path}/common/include", ] if (ability_runtime_graphics) { - defines = [ - "SUPPORT_GRAPHICS", - ] + defines = [ "SUPPORT_GRAPHICS" ] } } @@ -704,8 +702,8 @@ ohos_shared_library("insight_intent_executor") { sources = [ "${ability_runtime_native_path}/ability/native/insight_intent_executor/insight_intent_executor.cpp", "${ability_runtime_native_path}/ability/native/insight_intent_executor/insight_intent_executor_mgr.cpp", - "${ability_runtime_native_path}/ability/native/insight_intent_executor/js_insight_intent_executor.cpp", "${ability_runtime_native_path}/ability/native/insight_intent_executor/js_insight_intent_entry.cpp", + "${ability_runtime_native_path}/ability/native/insight_intent_executor/js_insight_intent_executor.cpp", "${ability_runtime_native_path}/ability/native/insight_intent_executor/js_insight_intent_func.cpp", "${ability_runtime_native_path}/ability/native/insight_intent_executor/js_insight_intent_page.cpp", "${ability_runtime_native_path}/ability/native/insight_intent_executor/js_insight_intent_utils.cpp", @@ -968,10 +966,10 @@ ohos_shared_library("form_extension") { sources = [ "${ability_runtime_native_path}/ability/native/form_extension.cpp", + "${ability_runtime_native_path}/ability/native/form_runtime/cj_form_extension_instance.cpp", "${ability_runtime_native_path}/ability/native/form_runtime/form_extension_provider_client.cpp", "${ability_runtime_native_path}/ability/native/form_runtime/js_form_extension.cpp", "${ability_runtime_native_path}/ability/native/form_runtime/js_form_extension_context.cpp", - "${ability_runtime_native_path}/ability/native/form_runtime/cj_form_extension_instance.cpp", "${ability_runtime_native_path}/appkit/ability_runtime/form_extension_context.cpp", ] @@ -1042,8 +1040,8 @@ ohos_shared_library("cj_form_extension") { ":form_extension", "${ability_runtime_innerkits_path}/runtime:runtime", "${ability_runtime_native_path}/ability:ability_context_native", - "${ability_runtime_native_path}/appkit:app_context", "${ability_runtime_native_path}/ability:cj_ability_context_native", + "${ability_runtime_native_path}/appkit:app_context", "${ability_runtime_path}/frameworks/cj/ffi:cj_ability_ffi", ] @@ -1123,6 +1121,8 @@ ohos_shared_library("service_extension") { defines = [ "AMS_LOG_TAG = \"Ability\"" ] defines += [ "AMS_LOG_DOMAIN = 0xD001300" ] include_dirs = [ + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", + "${ability_runtime_path}/frameworks/ets/ani/service_extension_ability/include", "${ability_runtime_path}/interfaces/kits/native/ability/native", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime", "${ability_runtime_path}/utils/global/freeze/include", @@ -1133,6 +1133,7 @@ ohos_shared_library("service_extension") { "${ability_runtime_native_path}/ability/native/js_service_extension_context.cpp", "${ability_runtime_native_path}/ability/native/service_extension.cpp", "${ability_runtime_native_path}/appkit/ability_runtime/service_extension_context.cpp", + "${ability_runtime_path}/frameworks/ets/ani/service_extension_ability/src/ets_service_extension.cpp", ] deps = [ @@ -1149,12 +1150,14 @@ ohos_shared_library("service_extension") { "${ability_runtime_native_path}/appkit:app_context", "${ability_runtime_native_path}/insight_intent/insight_intent_context:insightintentcontext", "${ability_runtime_path}/utils/global/freeze:freeze_util", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", ] external_deps = [ "ability_base:configuration", "ability_base:want", "ability_base:zuri", + "bundle_framework:libappexecfwk_common", "c_utils:utils", "common_event_service:cesfwk_innerkits", "eventhandler:libeventhandler", @@ -1162,7 +1165,9 @@ ohos_shared_library("service_extension") { "hitrace:hitrace_meter", "ipc:ipc_core", "ipc:ipc_napi", + "ipc:rpc_ani", "napi:ace_napi", + "runtime_core:ani", "safwk:system_ability_fwk", "samgr:samgr_proxy", ] @@ -1677,7 +1682,12 @@ config("ui_extension_public_config") { } ohos_shared_library("ui_extension") { - include_dirs = [ "${ability_runtime_path}/interfaces/kits/native/ability/native/ui_service_extension_ability/connection" ] + include_dirs = [ + "${ability_runtime_path}/interfaces/kits/native/ability/native/ui_service_extension_ability/connection", + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", + "${ability_runtime_path}/frameworks/ets/ani/ui_extension_ability/include", + "${ability_runtime_path}/frameworks/ets/ani/enum_convert", + ] sources = [ "${ability_runtime_native_path}/ability/native/ui_extension_ability/js_embeddable_ui_ability_context.cpp", "${ability_runtime_native_path}/ability/native/ui_extension_ability/js_ui_extension.cpp", @@ -1688,6 +1698,8 @@ ohos_shared_library("ui_extension") { "${ability_runtime_native_path}/ability/native/ui_extension_base/js_uiservice_uiext_connection.cpp", "${ability_runtime_native_path}/ability/native/ui_extension_base/ui_extension_context.cpp", "${ability_runtime_native_path}/ability/native/ui_extension_base/ui_extension_servicehost_stub_impl.cpp", + "${ability_runtime_path}/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_content_session.cpp", + "${ability_runtime_path}/frameworks/ets/ani/ui_extension_ability/src/ets_ui_extension_context.cpp", ] public_configs = [ ":ui_extension_public_config" ] @@ -1706,6 +1718,7 @@ ohos_shared_library("ui_extension") { "${ability_runtime_native_path}/ability/native:insight_intent_executor", "${ability_runtime_native_path}/appkit:app_context", "${ability_runtime_native_path}/appkit:app_context_utils", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", ] external_deps = [ @@ -1716,6 +1729,8 @@ ohos_shared_library("ui_extension") { "access_token:libaccesstoken_sdk", "access_token:libtokenid_sdk", "ace_engine:ace_uicontent", + "bundle_framework:bms_ani_common", + "bundle_framework:libappexecfwk_common", "c_utils:utils", "eventhandler:libeventhandler", "hilog:libhilog", @@ -1724,6 +1739,7 @@ ohos_shared_library("ui_extension") { "ipc:ipc_napi", "napi:ace_napi", "window_manager:embeddablewindowstage_kit", + "window_manager:embeddablewindowstageani_kit", "window_manager:extensionwindow_napi", "window_manager:windowstage_kit", ] diff --git a/frameworks/native/ability/native/service_extension.cpp b/frameworks/native/ability/native/service_extension.cpp index 0838b03f9aa..cbf2ad871c8 100644 --- a/frameworks/native/ability/native/service_extension.cpp +++ b/frameworks/native/ability/native/service_extension.cpp @@ -21,6 +21,7 @@ #include "js_service_extension.h" #include "runtime.h" #include "service_extension_context.h" +#include "ets_service_extension.h" namespace OHOS { namespace AbilityRuntime { @@ -46,7 +47,8 @@ ServiceExtension* ServiceExtension::Create(const std::unique_ptr& runti switch (runtime->GetLanguage()) { case Runtime::Language::JS: return JsServiceExtension::Create(runtime); - + case Runtime::Language::ETS: + return EtsServiceExtension::Create(runtime); default: return new ServiceExtension(); } diff --git a/frameworks/native/appkit/BUILD.gn b/frameworks/native/appkit/BUILD.gn index 4a3092cca55..ddd25fc1faf 100644 --- a/frameworks/native/appkit/BUILD.gn +++ b/frameworks/native/appkit/BUILD.gn @@ -475,6 +475,7 @@ ohos_shared_library("appkit_delegator") { include_dirs = [ "native", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/app", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/ability_delegator/include", @@ -491,6 +492,7 @@ ohos_shared_library("appkit_delegator") { "${ability_runtime_native_path}/appkit/ability_delegator/ability_delegator_args.cpp", "${ability_runtime_native_path}/appkit/ability_delegator/ability_delegator_registry.cpp", "${ability_runtime_native_path}/appkit/ability_delegator/delegator_thread.cpp", + "${ability_runtime_native_path}/appkit/ability_delegator/runner_runtime/ets_test_runner.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/iability_stage_monitor.cpp", @@ -526,6 +528,7 @@ ohos_shared_library("appkit_delegator") { "ipc:ipc_core", "json:nlohmann_json_static", "napi:ace_napi", + "runtime_core:ani", "samgr:samgr_proxy", ] diff --git a/frameworks/native/appkit/ability_delegator/ability_delegator.cpp b/frameworks/native/appkit/ability_delegator/ability_delegator.cpp index 1449f61557f..0c9ef8125c7 100644 --- a/frameworks/native/appkit/ability_delegator/ability_delegator.cpp +++ b/frameworks/native/appkit/ability_delegator/ability_delegator.cpp @@ -115,7 +115,7 @@ size_t AbilityDelegator::GetStageMonitorsNum() } -std::shared_ptr AbilityDelegator::WaitAbilityMonitor( +std::shared_ptr AbilityDelegator::WaitAbilityMonitor( const std::shared_ptr &monitor) { if (!monitor) { @@ -151,7 +151,7 @@ std::shared_ptr AbilityDelegator::WaitAbilityStag return stage; } -std::shared_ptr AbilityDelegator::WaitAbilityMonitor( +std::shared_ptr AbilityDelegator::WaitAbilityMonitor( const std::shared_ptr &monitor, const int64_t timeoutMs) { if (!monitor) { @@ -208,7 +208,7 @@ AbilityDelegator::AbilityState AbilityDelegator::GetAbilityState(const sptrlifecycleState_); } -std::shared_ptr AbilityDelegator::GetCurrentTopAbility() +std::shared_ptr AbilityDelegator::GetCurrentTopAbility() { AppExecFwk::ElementName elementName = AAFwk::AbilityManagerClient::GetInstance()->GetTopAbility(); std::string bundleName = elementName.GetBundleName(); @@ -367,7 +367,7 @@ void AbilityDelegator::Print(const std::string &msg) testObserver->TestStatus(realMsg, 0); } -void AbilityDelegator::PostPerformStart(const std::shared_ptr &ability) +void AbilityDelegator::PostPerformStart(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); @@ -388,9 +388,8 @@ void AbilityDelegator::PostPerformStart(const std::shared_ptrMatch(ability, true)) { - monitor->OnAbilityStart(ability->object_); + monitor->OnAbilityStart(ability); } } } @@ -417,7 +416,7 @@ void AbilityDelegator::PostPerformStageStart(const std::shared_ptr &ability) +void AbilityDelegator::PostPerformScenceCreated(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); @@ -438,14 +437,13 @@ void AbilityDelegator::PostPerformScenceCreated(const std::shared_ptrMatch(ability)) { - monitor->OnWindowStageCreate(ability->object_); + if (monitor->Match(ability, true)) { + monitor->OnWindowStageCreate(ability); } } } -void AbilityDelegator::PostPerformScenceRestored(const std::shared_ptr &ability) +void AbilityDelegator::PostPerformScenceRestored(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); @@ -466,14 +464,13 @@ void AbilityDelegator::PostPerformScenceRestored(const std::shared_ptrMatch(ability)) { - monitor->OnWindowStageRestore(ability->object_); + if (monitor->Match(ability, true)) { + monitor->OnWindowStageRestore(ability); } } } -void AbilityDelegator::PostPerformScenceDestroyed(const std::shared_ptr &ability) +void AbilityDelegator::PostPerformScenceDestroyed(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); @@ -494,14 +491,13 @@ void AbilityDelegator::PostPerformScenceDestroyed(const std::shared_ptrMatch(ability)) { - monitor->OnWindowStageDestroy(ability->object_); + if (monitor->Match(ability, true)) { + monitor->OnWindowStageDestroy(ability); } } } -void AbilityDelegator::PostPerformForeground(const std::shared_ptr &ability) +void AbilityDelegator::PostPerformForeground(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); @@ -522,14 +518,13 @@ void AbilityDelegator::PostPerformForeground(const std::shared_ptrMatch(ability)) { - monitor->OnAbilityForeground(ability->object_); + if (monitor->Match(ability, true)) { + monitor->OnAbilityForeground(ability); } } } -void AbilityDelegator::PostPerformBackground(const std::shared_ptr &ability) +void AbilityDelegator::PostPerformBackground(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "called"); @@ -550,14 +545,13 @@ void AbilityDelegator::PostPerformBackground(const std::shared_ptrMatch(ability)) { - monitor->OnAbilityBackground(ability->object_); + if (monitor->Match(ability, true)) { + monitor->OnAbilityBackground(ability); } } } -void AbilityDelegator::PostPerformStop(const std::shared_ptr &ability) +void AbilityDelegator::PostPerformStop(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "Enter"); @@ -578,9 +572,8 @@ void AbilityDelegator::PostPerformStop(const std::shared_ptrMatch(ability)) { - monitor->OnAbilityStop(ability->object_); + if (monitor->Match(ability, true)) { + monitor->OnAbilityStop(ability); } } @@ -613,7 +606,7 @@ AbilityDelegator::AbilityState AbilityDelegator::ConvertAbilityState( return abilityState; } -void AbilityDelegator::ProcessAbilityProperties(const std::shared_ptr &ability) +void AbilityDelegator::ProcessAbilityProperties(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "Enter"); @@ -636,7 +629,7 @@ void AbilityDelegator::ProcessAbilityProperties(const std::shared_ptr &ability) +void AbilityDelegator::RemoveAbilityProperty(const std::shared_ptr &ability) { TAG_LOGD(AAFwkTag::DELEGATOR, "called"); @@ -654,7 +647,7 @@ void AbilityDelegator::RemoveAbilityProperty(const std::shared_ptr AbilityDelegator::FindPropertyByToken(const sptr &token) +std::shared_ptr AbilityDelegator::FindPropertyByToken(const sptr &token) { TAG_LOGI(AAFwkTag::DELEGATOR, "Enter"); @@ -678,7 +671,7 @@ std::shared_ptr AbilityDelegator::FindPropertyByToken return {}; } -std::shared_ptr AbilityDelegator::FindPropertyByName(const std::string &name) +std::shared_ptr AbilityDelegator::FindPropertyByName(const std::string &name) { TAG_LOGI(AAFwkTag::DELEGATOR, "find property by %{public}s", name.c_str()); @@ -741,7 +734,7 @@ void AbilityDelegator::RegisterClearFunc(ClearFunc func) clearFunc_ = func; } -inline void AbilityDelegator::CallClearFunc(const std::shared_ptr &ability) +inline void AbilityDelegator::CallClearFunc(const std::shared_ptr &ability) { TAG_LOGI(AAFwkTag::DELEGATOR, "Enter"); if (clearFunc_) { diff --git a/frameworks/native/appkit/ability_delegator/iability_monitor.cpp b/frameworks/native/appkit/ability_delegator/iability_monitor.cpp index 17bf4c740bd..4a6238cb047 100644 --- a/frameworks/native/appkit/ability_delegator/iability_monitor.cpp +++ b/frameworks/native/appkit/ability_delegator/iability_monitor.cpp @@ -27,7 +27,7 @@ IAbilityMonitor::IAbilityMonitor(const std::string &abilityName, const std::string &moduleName) : abilityName_(abilityName), moduleName_(moduleName) {} -bool IAbilityMonitor::Match(const std::shared_ptr &ability, bool isNotify) +bool IAbilityMonitor::Match(const std::shared_ptr &ability, bool isNotify) { if (!ability) { TAG_LOGW(AAFwkTag::DELEGATOR, "invalid ability property"); @@ -69,12 +69,12 @@ bool IAbilityMonitor::Match(const std::shared_ptr &ab return true; } -std::shared_ptr IAbilityMonitor::WaitForAbility() +std::shared_ptr IAbilityMonitor::WaitForAbility() { return WaitForAbility(MAX_TIME_OUT); } -std::shared_ptr IAbilityMonitor::WaitForAbility(const int64_t timeoutMs) +std::shared_ptr IAbilityMonitor::WaitForAbility(const int64_t timeoutMs) { auto realTime = timeoutMs; if (timeoutMs <= 0) { @@ -92,25 +92,25 @@ std::shared_ptr IAbilityMonitor::WaitForAbility(const return matchedAbility_; } -void IAbilityMonitor::OnAbilityStart(const std::weak_ptr &abilityObj) +void IAbilityMonitor::OnAbilityStart(const std::weak_ptr &abilityObj) {} -void IAbilityMonitor::OnAbilityForeground(const std::weak_ptr &abilityObj) +void IAbilityMonitor::OnAbilityForeground(const std::weak_ptr &abilityObj) {} -void IAbilityMonitor::OnAbilityBackground(const std::weak_ptr &abilityObj) +void IAbilityMonitor::OnAbilityBackground(const std::weak_ptr &abilityObj) {} -void IAbilityMonitor::OnAbilityStop(const std::weak_ptr &abilityObj) +void IAbilityMonitor::OnAbilityStop(const std::weak_ptr &abilityObj) {} -void IAbilityMonitor::OnWindowStageCreate(const std::weak_ptr &abilityObj) +void IAbilityMonitor::OnWindowStageCreate(const std::weak_ptr &abilityObj) {} -void IAbilityMonitor::OnWindowStageRestore(const std::weak_ptr &abilityObj) +void IAbilityMonitor::OnWindowStageRestore(const std::weak_ptr &abilityObj) {} -void IAbilityMonitor::OnWindowStageDestroy(const std::weak_ptr &abilityObj) +void IAbilityMonitor::OnWindowStageDestroy(const std::weak_ptr &abilityObj) {} } // namespace AppExecFwk } // namespace OHOS diff --git a/frameworks/native/appkit/ability_delegator/runner_runtime/ets_test_runner.cpp b/frameworks/native/appkit/ability_delegator/runner_runtime/ets_test_runner.cpp new file mode 100644 index 00000000000..79e99fb7333 --- /dev/null +++ b/frameworks/native/appkit/ability_delegator/runner_runtime/ets_test_runner.cpp @@ -0,0 +1,179 @@ +/* + * 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 + +#include "ability_delegator_registry.h" +#include "hilog_tag_wrapper.h" +#include "runner_runtime/ets_test_runner.h" + +namespace OHOS { +namespace RunnerRuntime { +namespace { +const std::string CAPITALTESTRUNNER = "/ets/TestRunner/"; +const std::string LOWERCASETESTRUNNER = "/ets/testrunner/"; +} // namespace + +std::unique_ptr ETSTestRunner::Create(const std::unique_ptr &runtime, + const std::shared_ptr &args, const AppExecFwk::BundleInfo &bundleInfo) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "ETSTestRunner Create"); + if (!runtime) { + TAG_LOGE(AAFwkTag::DELEGATOR, "invalid runtime"); + return nullptr; + } + + if (!args) { + TAG_LOGE(AAFwkTag::DELEGATOR, "invalid args"); + return nullptr; + } + + auto pTestRunner = new (std::nothrow) ETSTestRunner(static_cast(*runtime), args, bundleInfo); + if (!pTestRunner) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null testRunner"); + return nullptr; + } + + return std::unique_ptr(pTestRunner); +} + +ETSTestRunner::ETSTestRunner( + ETSRuntime &etsRuntime, const std::shared_ptr &args, const AppExecFwk::BundleInfo &bundleInfo) + : etsRuntime_(etsRuntime) +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "ETSTestRunner constructor"); + std::string moduleName; + if (args) { + std::string srcPath; + if (bundleInfo.hapModuleInfos.back().isModuleJson) { + srcPath.append(args->GetTestModuleName()); + if (args->GetTestRunnerClassName().find("/") == std::string::npos) { + srcPath.append(LOWERCASETESTRUNNER); + } + moduleName = args->GetTestModuleName(); + } else { + srcPath.append(args->GetTestPackageName()); + srcPath.append("/assets/sts/TestRunner/"); + moduleName = args->GetTestPackageName(); + } + srcPath.append(args->GetTestRunnerClassName()); + srcPath.append(".abc"); + srcPath_ = srcPath; + } + TAG_LOGI(AAFwkTag::DELEGATOR, "srcPath: %{public}s", srcPath_.c_str()); + + if (!moduleName.empty()) { + for (auto hapModuleInfo : bundleInfo.hapModuleInfos) { + if ((hapModuleInfo.isModuleJson && hapModuleInfo.name == moduleName) || + hapModuleInfo.package == moduleName) { + hapPath_ = hapModuleInfo.hapPath; + break; + } + } + } else { + hapPath_ = bundleInfo.hapModuleInfos.back().hapPath; + } + AppExecFwk::HapModuleInfo entryHapModuleInfo; + if (!bundleInfo.hapModuleInfos.empty()) { + for (auto hapModuleInfo : bundleInfo.hapModuleInfos) { + if (hapModuleInfo.moduleType == AppExecFwk::ModuleType::ENTRY) { + entryHapModuleInfo = hapModuleInfo; + break; + } + } + } + TAG_LOGI(AAFwkTag::DELEGATOR, "hapPath: %{public}s", hapPath_.c_str()); + moduleName.append("::").append("TestRunner"); + etsTestRunnerObj_ = etsRuntime_.LoadModule(moduleName, srcPath_, hapPath_, + bundleInfo.hapModuleInfos.back().compileMode == AppExecFwk::CompileMode::ES_MODULE, + false, srcPath_); + if (!etsTestRunnerObj_ && srcPath_.find(LOWERCASETESTRUNNER) != std::string::npos) { + TAG_LOGI(AAFwkTag::DELEGATOR, "not found %{public}s , retry load capital address", srcPath_.c_str()); + std::regex src_pattern(LOWERCASETESTRUNNER); + srcPath_ = std::regex_replace(srcPath_, src_pattern, CAPITALTESTRUNNER); + TAG_LOGI(AAFwkTag::DELEGATOR, "capital address is %{public}s", srcPath_.c_str()); + etsTestRunnerObj_ = etsRuntime_.LoadModule(moduleName, srcPath_, hapPath_, + bundleInfo.hapModuleInfos.back().compileMode == AppExecFwk::CompileMode::ES_MODULE, + false, srcPath_); + } +} + +ETSTestRunner::~ETSTestRunner() = default; + +void ETSTestRunner::Prepare() +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "ETSTestRunner Prepare"); + if (etsTestRunnerObj_ != nullptr) { + TAG_LOGI(AAFwkTag::DELEGATOR, "use etsTestRunnerObj_"); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "ResetError failed"); + } + ani_method method; + ani_status status = ANI_ERROR; + status = env->Class_FindMethod(etsTestRunnerObj_->aniCls, "onPrepare", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "get onPrepare failed status : %{public}d", status); + return; + } + TAG_LOGI(AAFwkTag::DELEGATOR, "get onPrepare success"); + + ani_int result; + status = env->Object_CallMethod_Void(etsTestRunnerObj_->aniObj, method, &result); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_CallMethod_Void onPrepare failed status : %{public}d", status); + } else { + TAG_LOGI(AAFwkTag::DELEGATOR, "Object_CallMethod_Void onPrepare success"); + } + } +} + +void ETSTestRunner::Run() +{ + TAG_LOGI(AAFwkTag::DELEGATOR, "ETSTestRunner Run"); + if (etsTestRunnerObj_ != nullptr) { + TAG_LOGI(AAFwkTag::DELEGATOR, "use etsTestRunnerObj_"); + auto env = etsRuntime_.GetAniEnv(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::DELEGATOR, "null env"); + return; + } + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "ResetError failed"); + } + ani_method method; + ani_status status = ANI_ERROR; + status = env->Class_FindMethod(etsTestRunnerObj_->aniCls, "onRun", ":V", &method); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "get onRun failed status : %{public}d", status); + return; + } + TAG_LOGI(AAFwkTag::DELEGATOR, "get onRun success"); + + ani_int result; + status = env->Object_CallMethod_Void(etsTestRunnerObj_->aniObj, method, &result); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::DELEGATOR, "Object_CallMethod_Void onRun failed status : %{public}d", status); + } else { + TAG_LOGI(AAFwkTag::DELEGATOR, "Object_CallMethod_Void onRun success"); + } + } +} +} // namespace RunnerRuntime +} // namespace OHOS diff --git a/frameworks/native/appkit/app/main_thread.cpp b/frameworks/native/appkit/app/main_thread.cpp index d15795546b2..04e2ba084c6 100644 --- a/frameworks/native/appkit/app/main_thread.cpp +++ b/frameworks/native/appkit/app/main_thread.cpp @@ -2461,23 +2461,23 @@ bool MainThread::PrepareAbilityDelegator(const std::shared_ptr & TAG_LOGD(AAFwkTag::APPKIT, "Stage model"); if (applicationCodeLanguage == AbilityRuntime::CODE_LANGUAGE_ARKTS_1_0) { TAG_LOGI(AAFwkTag::DELEGATOR, "create 1.0 testrunner"); - auto &runtime = application_->GetRuntime(AbilityRuntime::CODE_LANGUAGE_ARKTS_1_0); + auto& runtime = application_->GetRuntime(AbilityRuntime::CODE_LANGUAGE_ARKTS_1_0); auto testRunner = TestRunner::Create(runtime, args, false); auto delegator = IAbilityDelegator::Create(runtime, application_->GetAppContext(), std::move(testRunner), record->observer); - AbilityDelegatorRegistry::RegisterInstance(delegator, args, runtime->GetLanguage()); - delegator->SetApiTargetVersion(targetVersion); + AbilityDelegatorRegistry::RegisterInstance(delegator, args, AbilityRuntime::Runtime::Language::JS); + delegator->SetApiTargetVersion(targetVersion); delegator->Prepare(); } if (applicationCodeLanguage == AbilityRuntime::CODE_LANGUAGE_ARKTS_1_2) { TAG_LOGI(AAFwkTag::DELEGATOR, "create 1.2 testrunner"); - auto &runtime = application_->GetRuntime(AbilityRuntime::CODE_LANGUAGE_ARKTS_1_2); + auto& runtime = application_->GetRuntime(AbilityRuntime::CODE_LANGUAGE_ARKTS_1_2); auto testRunner = TestRunner::Create(runtime, args, false); auto delegator = IAbilityDelegator::Create(runtime, application_->GetAppContext(), std::move(testRunner), record->observer); - AbilityDelegatorRegistry::RegisterInstance(delegator, args, runtime->GetLanguage()); - delegator->SetApiTargetVersion(targetVersion); + AbilityDelegatorRegistry::RegisterInstance(delegator, args, AbilityRuntime::Runtime::Language::ETS); + delegator->SetApiTargetVersion(targetVersion); delegator->Prepare(); } } else { // FA model @@ -2497,8 +2497,10 @@ bool MainThread::PrepareAbilityDelegator(const std::shared_ptr & return false; } bool isFaJsModel = entryHapModuleInfo.abilityInfos.front().srcLanguage == "js" ? true : false; - static auto runtime = AbilityRuntime::Runtime::Create(options); - auto testRunner = TestRunner::Create(runtime, args, isFaJsModel); + options.langs.emplace(AbilityRuntime::Runtime::Language::JS, true); // default + static auto runtimes = AbilityRuntime::Runtime::CreateRuntimes(options); + for (const auto& runtime : runtimes) { + auto testRunner = TestRunner::Create(runtime, args, isFaJsModel); if (testRunner == nullptr) { TAG_LOGE(AAFwkTag::APPKIT, "null testRunner"); return false; @@ -2509,9 +2511,10 @@ bool MainThread::PrepareAbilityDelegator(const std::shared_ptr & } auto delegator = std::make_shared( application_->GetAppContext(), std::move(testRunner), record->observer); - AbilityDelegatorRegistry::RegisterInstance(delegator, args, AbilityRuntime::Runtime::Language::JS); + AbilityDelegatorRegistry::RegisterInstance(delegator, args, runtime->GetLanguage()); delegator->SetApiTargetVersion(targetVersion); delegator->Prepare(); + } } return true; } diff --git a/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h b/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h index 19f5e0cc52d..217952afe26 100644 --- a/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h +++ b/interfaces/kits/native/appkit/ability_delegator/ability_delegator.h @@ -69,7 +69,7 @@ public: /** * Definition of cleanup function. */ - using ClearFunc = std::function &)>; + using ClearFunc = std::function &)>; public: static std::shared_ptr Create(const std::shared_ptr& context, @@ -143,7 +143,7 @@ public: * @param monitor, Indicates the specified monitor object. * @return the obtained ability. */ - std::shared_ptr WaitAbilityMonitor(const std::shared_ptr &monitor); + std::shared_ptr WaitAbilityMonitor(const std::shared_ptr &monitor); /** * Waits for the specified monitor and return the obtained abilityStage. @@ -161,7 +161,7 @@ public: * @param timeoutMs, Indicates the specified time out time, in milliseconds. * @return the obtained ability. */ - std::shared_ptr WaitAbilityMonitor( + std::shared_ptr WaitAbilityMonitor( const std::shared_ptr &monitor, const int64_t timeoutMs); /** @@ -194,7 +194,7 @@ public: * * @return the ability that is currently being displayed. */ - std::shared_ptr GetCurrentTopAbility(); + std::shared_ptr GetCurrentTopAbility(); /** * Obtains the name of the thread. @@ -259,7 +259,7 @@ public: * * @param ability, Indicates the ability properties. */ - void PostPerformStart(const std::shared_ptr &ability); + void PostPerformStart(const std::shared_ptr &ability); /** * Saves abilityStage properties when abilityStage is started and notify monitors. @@ -273,42 +273,42 @@ public: * * @param ability, Indicates the ability properties. */ - void PostPerformScenceCreated(const std::shared_ptr &ability); + void PostPerformScenceCreated(const std::shared_ptr &ability); /** * Saves ability properties when scence is restored and notify monitors of state changes. * * @param ability, Indicates the ability properties. */ - void PostPerformScenceRestored(const std::shared_ptr &ability); + void PostPerformScenceRestored(const std::shared_ptr &ability); /** * Saves ability properties when scence is destroyed and notify monitors of state changes. * * @param ability, Indicates the ability properties. */ - void PostPerformScenceDestroyed(const std::shared_ptr &ability); + void PostPerformScenceDestroyed(const std::shared_ptr &ability); /** * Saves ability properties when ability is in the foreground and notify monitors of state changes. * * @param ability, Indicates the ability properties. */ - void PostPerformForeground(const std::shared_ptr &ability); + void PostPerformForeground(const std::shared_ptr &ability); /** * Saves ability properties when ability is in the background and notify monitors of state changes. * * @param ability, Indicates the ability properties. */ - void PostPerformBackground(const std::shared_ptr &ability); + void PostPerformBackground(const std::shared_ptr &ability); /** * Saves ability properties when ability is stopped and notify monitors of state changes. * * @param ability, Indicates the ability properties. */ - void PostPerformStop(const std::shared_ptr &ability); + void PostPerformStop(const std::shared_ptr &ability); /** * Finishes user test. @@ -328,11 +328,11 @@ public: private: AbilityDelegator::AbilityState ConvertAbilityState(const AbilityLifecycleExecutor::LifecycleState lifecycleState); - void ProcessAbilityProperties(const std::shared_ptr &ability); - void RemoveAbilityProperty(const std::shared_ptr &ability); - std::shared_ptr FindPropertyByToken(const sptr &token); - std::shared_ptr FindPropertyByName(const std::string &name); - inline void CallClearFunc(const std::shared_ptr &ability); + void ProcessAbilityProperties(const std::shared_ptr &ability); + void RemoveAbilityProperty(const std::shared_ptr &ability); + std::shared_ptr FindPropertyByToken(const sptr &token); + std::shared_ptr FindPropertyByName(const std::string &name); + inline void CallClearFunc(const std::shared_ptr &ability); private: static constexpr size_t INFORMATION_MAX_LENGTH {1000}; @@ -345,7 +345,7 @@ private: sptr observer_; std::unique_ptr delegatorThread_; - std::list> abilityProperties_; + std::list> abilityProperties_; std::vector> abilityMonitors_; std::vector> abilityStageMonitors_; 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 3f649fb32ca..56baa8b1107 100644 --- a/interfaces/kits/native/appkit/ability_delegator/ability_delegator_infos.h +++ b/interfaces/kits/native/appkit/ability_delegator/ability_delegator_infos.h @@ -23,8 +23,12 @@ class NativeReference; namespace OHOS { +namespace AbilityRuntime { + struct ETSNativeReference; +} namespace AppExecFwk { -struct ADelegatorAbilityProperty { + +struct BaseDelegatorAbilityProperty { // token of ability sptr token_; // name of ability @@ -35,10 +39,15 @@ struct ADelegatorAbilityProperty { std::string fullName_; // lifecycle state of ability AbilityLifecycleExecutor::LifecycleState lifecycleState_ {AbilityLifecycleExecutor::LifecycleState::UNINITIALIZED}; - // ability object in jsruntime +}; +struct ADelegatorAbilityProperty : public BaseDelegatorAbilityProperty { std::weak_ptr object_; }; +struct ETSDelegatorAbilityProperty : public BaseDelegatorAbilityProperty { + std::weak_ptr object_; +}; + struct DelegatorAbilityStageProperty { std::string moduleName_; std::string srcEntrance_; diff --git a/interfaces/kits/native/appkit/ability_delegator/iability_monitor.h b/interfaces/kits/native/appkit/ability_delegator/iability_monitor.h index 6a91fec7732..f899604dd30 100644 --- a/interfaces/kits/native/appkit/ability_delegator/iability_monitor.h +++ b/interfaces/kits/native/appkit/ability_delegator/iability_monitor.h @@ -63,7 +63,7 @@ public: * @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); + 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 @@ -72,7 +72,7 @@ public: * * @return the Ability object if any object has started is matched within 5 seconds; returns null otherwise. */ - virtual std::shared_ptr WaitForAbility(); + virtual std::shared_ptr WaitForAbility(); /** * Waits for and returns the started Ability object that matches the conditions specified in this monitor @@ -84,61 +84,61 @@ public: * @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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + virtual void OnWindowStageDestroy(const std::weak_ptr &abilityObj); private: std::string abilityName_; std::string moduleName_; - std::shared_ptr matchedAbility_; + std::shared_ptr matchedAbility_; std::condition_variable cvMatch_; std::mutex mMatch_; diff --git a/interfaces/kits/native/appkit/ability_delegator/runner_runtime/ets_test_runner.h b/interfaces/kits/native/appkit/ability_delegator/runner_runtime/ets_test_runner.h new file mode 100644 index 00000000000..c9c58f76fc9 --- /dev/null +++ b/interfaces/kits/native/appkit/ability_delegator/runner_runtime/ets_test_runner.h @@ -0,0 +1,71 @@ +/* + * 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_TEST_RUNNER_H +#define OHOS_ABILITY_RUNTIME_ETS_TEST_RUNNER_H + +#include "bundle_info.h" +#include "ets_runtime.h" +#include "test_runner.h" + +class ETSNativeReference; + +namespace OHOS { +namespace RunnerRuntime { +using namespace AppExecFwk; +using namespace AbilityRuntime; + +class ETSTestRunner : public TestRunner { +public: + /** + * Creates a TestRunner instance with the input parameter passed. + * + * @param runtime Indicates the ability runtime. + * @param args Indicates the AbilityDelegatorArgs object. + * @param bundleInfo Indicates the bundle info. + * @return the TestRunner object if JsTestRunner object is created successfully; returns null otherwise. + */ + static std::unique_ptr Create(const std::unique_ptr &runtime, + const std::shared_ptr &args, const AppExecFwk::BundleInfo &bundleInfo); + + /** + * Default deconstructor used to deconstruct. + */ + ~ETSTestRunner() override; + + /** + * Prepares the testing environment for running test code. + */ + void Prepare() override; + + /** + * Runs all test code. + */ + void Run() override; + +private: + ETSTestRunner(ETSRuntime &ETSRuntime, + const std::shared_ptr &args, const AppExecFwk::BundleInfo &bundleInfo); + void CallOnPrepareMethod(ani_env* aniEnv); + void CallOnRunMethod(ani_env* aniEnv); + + ETSRuntime &etsRuntime_; + std::unique_ptr etsTestRunnerObj_; + std::string srcPath_; + std::string hapPath_; +}; +} // namespace RunnerRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_TEST_RUNNER_H diff --git a/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.cpp b/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.cpp index 849f3efa5f7..1c64541ce08 100644 --- a/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.cpp +++ b/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.cpp @@ -33,49 +33,49 @@ MockIabilityMonitor::MockIabilityMonitor(const std::string& abilityName) : IAbil windowStageDestroy_ = false; } -void MockIabilityMonitor::OnAbilityStart(const std::weak_ptr& abilityObj) +void MockIabilityMonitor::OnAbilityStart(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::OnAbilityStart is called"); start_ = true; } -void MockIabilityMonitor::OnAbilityForeground(const std::weak_ptr& abilityObj) +void MockIabilityMonitor::OnAbilityForeground(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::OnAbilityForeground is called"); foreground_ = true; } -void MockIabilityMonitor::OnAbilityBackground(const std::weak_ptr& abilityObj) +void MockIabilityMonitor::OnAbilityBackground(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::OnAbilityBackground is called"); background_ = true; } -void MockIabilityMonitor::OnAbilityStop(const std::weak_ptr& abilityObj) +void MockIabilityMonitor::OnAbilityStop(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::OnAbilityStop is called"); stop_ = true; } -void MockIabilityMonitor::OnWindowStageCreate(const std::weak_ptr& abilityObj) +void MockIabilityMonitor::OnWindowStageCreate(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::OnWindowStageCreate is called"); windowStageCreate_ = true; } -void MockIabilityMonitor::OnWindowStageRestore(const std::weak_ptr& abilityObj) +void MockIabilityMonitor::OnWindowStageRestore(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::OnWindowStageRestore is called"); windowStageRestore_ = true; } -void MockIabilityMonitor::OnWindowStageDestroy(const std::weak_ptr& abilityObj) +void MockIabilityMonitor::OnWindowStageDestroy(const std::weak_ptr &abilityObj) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::OnWindowStageDestroy is called"); windowStageDestroy_ = true; } -bool MockIabilityMonitor::Match(const std::shared_ptr& ability, bool isNotify) +bool MockIabilityMonitor::Match(const std::shared_ptr &ability, bool isNotify) { TAG_LOGI(AAFwkTag::TEST, "MockIabilityMonitor::Match is called"); diff --git a/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.h b/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.h index 7cda62a9808..5f2a8f7e2d7 100644 --- a/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.h +++ b/test/mock/frameworks_kits_appkit_native_test/ability_delegator/mock_iability_monitor.h @@ -28,7 +28,7 @@ public: explicit MockIabilityMonitor(const std::string& abilityName); virtual ~MockIabilityMonitor() = default; - virtual bool Match(const std::shared_ptr& ability, bool isNotify = false); + virtual bool Match(const std::shared_ptr &ability, bool isNotify = false); std::shared_ptr waitForAbility() { @@ -39,14 +39,14 @@ public: return std::make_shared(); }; - 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 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 OnWindowStageCreate(const std::weak_ptr &abilityObj) override; + void OnWindowStageRestore(const std::weak_ptr &abilityObj) override; + void OnWindowStageDestroy(const std::weak_ptr &abilityObj) override; bool start_; bool foreground_; diff --git a/test/moduletest/ability_delegator_test/BUILD.gn b/test/moduletest/ability_delegator_test/BUILD.gn index 649a72006d8..4d6378c26b5 100644 --- a/test/moduletest/ability_delegator_test/BUILD.gn +++ b/test/moduletest/ability_delegator_test/BUILD.gn @@ -134,6 +134,7 @@ ohos_moduletest("ability_delegator_registry_moduletest") { "hilog:libhilog", "init:libbegetutil", "ipc:ipc_core", + "runtime_core:ani", "napi:ace_napi", ] } @@ -164,6 +165,7 @@ ohos_moduletest("iability_monitor_moduletest") { "googletest:gtest_main", "hilog:libhilog", "ipc:ipc_core", + "runtime_core:ani", "napi:ace_napi", ] } @@ -198,6 +200,8 @@ ohos_moduletest("ability_delegator_moduletest") { "hilog:libhilog", "init:libbegetutil", "ipc:ipc_core", + "runtime_core:ani", + "napi:ace_napi", ] if (ability_runtime_graphics) { @@ -243,6 +247,7 @@ ohos_moduletest("js_test_runner_moduletest") { "hilog:libhilog", "init:libbegetutil", "ipc:ipc_core", + "runtime_core:ani", "napi:ace_napi", ] } diff --git a/test/unittest/app_recovery_test/BUILD.gn b/test/unittest/app_recovery_test/BUILD.gn index b0e3ce8f526..93b2719aebf 100644 --- a/test/unittest/app_recovery_test/BUILD.gn +++ b/test/unittest/app_recovery_test/BUILD.gn @@ -72,6 +72,7 @@ ohos_unittest("AppRecoveryUnitTest") { "image_framework:image_native", "ipc:ipc_core", "napi:ace_napi", + "runtime_core:ani", "window_manager:libdm", "window_manager:libwm", "window_manager:windowstage_kit", diff --git a/test/unittest/cj_test_runner_test/BUILD.gn b/test/unittest/cj_test_runner_test/BUILD.gn index 891969d72a3..7c6ef3b90f8 100644 --- a/test/unittest/cj_test_runner_test/BUILD.gn +++ b/test/unittest/cj_test_runner_test/BUILD.gn @@ -19,6 +19,7 @@ ohos_unittest("cj_test_runner_test") { module_out_path = "ability_runtime/ability_runtime/cj_test_runner_test" include_dirs = [ "native", + "${ability_runtime_path}/ets_environment/interfaces/inner_api", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/app", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/ability_delegator/include", diff --git a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn index 93ebc7c8779..6a5728461d2 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn +++ b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/BUILD.gn @@ -112,6 +112,7 @@ ohos_unittest("iability_monitor_unittest") { "hilog:libhilog", "ipc:ipc_core", "napi:ace_napi", + "runtime_core:ani", ] } @@ -147,6 +148,7 @@ ohos_unittest("ability_delegator_unittest") { "init:libbegetutil", "ipc:ipc_core", "napi:ace_napi", + "runtime_core:ani", ] if (ability_runtime_graphics) { @@ -174,6 +176,7 @@ ohos_unittest("delegator_thread_unittest") { "googletest:gtest_main", "hilog:libhilog", "ipc:ipc_core", + "runtime_core:ani", ] } @@ -250,6 +253,7 @@ ohos_unittest("js_test_runner_unittest") { "init:libbegetutil", "ipc:ipc_core", "napi:ace_napi", + "runtime_core:ani", ] } diff --git a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_test.cpp b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_test.cpp index 59ed7bb9521..291cdc72f71 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_test.cpp +++ b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/ability_delegator_test.cpp @@ -1831,7 +1831,7 @@ HWTEST_F(AbilityDelegatorTest, RegisterClearFuncTest_0100, TestSize.Level1) ASSERT_NE(commonDelegator_, nullptr); // Register clear function. - auto clearFunc = [](const std::shared_ptr &property) { + auto clearFunc = [](const std::shared_ptr &property) { TAG_LOGI(AAFwkTag::TEST, "Clear function is called"); }; commonDelegator_->RegisterClearFunc(clearFunc); diff --git a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/iability_monitor_test.cpp b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/iability_monitor_test.cpp index 516a62a1a7f..5f9106bdebe 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/iability_monitor_test.cpp +++ b/test/unittest/frameworks_kits_appkit_native_test/ability_delegator/iability_monitor_test.cpp @@ -226,7 +226,7 @@ HWTEST_F(IabilityMonitorTest, FuncTest_0100, TestSize.Level1) TAG_LOGI(AAFwkTag::TEST, "test start."); auto iabilityMonitor = new IAbilityMonitor(ABILITY_NAME); ASSERT_NE(iabilityMonitor, nullptr); - auto nativeRef = std::shared_ptr(); + auto nativeRef = std::shared_ptr(); iabilityMonitor->OnAbilityStart(nativeRef); iabilityMonitor->OnAbilityForeground(nativeRef); iabilityMonitor->OnAbilityBackground(nativeRef); diff --git a/test/unittest/js_ui_ability_test/BUILD.gn b/test/unittest/js_ui_ability_test/BUILD.gn index fd77d23885a..efdda0d6043 100644 --- a/test/unittest/js_ui_ability_test/BUILD.gn +++ b/test/unittest/js_ui_ability_test/BUILD.gn @@ -69,6 +69,7 @@ ohos_unittest("js_ui_ability_test") { "ipc:ipc_napi", "libuv:uv", "napi:ace_napi", + "runtime_core:ani", "window_manager:libwsutils", ] } -- Gitee