From d89f6591e1d9befe2d394f168d9d245c6786b146 Mon Sep 17 00:00:00 2001 From: acdemicJava Date: Thu, 16 Apr 2026 19:15:51 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BA=E5=8F=82?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: acdemicJava Signed-off-by: acdemicJava --- .../error_manager/src/error_manager_ani.cpp | 16 ++++++---- .../app/error_manager/js_error_manager.cpp | 29 ++++++++++++------- .../appfreeze_inner_test.cpp | 2 +- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/frameworks/ets/ani/error_manager/src/error_manager_ani.cpp b/frameworks/ets/ani/error_manager/src/error_manager_ani.cpp index c04feb2d1a..8520e2e7cc 100644 --- a/frameworks/ets/ani/error_manager/src/error_manager_ani.cpp +++ b/frameworks/ets/ani/error_manager/src/error_manager_ani.cpp @@ -134,12 +134,12 @@ public: EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_MAIN_THREAD); return result; } - if (IsRefUndefined(env, function)) { + if (IsNull(env, function)) { TAG_LOGE(AAFwkTag::JSNAPI, "invalid func"); EtsErrorUtil::ThrowInvalidNumParametersError(env); return result; } - if (IsNull(env, function)) { + if (IsRefUndefined(env, function)) { function = nullptr; } std::lock_guard lock(g_defaultHandlerMtx); @@ -362,7 +362,7 @@ public: return result; } - if (function == nullptr) { + if (IsRefUndefined(env, function)) { env->GlobalReference_Delete(g_freezeObserver.ref); g_freezeObserver.ref = nullptr; g_freezeObserver = {}; @@ -373,7 +373,9 @@ public: } return result; } - if (!ValidateFunction(env, function)) { + if (IsNull(env, function)) { + TAG_LOGE(AAFwkTag::JSNAPI, "invalid func"); + EtsErrorUtil::ThrowInvalidNumParametersError(env); return result; } ani_object observer = static_cast(g_freezeObserver.ref); @@ -427,7 +429,7 @@ public: { ani_object result{}; std::lock_guard lock(g_unhandledRejectionMtx); - if (function == nullptr) { + if (IsRefUndefined(env, function)) { for (auto& iter : g_unhandledRejectionObservers) { env->GlobalReference_Delete(iter); } @@ -435,7 +437,9 @@ public: return result; } - if (!ValidateFunction(env, function)) { + if (IsNull(env, function)) { + TAG_LOGE(AAFwkTag::JSNAPI, "invalid func"); + EtsErrorUtil::ThrowInvalidNumParametersError(env); return result; } diff --git a/frameworks/js/napi/app/error_manager/js_error_manager.cpp b/frameworks/js/napi/app/error_manager/js_error_manager.cpp index 667c40bc8c..db12063bbb 100644 --- a/frameworks/js/napi/app/error_manager/js_error_manager.cpp +++ b/frameworks/js/napi/app/error_manager/js_error_manager.cpp @@ -1016,10 +1016,15 @@ private: ThrowError(env, AbilityErrorCode::ERROR_CODE_MAIN_THREAD); return CreateJsUndefined(env); } - if (CheckTypeForNapiValue(env, function, napi_null) ||CheckTypeForNapiValue(env, function, napi_undefined)) { + if (CheckTypeForNapiValue(env, function, napi_null)) { + TAG_LOGE(AAFwkTag::JSNAPI, "null function."); ThrowInvalidNumParametersError(env); return CreateJsUndefined(env); } + if (CheckTypeForNapiValue(env, function, napi_undefined)) { + TAG_LOGI(AAFwkTag::JSNAPI, "Get defaultHandler undefined"); + function = nullptr; + } std::lock_guard lock(defaultHandlerMtx); napi_value object = nullptr; if (defaultHandler.ref == nullptr) { @@ -1052,10 +1057,10 @@ private: return CreateJsUndefined(env); } - if (CheckTypeForNapiValue(env, function, napi_null) || CheckTypeForNapiValue(env, function, napi_undefined)) { - TAG_LOGE(AAFwkTag::JSNAPI, "CheckTypeForNapiValue failed"); - ThrowInvalidNumParametersError(env); - return CreateJsUndefined(env); + if (CheckTypeForNapiValue(env, function, napi_undefined) || + CheckTypeForNapiValue(env, function, napi_null)) { + TAG_LOGW(AAFwkTag::JSNAPI, "null or undefined function."); + function = nullptr; } std::lock_guard lock(defaultLeakMtx); napi_value oldObserverFunc = nullptr; @@ -1462,7 +1467,7 @@ private: return res; } - if (function == nullptr) { + if (function == nullptr || CheckTypeForNapiValue(env, function, napi_undefined)) { NAPI_CALL(env, napi_delete_reference(env, freezeObserver.ref)); freezeObserver = {}; if (freezeCallbackRegistered) { @@ -1472,8 +1477,10 @@ private: } return res; } - if (!ValidateFunction(env, function)) { - return nullptr; + if (CheckTypeForNapiValue(env, function, napi_null)) { + TAG_LOGE(AAFwkTag::JSNAPI, "null function."); + ThrowInvalidNumParametersError(env); + return CreateJsUndefined(env); } napi_value observer = nullptr; NAPI_CALL(env, napi_get_reference_value(env, freezeObserver.ref, &observer)); @@ -1583,8 +1590,10 @@ private: return res; } napi_value function = argv[INDEX_ONE]; - if (!ValidateFunction(env, function)) { - return res; + if (function == nullptr || CheckTypeForNapiValue(env, function, napi_null)) { + TAG_LOGE(AAFwkTag::JSNAPI, "null function."); + ThrowInvalidNumParametersError(env); + return CreateJsUndefined(env); } for (auto& iter : unhandledRejectionObservers) { napi_value observer = nullptr; diff --git a/test/unittest/dfr_test/appfreeze_inner_test/appfreeze_inner_test.cpp b/test/unittest/dfr_test/appfreeze_inner_test/appfreeze_inner_test.cpp index da11e19e9d..e0b43c70b6 100644 --- a/test/unittest/dfr_test/appfreeze_inner_test/appfreeze_inner_test.cpp +++ b/test/unittest/dfr_test/appfreeze_inner_test/appfreeze_inner_test.cpp @@ -660,4 +660,4 @@ HWTEST_F(AppfreezeInnerTest, AppfreezeInner_ReportLifeCycleAsAppfreeze_001, Test EXPECT_TRUE(!appfreezeInner->GetReportLifeCycleAsAppfreeze()); } } // namespace AppExecFwk -} // namespace OHOS +} // namespace OHOS \ No newline at end of file From dbb5f19a15447f6d4fa9adaa3346b5e09627916a Mon Sep 17 00:00:00 2001 From: zhangyuhang72 Date: Tue, 21 Apr 2026 19:37:36 +0800 Subject: [PATCH 2/9] Connect ModularObjectExtension Co-Authored-By:Agent Signed-off-by: zhangyuhang72 Change-Id: I142c0ab148217c74d34403cb48fc67f9e87e1e9b --- frameworks/c/ability_runtime/BUILD.gn | 17 +- .../c_modular_object_connection_callback.h | 87 +++ .../include/c_modular_object_utils.h | 44 ++ .../include/connect_options_impl.h | 37 ++ .../modular_object_ability_connection.h | 63 +++ .../modular_object_connection_manager.h | 121 ++++ .../include/modular_object_extension_types.h | 45 ++ .../c_modular_object_connection_callback.cpp | 166 ++++++ .../src/c_modular_object_utils.cpp | 160 ++++++ .../c/ability_runtime/src/connect_options.cpp | 132 +++++ .../src/modular_object_ability_connection.cpp | 95 ++++ .../src/modular_object_connection_manager.cpp | 149 +++++ .../src/modular_object_extension_ability.cpp | 150 +++++ .../src/modular_object_extension_context.cpp | 143 +++++ .../src/modular_object_extension_manager.cpp | 107 +++- frameworks/native/ability/native/BUILD.gn | 122 ++++ .../native/extension_ability_thread.cpp | 3 + .../modular_object_extension.cpp | 203 +++++++ .../modular_object_extension_context_impl.cpp | 45 ++ ...modular_object_extension_module_loader.cpp | 43 ++ .../include/ability_manager_errors.h | 4 + .../ability_runtime/ability_runtime_common.h | 35 ++ .../kits/c/ability_runtime/connect_options.h | 173 ++++++ .../modular_object_extension_ability.h | 210 +++++++ .../modular_object_extension_context.h | 165 ++++++ .../modular_object_extension_manager.h | 55 +- .../modular_object_extension.h | 78 +++ .../modular_object_extension_context_impl.h | 46 ++ .../modular_object_extension_module_loader.h | 33 ++ services/abilitymgr/BUILD.gn | 5 + services/abilitymgr/abilitymgr.gni | 3 + .../include/ability_manager_service.h | 8 +- .../extension_record_manager.h | 7 + .../modular_object/modular_object_manager.h | 3 +- .../abilitymgr/include/modular_object_utils.h | 50 ++ .../ui_extension_ability_manager.h | 7 + .../src/ability_manager_service.cpp | 5 + .../extension_record_manager.cpp | 17 + .../modular_object/modular_object_manager.cpp | 8 +- .../abilitymgr/src/modular_object_utils.cpp | 233 ++++++++ .../ui_extension_ability_manager.cpp | 7 + test/unittest/BUILD.gn | 11 + .../BUILD.gn | 1 + .../BUILD.gn | 1 + .../BUILD.gn | 1 + .../BUILD.gn | 52 ++ ...odular_object_connection_callback_test.cpp | 353 ++++++++++++ .../mock/include/ability_connect_callback.h | 40 ++ .../c_modular_object_connection_callback.h | 68 +++ .../mock/include/c_modular_object_utils.h | 87 +++ .../mock/include/connect_options_impl.h | 53 ++ .../mock/include/element_name.h | 49 ++ .../mock/include/ipc_inner_object.h | 45 ++ .../modular_object_connection_manager.h | 48 ++ .../include/modular_object_extension_types.h | 49 ++ .../mock/include/want_manager.h | 21 + .../c_modular_object_utils_test/BUILD.gn | 62 ++ .../c_modular_object_utils_test.cpp | 532 ++++++++++++++++++ .../mock/include/connect_options.h | 44 ++ .../mock/include/element_name.h | 46 ++ .../mock/include/mock_context_base.h | 39 ++ .../mock/include/mock_my_flag.h | 31 + .../include/native_extension/context_impl.h | 27 + .../mock/include/want.h | 51 ++ .../mock/include/want_manager.h | 34 ++ .../src/mock_ability_business_error_utils.cpp | 25 + .../mock/src/mock_my_flag.cpp | 20 + .../mock/src/mock_want_manager.cpp | 31 + .../mock/src/mock_want_utils.cpp | 25 + test/unittest/connect_options_test/BUILD.gn | 48 ++ .../connect_options_test.cpp | 253 +++++++++ .../BUILD.gn | 46 ++ .../mock/include/ability_connect_callback.h | 38 ++ .../mock/include/ability_connection.h | 79 +++ .../mock/include/connection_manager.h | 19 + .../mock/include/element_name.h | 50 ++ .../modular_object_ability_connection.h | 42 ++ .../modular_object_connection_manager.h | 62 ++ ...modular_object_ability_connection_test.cpp | 267 +++++++++ .../BUILD.gn | 46 ++ .../mock/include/ability_connect_callback.h | 39 ++ .../mock/include/ability_connection.h | 80 +++ .../mock/include/ability_manager_client.h | 78 +++ .../mock/include/element_name.h | 50 ++ .../mock/include/operation.h | 51 ++ .../mock/include/want.h | 36 ++ ...modular_object_connection_manager_test.cpp | 261 +++++++++ .../BUILD.gn | 45 ++ .../mock/include/ability_runtime_common.h | 43 ++ .../mock/include/extension_ability.h | 21 + .../mock/include/extension_ability_info.h | 31 + .../mock/include/ipc_cparcel.h | 23 + .../modular_object_extension_ability.h | 64 +++ .../modular_object_extension_context.h | 25 + .../include/modular_object_extension_types.h | 43 ++ .../include/native_extension/context_impl.h | 33 ++ .../native_extension/extension_ability_impl.h | 43 ++ .../mock/include/want.h | 27 + .../modular_object_extension_ability_test.cpp | 272 +++++++++ .../BUILD.gn | 45 ++ .../mock/include/ability_base_error.h | 22 + .../include/ability_business_error_utils.h | 38 ++ .../mock/include/ability_manager_client.h | 19 + .../mock/include/ability_runtime_common.h | 43 ++ .../mock/include/errors.h | 24 + .../mock/include/extension_ability.h | 21 + .../mock/include/extension_ability_info.h | 30 + .../mock/include/ipc_cparcel.h | 23 + .../mock/include/mock_types.h | 26 + .../modular_object_extension_ability.h | 55 ++ .../modular_object_extension_context.h | 49 ++ .../modular_object_extension_context_impl.h | 41 ++ .../include/modular_object_extension_types.h | 35 ++ .../include/native_extension/context_impl.h | 33 ++ .../native_extension/extension_ability_impl.h | 35 ++ .../mock/include/start_options_impl.h | 25 + .../mock/include/want.h | 27 + .../mock/include/want_manager.h | 51 ++ .../mock/include/want_utils.h | 27 + ...lar_object_extension_context_capi_test.cpp | 328 +++++++++++ .../BUILD.gn | 43 ++ .../mock/include/errors.h | 23 + .../mock/include/extension_context.h | 94 ++++ .../mock/include/hitrace_meter.h | 22 + .../modular_object_extension_context_impl.h | 51 ++ ...lar_object_extension_context_impl_test.cpp | 176 ++++++ .../BUILD.gn | 58 ++ ..._object_extension_manager_connect_test.cpp | 253 +++++++++ .../BUILD.gn | 1 + .../modular_object_extension_test/BUILD.gn | 47 ++ .../mock/include/ability_base_error.h | 21 + .../mock/include/ability_runtime_common.h | 39 ++ .../mock/include/element_name.h | 47 ++ .../mock/include/errors.h | 23 + .../mock/include/extension.h | 60 ++ .../mock/include/extension_ability.h | 21 + .../mock/include/extension_ability_info.h | 31 + .../mock/include/extension_base.h | 50 ++ .../mock/include/ipc_cparcel.h | 26 + .../mock/include/ipc_inner_object.h | 21 + .../mock/include/mock_types.h | 39 ++ .../mock/include/modular_object_extension.h | 75 +++ .../modular_object_extension_ability.h | 52 ++ .../modular_object_extension_context_impl.h | 34 ++ .../include/modular_object_extension_types.h | 35 ++ .../include/native_extension/context_impl.h | 33 ++ .../native_extension/extension_ability_impl.h | 35 ++ .../mock/include/native_runtime.h | 38 ++ .../mock/include/want.h | 26 + .../mock/include/want_manager.h | 52 ++ .../modular_object_extension_test.cpp | 352 ++++++++++++ .../modular_object_utils_test/BUILD.gn | 54 ++ .../mock/include/ability_manager_errors.h | 48 ++ .../mock/include/ability_manager_service.h | 94 ++++ .../include/ability_record/ability_request.h | 83 +++ .../mock/include/ability_util.h | 34 ++ .../mock/include/app_mgr_client.h | 42 ++ .../mock/include/app_utils.h | 38 ++ .../mock/include/bundle_mgr_helper.h | 54 ++ .../mock/include/ipc_skeleton.h | 45 ++ .../mock/include/mock_flag.h | 64 +++ .../include/modular_object_extension_info.h | 43 ++ .../include/modular_object_rdb_storage_mgr.h | 64 +++ .../mock/include/modular_object_utils.h | 51 ++ .../mock/include/os_account_manager_wrapper.h | 41 ++ .../mock/include/parameters.h | 33 ++ .../mock/include/running_process_info.h | 40 ++ .../mock/include/scene_board_judgement.h | 33 ++ .../mock/include/singleton.h | 37 ++ .../mock/src/mock_flag.cpp | 38 ++ .../modular_object_utils_test.cpp | 482 ++++++++++++++++ .../extension_record_manager_test.cpp | 138 +++++ 172 files changed, 11548 insertions(+), 28 deletions(-) create mode 100644 frameworks/c/ability_runtime/include/c_modular_object_connection_callback.h create mode 100644 frameworks/c/ability_runtime/include/c_modular_object_utils.h create mode 100644 frameworks/c/ability_runtime/include/connect_options_impl.h create mode 100644 frameworks/c/ability_runtime/include/modular_object_ability_connection.h create mode 100644 frameworks/c/ability_runtime/include/modular_object_connection_manager.h create mode 100644 frameworks/c/ability_runtime/include/modular_object_extension_types.h create mode 100644 frameworks/c/ability_runtime/src/c_modular_object_connection_callback.cpp create mode 100644 frameworks/c/ability_runtime/src/c_modular_object_utils.cpp create mode 100644 frameworks/c/ability_runtime/src/connect_options.cpp create mode 100644 frameworks/c/ability_runtime/src/modular_object_ability_connection.cpp create mode 100644 frameworks/c/ability_runtime/src/modular_object_connection_manager.cpp create mode 100644 frameworks/c/ability_runtime/src/modular_object_extension_ability.cpp create mode 100644 frameworks/c/ability_runtime/src/modular_object_extension_context.cpp create mode 100644 frameworks/native/ability/native/modular_object_extension/modular_object_extension.cpp create mode 100644 frameworks/native/ability/native/modular_object_extension/modular_object_extension_context_impl.cpp create mode 100644 frameworks/native/ability/native/modular_object_extension/modular_object_extension_module_loader.cpp create mode 100644 interfaces/kits/c/ability_runtime/connect_options.h create mode 100644 interfaces/kits/c/ability_runtime/modular_object_extension_ability.h create mode 100644 interfaces/kits/c/ability_runtime/modular_object_extension_context.h create mode 100644 interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension.h create mode 100644 interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_context_impl.h create mode 100644 interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_module_loader.h create mode 100644 services/abilitymgr/include/modular_object_utils.h create mode 100644 services/abilitymgr/src/modular_object_utils.cpp create mode 100644 test/unittest/c_modular_object_connection_callback_test/BUILD.gn create mode 100644 test/unittest/c_modular_object_connection_callback_test/c_modular_object_connection_callback_test.cpp create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/ability_connect_callback.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_connection_callback.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_utils.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/connect_options_impl.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/element_name.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/ipc_inner_object.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_connection_manager.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_extension_types.h create mode 100644 test/unittest/c_modular_object_connection_callback_test/mock/include/want_manager.h create mode 100644 test/unittest/c_modular_object_utils_test/BUILD.gn create mode 100644 test/unittest/c_modular_object_utils_test/c_modular_object_utils_test.cpp create mode 100644 test/unittest/c_modular_object_utils_test/mock/include/connect_options.h create mode 100644 test/unittest/c_modular_object_utils_test/mock/include/element_name.h create mode 100644 test/unittest/c_modular_object_utils_test/mock/include/mock_context_base.h create mode 100644 test/unittest/c_modular_object_utils_test/mock/include/mock_my_flag.h create mode 100644 test/unittest/c_modular_object_utils_test/mock/include/native_extension/context_impl.h create mode 100644 test/unittest/c_modular_object_utils_test/mock/include/want.h create mode 100644 test/unittest/c_modular_object_utils_test/mock/include/want_manager.h create mode 100644 test/unittest/c_modular_object_utils_test/mock/src/mock_ability_business_error_utils.cpp create mode 100644 test/unittest/c_modular_object_utils_test/mock/src/mock_my_flag.cpp create mode 100644 test/unittest/c_modular_object_utils_test/mock/src/mock_want_manager.cpp create mode 100644 test/unittest/c_modular_object_utils_test/mock/src/mock_want_utils.cpp create mode 100644 test/unittest/connect_options_test/BUILD.gn create mode 100644 test/unittest/connect_options_test/connect_options_test.cpp create mode 100644 test/unittest/modular_object_ability_connection_test/BUILD.gn create mode 100644 test/unittest/modular_object_ability_connection_test/mock/include/ability_connect_callback.h create mode 100644 test/unittest/modular_object_ability_connection_test/mock/include/ability_connection.h create mode 100644 test/unittest/modular_object_ability_connection_test/mock/include/connection_manager.h create mode 100644 test/unittest/modular_object_ability_connection_test/mock/include/element_name.h create mode 100644 test/unittest/modular_object_ability_connection_test/mock/include/modular_object_ability_connection.h create mode 100644 test/unittest/modular_object_ability_connection_test/mock/include/modular_object_connection_manager.h create mode 100644 test/unittest/modular_object_ability_connection_test/modular_object_ability_connection_test.cpp create mode 100644 test/unittest/modular_object_connection_manager_test/BUILD.gn create mode 100644 test/unittest/modular_object_connection_manager_test/mock/include/ability_connect_callback.h create mode 100644 test/unittest/modular_object_connection_manager_test/mock/include/ability_connection.h create mode 100644 test/unittest/modular_object_connection_manager_test/mock/include/ability_manager_client.h create mode 100644 test/unittest/modular_object_connection_manager_test/mock/include/element_name.h create mode 100644 test/unittest/modular_object_connection_manager_test/mock/include/operation.h create mode 100644 test/unittest/modular_object_connection_manager_test/mock/include/want.h create mode 100644 test/unittest/modular_object_connection_manager_test/modular_object_connection_manager_test.cpp create mode 100644 test/unittest/modular_object_extension_ability_test/BUILD.gn create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/ability_runtime_common.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/extension_ability.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/extension_ability_info.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/ipc_cparcel.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_ability.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_context.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_types.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/native_extension/context_impl.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/native_extension/extension_ability_impl.h create mode 100644 test/unittest/modular_object_extension_ability_test/mock/include/want.h create mode 100644 test/unittest/modular_object_extension_ability_test/modular_object_extension_ability_test.cpp create mode 100644 test/unittest/modular_object_extension_context_capi_test/BUILD.gn create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/ability_base_error.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/ability_business_error_utils.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/ability_manager_client.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/ability_runtime_common.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/errors.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability_info.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/ipc_cparcel.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/mock_types.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_ability.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context_impl.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_types.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/context_impl.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/extension_ability_impl.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/start_options_impl.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/want.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/want_manager.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/mock/include/want_utils.h create mode 100644 test/unittest/modular_object_extension_context_capi_test/modular_object_extension_context_capi_test.cpp create mode 100644 test/unittest/modular_object_extension_context_impl_test/BUILD.gn create mode 100644 test/unittest/modular_object_extension_context_impl_test/mock/include/errors.h create mode 100644 test/unittest/modular_object_extension_context_impl_test/mock/include/extension_context.h create mode 100644 test/unittest/modular_object_extension_context_impl_test/mock/include/hitrace_meter.h create mode 100644 test/unittest/modular_object_extension_context_impl_test/mock/include/modular_object_extension_context_impl.h create mode 100644 test/unittest/modular_object_extension_context_impl_test/modular_object_extension_context_impl_test.cpp create mode 100644 test/unittest/modular_object_extension_manager_connect_test/BUILD.gn create mode 100644 test/unittest/modular_object_extension_manager_connect_test/modular_object_extension_manager_connect_test.cpp create mode 100644 test/unittest/modular_object_extension_test/BUILD.gn create mode 100644 test/unittest/modular_object_extension_test/mock/include/ability_base_error.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/ability_runtime_common.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/element_name.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/errors.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/extension.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/extension_ability.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/extension_ability_info.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/extension_base.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/ipc_cparcel.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/ipc_inner_object.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/mock_types.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/modular_object_extension.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/modular_object_extension_ability.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/modular_object_extension_context_impl.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/modular_object_extension_types.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/native_extension/context_impl.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/native_extension/extension_ability_impl.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/native_runtime.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/want.h create mode 100644 test/unittest/modular_object_extension_test/mock/include/want_manager.h create mode 100644 test/unittest/modular_object_extension_test/modular_object_extension_test.cpp create mode 100644 test/unittest/modular_object_utils_test/BUILD.gn create mode 100644 test/unittest/modular_object_utils_test/mock/include/ability_manager_errors.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/ability_manager_service.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/ability_record/ability_request.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/ability_util.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/app_mgr_client.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/app_utils.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/bundle_mgr_helper.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/ipc_skeleton.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/mock_flag.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/modular_object_extension_info.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/modular_object_rdb_storage_mgr.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/modular_object_utils.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/os_account_manager_wrapper.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/parameters.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/running_process_info.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/scene_board_judgement.h create mode 100644 test/unittest/modular_object_utils_test/mock/include/singleton.h create mode 100644 test/unittest/modular_object_utils_test/mock/src/mock_flag.cpp create mode 100644 test/unittest/modular_object_utils_test/modular_object_utils_test.cpp diff --git a/frameworks/c/ability_runtime/BUILD.gn b/frameworks/c/ability_runtime/BUILD.gn index dc6e380785..94f46fa9d2 100644 --- a/frameworks/c/ability_runtime/BUILD.gn +++ b/frameworks/c/ability_runtime/BUILD.gn @@ -42,8 +42,9 @@ ohos_shared_library("ability_runtime") { include_dirs = [ "include", - "${ability_runtime_path}/interfaces/inner_api/", - "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/", + "${ability_runtime_path}/interfaces/inner_api", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime", + "${ability_runtime_path}/interfaces/kits/native/ability/native/modular_object_extension", ] configs = [ @@ -55,21 +56,31 @@ ohos_shared_library("ability_runtime") { sources = [ "src/ability_business_error_utils.cpp", "src/application_context.cpp", + "src/connect_options.cpp", "src/context.cpp", "src/load_ability_callback_impl.cpp", + "src/modular_object_extension_ability.cpp", + "src/modular_object_extension_context.cpp", + "src/c_modular_object_connection_callback.cpp", "src/modular_object_extension_manager.cpp", + "src/modular_object_connection_manager.cpp", + "src/modular_object_ability_connection.cpp", + "src/c_modular_object_utils.cpp", "src/start_options.cpp", "src/start_options_impl.cpp", "src/want_utils.cpp", ] deps = [ + "${ability_runtime_innerkits_path}/ability_manager:ability_connect_callback_stub", "${ability_runtime_innerkits_path}/ability_manager:ability_manager", "${ability_runtime_innerkits_path}/ability_manager:ability_start_options", "${ability_runtime_innerkits_path}/ability_manager:process_options", "${ability_runtime_innerkits_path}/ability_manager:start_window_option", "${ability_runtime_innerkits_path}/app_manager:app_manager", "${ability_runtime_innerkits_path}/page_config_manager:page_config_manager", + "${ability_runtime_native_path}/ability:ability_context_native", + "${ability_runtime_native_path}/ability/native:modular_object_extension", "${ability_runtime_native_path}/appkit:app_context", ] @@ -83,6 +94,7 @@ ohos_shared_library("ability_runtime") { "image_framework:pixelmap", "ipc:ipc_capi", "ipc:ipc_core", + "ipc:ipc_napi", "napi:ace_napi", "samgr:samgr_proxy", ] @@ -91,6 +103,7 @@ ohos_shared_library("ability_runtime") { external_deps += [ "graphic_2d:color_manager", "image_framework:image", + "window_manager:libwm", "window_manager:window_animation_utils", ] defines = [ diff --git a/frameworks/c/ability_runtime/include/c_modular_object_connection_callback.h b/frameworks/c/ability_runtime/include/c_modular_object_connection_callback.h new file mode 100644 index 0000000000..d804b49483 --- /dev/null +++ b/frameworks/c/ability_runtime/include/c_modular_object_connection_callback.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026 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_C_MODULAR_OBJECT_CONNECTION_CALLBACK_H +#define OHOS_ABILITY_RUNTIME_C_MODULAR_OBJECT_CONNECTION_CALLBACK_H + +#include +#include + +#include "ability_connect_callback.h" +#include "connect_options_impl.h" +namespace OHOS { +namespace AbilityRuntime { + +struct ModularObjectConnectionKey { + int64_t id; +}; + +struct ModularObjectConnectionKeyCompare { + bool operator()(const ModularObjectConnectionKey &key1, const ModularObjectConnectionKey &key2) const + { + return key1.id < key2.id; + } +}; + +class CModularObjectConnectionCallback; + +namespace CModularObjectConnectionUtils { +/** + * @brief Insert connection callback into global registry. + * @param callback The callback object to insert. + * @return Returns the connection ID. + */ +int64_t InsertConnection(sptr callback); + +/** + * @brief Remove connection callback from global registry. + * @param connectionId The connection ID to remove. + */ +void RemoveConnectionCallback(int64_t connectionId); + +/** + * @brief Find connection callback by ID. + * @param connectionId The connection ID to find. + * @param callback Output parameter for the found callback. + */ +void FindConnection(int64_t connectionId, sptr &callback); +} // namespace CModularObjectConnectionUtils + +/** + * @brief C connection callback for ModularObjectExtension. + * Handles OnAbilityConnectDone/OnAbilityDisconnectDone and invokes user C callbacks. + */ +class CModularObjectConnectionCallback : public AbilityConnectCallback { +public: + CModularObjectConnectionCallback( + const std::shared_ptr &state); + ~CModularObjectConnectionCallback() override = default; + + void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) override; + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + + void SetConnectionId(int64_t id) { connectionId_ = id; } + int64_t GetConnectionId() const { return connectionId_; } + +private: + int64_t connectionId_ = 0; + std::weak_ptr state_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_C_MODULAR_OBJECT_CONNECTION_CALLBACK_H diff --git a/frameworks/c/ability_runtime/include/c_modular_object_utils.h b/frameworks/c/ability_runtime/include/c_modular_object_utils.h new file mode 100644 index 0000000000..91f7e22233 --- /dev/null +++ b/frameworks/c/ability_runtime/include/c_modular_object_utils.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_UTILS_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_UTILS_H + +#include + +#include "ability_runtime_common.h" +#include "connect_options_impl.h" +#include "context.h" +#include "element_name.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AbilityRuntime { +class CModularObjectUtils { +public: + static AbilityRuntime_ErrorCode ConvertConnectBusinessErrorCode(int32_t errCode); + static bool BuildElement(const AppExecFwk::ElementName &elementName, AbilityBase_Element &element); + static void DestroyElement(AbilityBase_Element &element); + static bool CopyToCString(const std::string &src, char *&dst); + static AbilityRuntime_ErrorCode TransformWant(AbilityBase_Want *want, AAFwk::Want &abilityWant); + static AbilityRuntime_ErrorCode CheckContextAndToken(AbilityRuntime_ContextHandle context, + sptr &token); + static void NotifyFailed(std::shared_ptr state, + int32_t businessErrorCode); +}; +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_UTILS_H diff --git a/frameworks/c/ability_runtime/include/connect_options_impl.h b/frameworks/c/ability_runtime/include/connect_options_impl.h new file mode 100644 index 0000000000..717cd40b1e --- /dev/null +++ b/frameworks/c/ability_runtime/include/connect_options_impl.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026 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 ABILITY_RUNTIME_CONNECT_OPTIONS_IMPL_H +#define ABILITY_RUNTIME_CONNECT_OPTIONS_IMPL_H + +#include +#include + +#include "connect_options.h" + +struct OH_AbilityRuntime_ConnectOptionsState { + std::mutex mutex; + bool alive = true; + OH_AbilityRuntime_ConnectOptions *owner = nullptr; + OH_AbilityRuntime_ConnectOptions_OnConnectCallback onConnectCallback = nullptr; + OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback onDisconnectCallback = nullptr; + OH_AbilityRuntime_ConnectOptions_OnFailedCallback onFailedCallback = nullptr; +}; + +struct OH_AbilityRuntime_ConnectOptions { + std::shared_ptr state; +}; + +#endif // ABILITY_RUNTIME_CONNECT_OPTIONS_IMPL_H diff --git a/frameworks/c/ability_runtime/include/modular_object_ability_connection.h b/frameworks/c/ability_runtime/include/modular_object_ability_connection.h new file mode 100644 index 0000000000..685d39d9f6 --- /dev/null +++ b/frameworks/c/ability_runtime/include/modular_object_ability_connection.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_ABILITY_CONNECTION_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_ABILITY_CONNECTION_H + +#include + +#include "ability_connection.h" + +namespace OHOS { +namespace AbilityRuntime { + +/** + * @class ModularObjectAbilityConnection + * @brief Connection class for ModularObjectExtension. + * + * Inherits from AbilityConnection and uses ModularObjectConnectionManager + * for connection lifecycle management instead of ConnectionManager. + */ +class ModularObjectAbilityConnection : public AbilityConnection { +public: + ModularObjectAbilityConnection() = default; + ~ModularObjectAbilityConnection() override = default; + + /** + * @brief Called when ability connection is done. + * + * @param element Service ability's ElementName. + * @param remoteObject The session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + + /** + * @brief Called when ability disconnection is done. + * + * @param element Service ability's ElementName. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + +private: + std::mutex modularMutex_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_ABILITY_CONNECTION_H diff --git a/frameworks/c/ability_runtime/include/modular_object_connection_manager.h b/frameworks/c/ability_runtime/include/modular_object_connection_manager.h new file mode 100644 index 0000000000..cdd23c9809 --- /dev/null +++ b/frameworks/c/ability_runtime/include/modular_object_connection_manager.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_CONNECTION_MANAGER_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_CONNECTION_MANAGER_H + +#include +#include +#include + +#include "ability_connect_callback.h" +#include "errors.h" +#include "iremote_object.h" +#include "modular_object_ability_connection.h" +#include "operation.h" +#include "want.h" + +namespace OHOS { +namespace AbilityRuntime { + +/** + * @brief Connection info key for ModularObjectExtension. + * Key consists of: abilityConnection + connectReceiver. + */ +struct ModularObjectConnectionInfo { + sptr abilityConnection; + AAFwk::Operation connectReceiver; + + ModularObjectConnectionInfo(const sptr &connection, + const AAFwk::Operation &receiver) + : abilityConnection(connection), connectReceiver(receiver) + {} + + bool operator<(const ModularObjectConnectionInfo &that) const + { + if (abilityConnection < that.abilityConnection) { + return true; + } + if (connectReceiver.GetBundleName() < that.connectReceiver.GetBundleName()) { + return true; + } + if (connectReceiver.GetBundleName() == that.connectReceiver.GetBundleName() && + connectReceiver.GetModuleName() < that.connectReceiver.GetModuleName()) { + return true; + } + if (connectReceiver.GetBundleName() == that.connectReceiver.GetBundleName() && + connectReceiver.GetModuleName() == that.connectReceiver.GetModuleName() && + connectReceiver.GetAbilityName() < that.connectReceiver.GetAbilityName()) { + return true; + } + return false; + } +}; + +/** + * @brief Manages connections to ModularObjectExtension instances. + * + * Key difference from ConnectionManager: NO connection reuse. + * Each connect call creates a new connection. + */ +class ModularObjectConnectionManager { +public: + ~ModularObjectConnectionManager() = default; + ModularObjectConnectionManager(const ModularObjectConnectionManager &) = delete; + ModularObjectConnectionManager &operator=(const ModularObjectConnectionManager &) = delete; + + static ModularObjectConnectionManager &GetInstance(); + + /** + * @brief Connect to ModularObjectExtension - always creates new connection. + * @param want The Want containing target ability info. + * @param callback The connection callback. + */ + ErrCode ConnectModularObjectExtension(const AAFwk::Want &want, + const sptr &callback); + + /** + * @brief Disconnect from ModularObjectExtension by callback. + * @param callback The connection callback to disconnect. + */ + ErrCode DisconnectModularObjectExtension(const sptr &callback); + + /** + * @brief Remove connection record by connection object. + * @param connection The connection to remove. + * @return true if removed, false otherwise. + */ + bool RemoveConnection(const sptr &connection); + + /** + * @brief Check if service exists and disconnect if not found. + * @param element The service element name. + * @param connection The connection to check. + * @return true if service does not exist and was disconnected, false if found. + */ + bool DisconnectNonexistentService(const AppExecFwk::ElementName &element, + const sptr &connection); + +private: + ModularObjectConnectionManager() = default; + + std::mutex connectionMutex_; + std::map>> connectionRecords_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_CONNECTION_MANAGER_H diff --git a/frameworks/c/ability_runtime/include/modular_object_extension_types.h b/frameworks/c/ability_runtime/include/modular_object_extension_types.h new file mode 100644 index 0000000000..2e1caa3657 --- /dev/null +++ b/frameworks/c/ability_runtime/include/modular_object_extension_types.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 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 ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_TYPES_H +#define ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_TYPES_H + +#include +#include "extension_ability_info.h" +#include "modular_object_extension_ability.h" +#include "native_extension/context_impl.h" +#include "native_extension/extension_ability_impl.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +struct OH_AbilityRuntime_ModularObjectExtensionContext : public AbilityRuntime_Context { +}; + +struct OH_AbilityRuntime_ModularObjectExtensionInstance : public AbilityRuntime_ExtensionInstance { + std::shared_ptr context; + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc = nullptr; +}; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_TYPES_H diff --git a/frameworks/c/ability_runtime/src/c_modular_object_connection_callback.cpp b/frameworks/c/ability_runtime/src/c_modular_object_connection_callback.cpp new file mode 100644 index 0000000000..117b2d9061 --- /dev/null +++ b/frameworks/c/ability_runtime/src/c_modular_object_connection_callback.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2026 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 "c_modular_object_connection_callback.h" + +#include +#include + +#include "c_modular_object_utils.h" +#include "hilog_tag_wrapper.h" +#include "ipc_inner_object.h" +#include "modular_object_connection_manager.h" +#include "modular_object_extension_types.h" +#include "want_manager.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +static std::map, + ModularObjectConnectionKeyCompare> g_connectCallbacks; +static std::recursive_mutex g_connectCallbacksLock; +static int64_t g_serialNumber = 0; +} // namespace + +namespace CModularObjectConnectionUtils { +int64_t InsertConnection(sptr callback) +{ + std::lock_guard lock(g_connectCallbacksLock); + if (callback == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "null callback"); + return -1; + } + int64_t connectId = g_serialNumber; + ModularObjectConnectionKey key; + key.id = g_serialNumber; + callback->SetConnectionId(connectId); + g_connectCallbacks.emplace(key, callback); + if (g_serialNumber < INT64_MAX) { + g_serialNumber++; + } else { + g_serialNumber = 0; + } + TAG_LOGD(AAFwkTag::EXT, "Connection inserted, id: %{public}" PRId64, connectId); + return connectId; +} + +void RemoveConnectionCallback(int64_t connectionId) +{ + sptr callback; + std::lock_guard lock(g_connectCallbacksLock); + auto item = std::find_if(g_connectCallbacks.begin(), g_connectCallbacks.end(), + [&connectionId](const auto &obj) { return connectionId == obj.first.id; }); + if (item != g_connectCallbacks.end()) { + callback = item->second; + g_connectCallbacks.erase(item); + } else { + TAG_LOGW(AAFwkTag::EXT, "Connection not found, id: %{public}" PRId64, connectionId); + } +} + +void FindConnection(int64_t connectionId, sptr &callback) +{ + std::lock_guard lock(g_connectCallbacksLock); + auto item = std::find_if(g_connectCallbacks.begin(), g_connectCallbacks.end(), + [&connectionId](const auto &obj) { return connectionId == obj.first.id; }); + if (item != g_connectCallbacks.end()) { + callback = item->second; + } +} +} // namespace CModularObjectConnectionUtils + +CModularObjectConnectionCallback::CModularObjectConnectionCallback( + const std::shared_ptr &state) + : state_(state) +{} + +void CModularObjectConnectionCallback::OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) +{ + TAG_LOGD(AAFwkTag::EXT, "ConnectDone:%{public}s, %{public}d", element.GetAbilityName().c_str(), resultCode); + if (remoteObject == nullptr) { + return; + } + auto state = state_.lock(); + if (state == nullptr) { + return; + } + + OH_AbilityRuntime_ConnectOptions_OnConnectCallback callback = nullptr; + OH_AbilityRuntime_ConnectOptions *owner = nullptr; + { + std::lock_guard guard(state->mutex); + if (!state->alive) { + return; + } + callback = state->onConnectCallback; + owner = state->owner; + } + if (callback == nullptr) { + return; + } + + AbilityBase_Element cElement; + if (!CModularObjectUtils::BuildElement(element, cElement)) { + CModularObjectUtils::NotifyFailed(state, ABILITY_RUNTIME_ERROR_CODE_INTERNAL); + return; + } + sptr remoteObjectCopy = remoteObject; + OHIPCRemoteProxy *proxy = CreateIPCRemoteProxy(remoteObjectCopy); + if (proxy == nullptr) { + CModularObjectUtils::DestroyElement(cElement); + CModularObjectUtils::NotifyFailed(state, ABILITY_RUNTIME_ERROR_CODE_INTERNAL); + return; + } + callback(owner, &cElement, proxy); + CModularObjectUtils::DestroyElement(cElement); +} + +void CModularObjectConnectionCallback::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, + int resultCode) +{ + TAG_LOGD(AAFwkTag::EXT, "DisconnectDone:%{public}s, %{public}d", element.GetAbilityName().c_str(), resultCode); + auto state = state_.lock(); + if (state == nullptr) { + TAG_LOGW(AAFwkTag::EXT, "state null"); + CModularObjectConnectionUtils::RemoveConnectionCallback(connectionId_); + return; + } + OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback callback = nullptr; + OH_AbilityRuntime_ConnectOptions *owner = nullptr; + { + std::lock_guard guard(state->mutex); + if (state->alive) { + callback = state->onDisconnectCallback; + owner = state->owner; + } else { + TAG_LOGW(AAFwkTag::EXT, "state not alive"); + } + } + + if (callback == nullptr) { + TAG_LOGW(AAFwkTag::EXT, "callback null"); + return; + } + AbilityBase_Element cElement; + if (CModularObjectUtils::BuildElement(element, cElement)) { + callback(owner, &cElement); + CModularObjectUtils::DestroyElement(cElement); + } else { + CModularObjectUtils::NotifyFailed(state, ABILITY_RUNTIME_ERROR_CODE_INTERNAL); + } +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/c/ability_runtime/src/c_modular_object_utils.cpp b/frameworks/c/ability_runtime/src/c_modular_object_utils.cpp new file mode 100644 index 0000000000..4245e8e81c --- /dev/null +++ b/frameworks/c/ability_runtime/src/c_modular_object_utils.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2026 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 "c_modular_object_utils.h" + +#include "ability_business_error_utils.h" +#include "ability_manager_errors.h" +#include "hilog_tag_wrapper.h" +#include "native_extension/context_impl.h" +#include "securec.h" +#include "want_manager.h" +#include "want_utils.h" + +using namespace OHOS::AAFwk; + +namespace OHOS { +namespace AbilityRuntime { +AbilityRuntime_ErrorCode CModularObjectUtils::ConvertConnectBusinessErrorCode(int32_t errCode) +{ + switch (errCode) { + case ABILITY_VISIBLE_FALSE_DENY_REQUEST: + return ABILITY_RUNTIME_ERROR_CODE_VISIBILITY_VERIFICATION_FAILED; + case ERR_STATIC_CFG_PERMISSION: + return ABILITY_RUNTIME_ERROR_CODE_STATIC_CFG_PERMISSION; + case ERR_CROSS_USER: + return ABILITY_RUNTIME_ERROR_CODE_CROSS_USER_OPERATION; + case ERR_CHECK_CALL_FROM_BACKGROUND_FAILED: + return ABILITY_RUNTIME_ERROR_CODE_NO_RUNNING_ABILITIES_WITH_UI; + case ERR_FREQ_START_ABILITY: + return ABILITY_RUNTIME_ERROR_CODE_UPPER_RATE_LIMIT; + case ERR_REACH_UPPER_LIMIT: + case ERR_UPPER_LIMIT: + return ABILITY_RUNTIME_ERROR_CODE_UPPER_CONNECTION_NUMBER_LIMIT; + case ERR_MODULAR_OBJECT_DISABLED: + return ABILITY_RUNTIME_ERROR_CODE_MODULAR_OBJECT_EXTENSION_DISABLED; + case ERR_NO_RUNNING_ABILITIES_WITH_UI: + return ABILITY_RUNTIME_ERROR_CODE_NO_RUNNING_ABILITIES_WITH_UI; + default: + return ConvertToCommonBusinessErrorCode(errCode); + } +} + +bool CModularObjectUtils::BuildElement(const AppExecFwk::ElementName &elementName, AbilityBase_Element &element) +{ + element.bundleName = nullptr; + element.moduleName = nullptr; + element.abilityName = nullptr; + if (!CopyToCString(elementName.GetBundleName(), element.bundleName)) { + return false; + } + if (!CopyToCString(elementName.GetModuleName(), element.moduleName)) { + delete[] element.bundleName; + element.bundleName = nullptr; + return false; + } + if (!CopyToCString(elementName.GetAbilityName(), element.abilityName)) { + delete[] element.bundleName; + delete[] element.moduleName; + element.bundleName = nullptr; + element.moduleName = nullptr; + return false; + } + return true; +} + +void CModularObjectUtils::DestroyElement(AbilityBase_Element &element) +{ + delete[] element.bundleName; + delete[] element.moduleName; + delete[] element.abilityName; + element.bundleName = nullptr; + element.moduleName = nullptr; + element.abilityName = nullptr; +} + +bool CModularObjectUtils::CopyToCString(const std::string &src, char *&dst) +{ + dst = new (std::nothrow) char[src.size() + 1]; + if (dst == nullptr) { + return false; + } + if (strcpy_s(dst, src.size() + 1, src.c_str()) != EOK) { + delete[] dst; + dst = nullptr; + return false; + } + return true; +} + +AbilityRuntime_ErrorCode CModularObjectUtils::TransformWant(AbilityBase_Want *want, AAFwk::Want &abilityWant) +{ + auto ret = CheckWant(want); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid want"); + return ret; + } + auto errCode = CWantManager::TransformToWant(*want, false, abilityWant); + if (errCode != ABILITY_BASE_ERROR_CODE_NO_ERROR) { + TAG_LOGE(AAFwkTag::APPKIT, "transform want failed: %{public}d", errCode); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode CModularObjectUtils::CheckContextAndToken(AbilityRuntime_ContextHandle context, + sptr &token) +{ + if (context == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null context"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + auto contextPtr = context->context.lock(); + if (contextPtr == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "context not exist"); + return ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST; + } + token = contextPtr->GetToken(); + if (token == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null token"); + return ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST; + } + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +void CModularObjectUtils::NotifyFailed(std::shared_ptr state, + int32_t businessErrorCode) +{ + if (state == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "state null"); + return; + } + OH_AbilityRuntime_ConnectOptions_OnFailedCallback callback = nullptr; + OH_AbilityRuntime_ConnectOptions *owner = nullptr; + { + std::lock_guard guard(state->mutex); + if (!state->alive) { + return; + } + callback = state->onFailedCallback; + owner = state->owner; + } + if (callback != nullptr) { + callback(owner, static_cast(businessErrorCode)); + } +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/c/ability_runtime/src/connect_options.cpp b/frameworks/c/ability_runtime/src/connect_options.cpp new file mode 100644 index 0000000000..447c3994b7 --- /dev/null +++ b/frameworks/c/ability_runtime/src/connect_options.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2026 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 "connect_options.h" + +#include + +#include "connect_options_impl.h" +#include "hilog_tag_wrapper.h" + +namespace { +std::shared_ptr GetState(OH_AbilityRuntime_ConnectOptions *connectOptions) +{ + if (connectOptions == nullptr || connectOptions->state == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid connectOptions"); + return nullptr; + } + return connectOptions->state; +} +} // namespace + +#ifdef __cplusplus +extern "C" { +#endif + +OH_AbilityRuntime_ConnectOptions* OH_AbilityRuntime_CreateConnectOptions(void) +{ + auto connectOptions = new (std::nothrow) OH_AbilityRuntime_ConnectOptions(); + if (connectOptions == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null connectOptions"); + return nullptr; + } + + auto state = std::make_shared(); + if (state == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null state"); + delete connectOptions; + return nullptr; + } + state->owner = connectOptions; + connectOptions->state = state; + return connectOptions; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_DestroyConnectOptions(OH_AbilityRuntime_ConnectOptions *connectOptions) +{ + auto state = GetState(connectOptions); + if (state == nullptr) { + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + + { + std::lock_guard guard(state->mutex); + state->alive = false; + state->owner = nullptr; + state->onConnectCallback = nullptr; + state->onDisconnectCallback = nullptr; + state->onFailedCallback = nullptr; + } + delete connectOptions; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectOptions_SetOnConnectCallback( + OH_AbilityRuntime_ConnectOptions *connectOptions, + OH_AbilityRuntime_ConnectOptions_OnConnectCallback onConnectCallback) +{ + auto state = GetState(connectOptions); + if (state == nullptr || onConnectCallback == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid params"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + std::lock_guard guard(state->mutex); + if (!state->alive) { + TAG_LOGE(AAFwkTag::APPKIT, "connect options already destroyed"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + state->onConnectCallback = onConnectCallback; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectOptions_SetOnDisconnectCallback( + OH_AbilityRuntime_ConnectOptions *connectOptions, + OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback onDisconnectCallback) +{ + auto state = GetState(connectOptions); + if (state == nullptr || onDisconnectCallback == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid params"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + std::lock_guard guard(state->mutex); + if (!state->alive) { + TAG_LOGE(AAFwkTag::APPKIT, "connect options already destroyed"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + state->onDisconnectCallback = onDisconnectCallback; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectOptions_SetOnFailedCallback( + OH_AbilityRuntime_ConnectOptions *connectOptions, + OH_AbilityRuntime_ConnectOptions_OnFailedCallback onFailedCallback) +{ + auto state = GetState(connectOptions); + if (state == nullptr || onFailedCallback == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid params"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + std::lock_guard guard(state->mutex); + if (!state->alive) { + TAG_LOGE(AAFwkTag::APPKIT, "connect options already destroyed"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + state->onFailedCallback = onFailedCallback; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/frameworks/c/ability_runtime/src/modular_object_ability_connection.cpp b/frameworks/c/ability_runtime/src/modular_object_ability_connection.cpp new file mode 100644 index 0000000000..fc93cc7d6c --- /dev/null +++ b/frameworks/c/ability_runtime/src/modular_object_ability_connection.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2026 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 "modular_object_ability_connection.h" + +#include + +#include "connection_manager.h" +#include "hilog_tag_wrapper.h" +#include "modular_object_connection_manager.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr int32_t DIED = -1; +} // namespace + +void ModularObjectAbilityConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + TAG_LOGI(AAFwkTag::EXT, + "OnAbilityConnectDone, bundleName:%{public}s, abilityName:%{public}s, resultCode:%{public}d", + element.GetBundleName().c_str(), element.GetAbilityName().c_str(), resultCode); + std::vector> callbacks; + { + std::lock_guard lock(modularMutex_); + callbacks = GetCallbackList(); + if (callbacks.empty()) { + TAG_LOGW(AAFwkTag::EXT, "empty callbackList"); + return; + } + + SetRemoteObject(remoteObject); + SetResultCode(resultCode); + SetConnectionState(CONNECTION_STATE_CONNECTED); + } + sptr connection(this); + if (ModularObjectConnectionManager::GetInstance().DisconnectNonexistentService(element, connection)) { + TAG_LOGW(AAFwkTag::EXT, "No need onConnect callback"); + return; + } + + auto item = callbacks.begin(); + while (item != callbacks.end()) { + (*item)->OnAbilityConnectDone(element, remoteObject, resultCode); + item++; + } +} + +void ModularObjectAbilityConnection::OnAbilityDisconnectDone( + const AppExecFwk::ElementName &element, int resultCode) +{ + TAG_LOGI(AAFwkTag::EXT, + "OnAbilityDisconnectDone, bundleName:%{public}s, abilityName:%{public}s, resultCode:%{public}d", + element.GetBundleName().c_str(), element.GetAbilityName().c_str(), resultCode); + std::vector> callbacks; + { + std::lock_guard lock(modularMutex_); + SetConnectionState(CONNECTION_STATE_DISCONNECTED); + callbacks = GetCallbackList(); + if (callbacks.empty()) { + TAG_LOGE(AAFwkTag::EXT, "empty callbackList"); + return; + } + } + + // if resultCode < 0 that means the service is dead + if (resultCode == DIED) { + sptr connection(this); + ModularObjectConnectionManager::GetInstance().RemoveConnection(connection); + resultCode = DIED + 1; + } + + auto item = callbacks.begin(); + while (item != callbacks.end()) { + (*item)->OnAbilityDisconnectDone(element, resultCode); + item++; + } + SetRemoteObject(nullptr); +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/c/ability_runtime/src/modular_object_connection_manager.cpp b/frameworks/c/ability_runtime/src/modular_object_connection_manager.cpp new file mode 100644 index 0000000000..7afd66db61 --- /dev/null +++ b/frameworks/c/ability_runtime/src/modular_object_connection_manager.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2026 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 "modular_object_connection_manager.h" + +#include "ability_manager_client.h" +#include "hilog_tag_wrapper.h" +#include "modular_object_ability_connection.h" + +namespace OHOS { +namespace AbilityRuntime { +ModularObjectConnectionManager &ModularObjectConnectionManager::GetInstance() +{ + static ModularObjectConnectionManager instance; + return instance; +} + +ErrCode ModularObjectConnectionManager::ConnectModularObjectExtension(const AAFwk::Want &want, + const sptr &callback) +{ + if (callback == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "Invalid callback"); + return ERR_INVALID_VALUE; + } + sptr abilityConnection = sptr::MakeSptr(); + if (abilityConnection == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "Failed to create connection"); + return ERR_INVALID_VALUE; + } + abilityConnection->AddConnectCallback(callback); + abilityConnection->SetConnectionState(CONNECTION_STATE_CONNECTING); + ModularObjectConnectionInfo info(abilityConnection, want.GetOperation()); + { + std::lock_guard guard(connectionMutex_); + auto &callbacks = connectionRecords_[info]; + callbacks.push_back(callback); + } + ErrCode ret = AAFwk::AbilityManagerClient::GetInstance()->ConnectAbilityWithExtensionType( + want, abilityConnection, nullptr, AAFwk::DEFAULT_INVAL_VALUE, + AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::EXT, "Connect failed: %{public}d", ret); + std::lock_guard guard(connectionMutex_); + connectionRecords_.erase(info); + return ret; + } + return ERR_OK; +} + +ErrCode ModularObjectConnectionManager::DisconnectModularObjectExtension( + const sptr &callback) +{ + if (callback == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "Invalid callback"); + return ERR_INVALID_VALUE; + } + + sptr abilityConnection; + { + std::lock_guard guard(connectionMutex_); + for (auto iter = connectionRecords_.begin(); iter != connectionRecords_.end(); ++iter) { + auto &callbacks = iter->second; + auto cbIter = std::find(callbacks.begin(), callbacks.end(), callback); + if (cbIter != callbacks.end()) { + abilityConnection = iter->first.abilityConnection; + callbacks.erase(cbIter); + if (callbacks.empty()) { + connectionRecords_.erase(iter); + } + break; + } + } + } + + if (abilityConnection == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "Connection not found"); + return AAFwk::CONNECTION_NOT_EXIST; + } + + ErrCode ret = AAFwk::AbilityManagerClient::GetInstance()->DisconnectAbility(abilityConnection); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::EXT, "Disconnect failed: %{public}d", ret); + } + return ret; +} + +bool ModularObjectConnectionManager::RemoveConnection( + const sptr &connection) +{ + std::lock_guard lock(connectionMutex_); + TAG_LOGD(AAFwkTag::EXT, "connectionRecordsSize: %{public}zu", connectionRecords_.size()); + + bool isDisconnect = false; + auto iter = connectionRecords_.begin(); + while (iter != connectionRecords_.end()) { + ModularObjectConnectionInfo connectionInfo = iter->first; + if (connectionInfo.abilityConnection == connection) { + TAG_LOGD(AAFwkTag::EXT, "Remove connection"); + iter = connectionRecords_.erase(iter); + isDisconnect = true; + } else { + ++iter; + } + } + return isDisconnect; +} + +bool ModularObjectConnectionManager::DisconnectNonexistentService( + const AppExecFwk::ElementName &element, + const sptr &connection) +{ + bool exist = false; + std::map>> connectionRecords; + { + std::lock_guard lock(connectionMutex_); + connectionRecords = connectionRecords_; + } + TAG_LOGD(AAFwkTag::EXT, "connectionRecordsSize: %{public}zu", connectionRecords.size()); + + for (auto &&record : connectionRecords) { + ModularObjectConnectionInfo connectionInfo = record.first; + if (connectionInfo.abilityConnection == connection && + connectionInfo.connectReceiver.GetBundleName() == element.GetBundleName()) { + TAG_LOGD(AAFwkTag::EXT, "find connection"); + exist = true; + break; + } + } + if (!exist) { + TAG_LOGE(AAFwkTag::EXT, "ext need disconnect"); + AAFwk::AbilityManagerClient::GetInstance()->DisconnectAbility(connection); + return true; + } + return false; +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/c/ability_runtime/src/modular_object_extension_ability.cpp b/frameworks/c/ability_runtime/src/modular_object_extension_ability.cpp new file mode 100644 index 0000000000..f4877e7983 --- /dev/null +++ b/frameworks/c/ability_runtime/src/modular_object_extension_ability.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_ability.h" + +#include "hilog_tag_wrapper.h" +#include "modular_object_extension_types.h" + +namespace { + +AbilityRuntime_ErrorCode CheckMoeInstance(OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModularObjectExtensionInstance **moeInstance) +{ + if (instance == nullptr || moeInstance == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid params"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + auto *inner = reinterpret_cast(instance); + if (inner->type != OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid extension type"); + return ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE; + } + *moeInstance = inner; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} +} // namespace + +#ifdef __cplusplus +extern "C" { +#endif + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc) +{ + if (onCreateFunc == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null onCreateFunc"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + OH_AbilityRuntime_ModularObjectExtensionInstance *inner = nullptr; + auto ret = CheckMoeInstance(instance, &inner); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + inner->onCreateFunc = onCreateFunc; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDestroyFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc) +{ + if (onDestroyFunc == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null onDestroyFunc"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + OH_AbilityRuntime_ModularObjectExtensionInstance *inner = nullptr; + auto ret = CheckMoeInstance(instance, &inner); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + inner->onDestroyFunc = onDestroyFunc; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnConnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc) +{ + if (onConnectFunc == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null onConnectFunc"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + OH_AbilityRuntime_ModularObjectExtensionInstance *inner = nullptr; + auto ret = CheckMoeInstance(instance, &inner); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + inner->onConnectFunc = onConnectFunc; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDisconnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc) +{ + if (onDisconnectFunc == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null onDisconnectFunc"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + OH_AbilityRuntime_ModularObjectExtensionInstance *inner = nullptr; + auto ret = CheckMoeInstance(instance, &inner); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + inner->onDisconnectFunc = onDisconnectFunc; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, OH_AbilityRuntime_ModObjExtensionContextHandle *context) +{ + if (context == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null context"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + OH_AbilityRuntime_ModularObjectExtensionInstance *inner = nullptr; + auto ret = CheckMoeInstance(instance, &inner); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + if (inner->context == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null inner context"); + return ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST; + } + *context = inner->context.get(); + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase( + AbilityRuntime_ExtensionInstanceHandle baseExtensionInstance, + OH_AbilityRuntime_ModObjExtensionInstanceHandle* modObjExtensionInstance) +{ + if (baseExtensionInstance == nullptr || modObjExtensionInstance == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid params"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + if (baseExtensionInstance->type != OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid extension type"); + return ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE; + } + *modObjExtensionInstance = reinterpret_cast(baseExtensionInstance); + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/frameworks/c/ability_runtime/src/modular_object_extension_context.cpp b/frameworks/c/ability_runtime/src/modular_object_extension_context.cpp new file mode 100644 index 0000000000..c3d7eae8eb --- /dev/null +++ b/frameworks/c/ability_runtime/src/modular_object_extension_context.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_context.h" + +#include "ability_business_error_utils.h" +#include "ability_manager_client.h" +#include "hilog_tag_wrapper.h" +#include "modular_object_extension_context_impl.h" +#include "modular_object_extension_types.h" +#include "start_options_impl.h" +#include "want_manager.h" +#include "want_utils.h" + +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AbilityRuntime; + +namespace { +AbilityRuntime_ErrorCode CheckMoeContext(OH_AbilityRuntime_ModObjExtensionContextHandle context, + std::shared_ptr &contextPtr) +{ + if (context == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null context"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + if (context->type != AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid extension type"); + return ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE; + } + contextPtr = context->context.lock(); + if (contextPtr == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "context not exist"); + return ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST; + } + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode TransformWant(const AbilityBase_Want *want, Want &abilityWant) +{ + auto ret = CheckWant(const_cast(want)); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid want"); + return ret; + } + auto errCode = CWantManager::TransformToWant(*want, false, abilityWant); + if (errCode != ABILITY_BASE_ERROR_CODE_NO_ERROR) { + TAG_LOGE(AAFwkTag::APPKIT, "transform want failed: %{public}d", errCode); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} +} // namespace + +#ifdef __cplusplus +extern "C" { +#endif + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_GetBaseContext( + OH_AbilityRuntime_ModObjExtensionContextHandle modObjExtensionContext, AbilityRuntime_ContextHandle* baseContext) +{ + if (modObjExtensionContext == nullptr || baseContext == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid params"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + if (modObjExtensionContext->type != AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT) { + TAG_LOGE(AAFwkTag::APPKIT, "invalid extension type"); + return ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE; + } + *baseContext = static_cast(modObjExtensionContext); + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility( + OH_AbilityRuntime_ModObjExtensionContextHandle context, const AbilityBase_Want *want) +{ + std::shared_ptr contextPtr; + auto ret = CheckMoeContext(context, contextPtr); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + Want abilityWant; + ret = TransformWant(want, abilityWant); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + auto moeContext = std::static_pointer_cast(contextPtr); + auto err = moeContext->StartSelfUIAbility(abilityWant); + return ConvertToAPI17BusinessErrorCode(err); +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions( + OH_AbilityRuntime_ModObjExtensionContextHandle context, const AbilityBase_Want *want, + const AbilityRuntime_StartOptions *options) +{ + if (options == nullptr) { + TAG_LOGE(AAFwkTag::APPKIT, "null options"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + std::shared_ptr contextPtr; + auto ret = CheckMoeContext(context, contextPtr); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + Want abilityWant; + ret = TransformWant(want, abilityWant); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + auto startOptions = const_cast(options)->GetInnerStartOptions(); + auto moeContext = std::static_pointer_cast(contextPtr); + auto err = moeContext->StartSelfUIAbilityWithStartOptions(abilityWant, startOptions); + return ConvertToAPI17BusinessErrorCode(err); +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf( + OH_AbilityRuntime_ModObjExtensionContextHandle context) +{ + std::shared_ptr contextPtr; + auto ret = CheckMoeContext(context, contextPtr); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + auto moeContext = std::static_pointer_cast(contextPtr); + auto err = moeContext->TerminateSelf(); + return ConvertToCommonBusinessErrorCode(err); +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/frameworks/c/ability_runtime/src/modular_object_extension_manager.cpp b/frameworks/c/ability_runtime/src/modular_object_extension_manager.cpp index 21cd210ab0..cf5d6328d3 100644 --- a/frameworks/c/ability_runtime/src/modular_object_extension_manager.cpp +++ b/frameworks/c/ability_runtime/src/modular_object_extension_manager.cpp @@ -15,11 +15,24 @@ #include "ability_runtime/modular_object_extension_manager.h" +#include "modular_object_extension_manager.h" + +#include +#include +#include + #include "ability_business_error_utils.h" #include "ability_manager_client.h" #include "ability_manager/include/modular_object_extension_info.h" +#include "connect_options_impl.h" +#include "c_modular_object_connection_callback.h" +#include "c_modular_object_utils.h" #include "hilog_tag_wrapper.h" -#include "want_manager.h" +#include "modular_object_connection_manager.h" + +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AbilityRuntime; struct OH_AbilityRuntime_AllModularObjectExtensionInfos { std::vector allMoeInfos; @@ -29,11 +42,73 @@ struct OH_AbilityRuntime_AllModularObjectExtensionInfos { extern "C" { #endif +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectModularObjectExtensionAbility(AbilityBase_Want *want, + OH_AbilityRuntime_ConnectOptions *connectOptions, int64_t *connectionId) +{ + TAG_LOGD(AAFwkTag::EXT, "Connect Moe"); + if (connectOptions == nullptr || connectionId == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "invalid params"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + if (connectOptions->state == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "null connectOptions state"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + { + std::lock_guard guard(connectOptions->state->mutex); + if (!connectOptions->state->alive) { + TAG_LOGE(AAFwkTag::EXT, "connect options already destroyed"); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + } + + Want abilityWant; + auto ret = CModularObjectUtils::TransformWant(want, abilityWant); + if (ret != ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) { + return ret; + } + + auto callback = sptr::MakeSptr(connectOptions->state); + if (callback == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "Failed to create connect callback"); + return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; + } + + int64_t newConnectionId = CModularObjectConnectionUtils::InsertConnection(callback); + if (newConnectionId < 0) { + TAG_LOGE(AAFwkTag::EXT, "Failed to insert connection"); + return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; + } + + int32_t innerRet = ModularObjectConnectionManager::GetInstance().ConnectModularObjectExtension( + abilityWant, callback); + if (innerRet != ERR_OK) { + CModularObjectConnectionUtils::RemoveConnectionCallback(newConnectionId); + return CModularObjectUtils::ConvertConnectBusinessErrorCode(innerRet); + } + + *connectionId = newConnectionId; + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} + +AbilityRuntime_ErrorCode OH_AbilityRuntime_DisconnectModularObjectExtensionAbility(int64_t connectionId) +{ + TAG_LOGD(AAFwkTag::EXT, "Disonnect Moe"); + sptr callback; + CModularObjectConnectionUtils::FindConnection(connectionId, callback); + if (callback == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "Connection not found, id: %{public}" PRId64, connectionId); + return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + } + int32_t innerRet = ModularObjectConnectionManager::GetInstance().DisconnectModularObjectExtension(callback); + return CModularObjectUtils::ConvertConnectBusinessErrorCode(innerRet); +} + AbilityRuntime_ErrorCode OH_AbilityRuntime_ReleaseAllExtensionInfos( OH_AbilityRuntime_AllModObjExtensionInfosHandle *allExtensionInfos) { if (!allExtensionInfos || !*allExtensionInfos) { - TAG_LOGD(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGD(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; } delete *allExtensionInfos; @@ -45,7 +120,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoLaunchMo OH_AbilityRuntime_ModObjExtensionInfoHandle extensionInfo, OH_AbilityRuntime_LaunchMode *launchMode) { if (!extensionInfo || !launchMode) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } auto info = reinterpret_cast(extensionInfo); @@ -57,7 +132,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoProcessM OH_AbilityRuntime_ModObjExtensionInfoHandle extensionInfo, OH_AbilityRuntime_ProcessMode *processMode) { if (!extensionInfo || !processMode) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } auto info = reinterpret_cast(extensionInfo); @@ -69,7 +144,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoThreadMo OH_AbilityRuntime_ModObjExtensionInfoHandle extensionInfo, OH_AbilityRuntime_ThreadMode *threadMode) { if (!extensionInfo || !threadMode) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } auto info = reinterpret_cast(extensionInfo); @@ -81,21 +156,21 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoElementN OH_AbilityRuntime_ModObjExtensionInfoHandle extensionInfo, AbilityBase_Element *element) { if (!extensionInfo || !element) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } auto info = reinterpret_cast(extensionInfo); char* newBundleName = strdup(info->bundleName.c_str()); if (!newBundleName) { - TAG_LOGE(AAFwkTag::APPKIT, "strdup bundleName failed"); + TAG_LOGE(AAFwkTag::EXT, "strdup bundleName failed"); return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; } char* newModuleName = strdup(info->moduleName.c_str()); if (!newModuleName) { free(newBundleName); - TAG_LOGE(AAFwkTag::APPKIT, "strdup moduleName failed"); + TAG_LOGE(AAFwkTag::EXT, "strdup moduleName failed"); return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; } @@ -103,7 +178,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoElementN if (!newAbilityName) { free(newBundleName); free(newModuleName); - TAG_LOGE(AAFwkTag::APPKIT, "strdup abilityName failed"); + TAG_LOGE(AAFwkTag::EXT, "strdup abilityName failed"); return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; } @@ -117,7 +192,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoDisableS OH_AbilityRuntime_ModObjExtensionInfoHandle extensionInfo, bool *isDisabled) { if (!extensionInfo || !isDisabled) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } auto info = reinterpret_cast(extensionInfo); @@ -129,7 +204,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_AcquireSelfModularObjectExtensionInfo OH_AbilityRuntime_AllModObjExtensionInfosHandle *outOwnedAllExtensionInfos) { if (!outOwnedAllExtensionInfos) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } @@ -138,7 +213,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_AcquireSelfModularObjectExtensionInfo std::vector dataList; auto ret = OHOS::AAFwk::AbilityManagerClient::GetInstance()->QuerySelfModularObjectExtensionInfos(dataList); if (ret != OHOS::ERR_OK) { - TAG_LOGE(AAFwkTag::APPKIT, "get modular object extension info inner error: %{public}d", ret); + TAG_LOGE(AAFwkTag::EXT, "get modular object extension info inner error: %{public}d", ret); return ConvertToCommonBusinessErrorCode(ret); } infos->allMoeInfos = dataList; @@ -150,7 +225,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetCountFromAllModObjExtensionInfos( OH_AbilityRuntime_AllModObjExtensionInfosHandle allExtensionInfos, size_t *count) { if (!allExtensionInfos || !count) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } *count = allExtensionInfos->allMoeInfos.size(); @@ -162,17 +237,17 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModObjExtensionInfoByIndex( OH_AbilityRuntime_ModObjExtensionInfoHandle *extensionInfo) { if (!allExtensionInfos || !extensionInfo) { - TAG_LOGE(AAFwkTag::APPKIT, "null parameter"); + TAG_LOGE(AAFwkTag::EXT, "null parameter"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } if (index >= allExtensionInfos->allMoeInfos.size()) { - TAG_LOGE(AAFwkTag::APPKIT, "index out of range"); + TAG_LOGE(AAFwkTag::EXT, "index out of range"); return ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; } *extensionInfo = reinterpret_cast(&(allExtensionInfos->allMoeInfos[index])); if (*extensionInfo == nullptr) { - TAG_LOGE(AAFwkTag::APPKIT, "Failed to get extension info for index %zu", index); + TAG_LOGE(AAFwkTag::EXT, "Failed to get extension info for index %zu", index); return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; } return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; diff --git a/frameworks/native/ability/native/BUILD.gn b/frameworks/native/ability/native/BUILD.gn index 89eb1c6e1c..49e085bf32 100644 --- a/frameworks/native/ability/native/BUILD.gn +++ b/frameworks/native/ability/native/BUILD.gn @@ -2382,6 +2382,7 @@ group("extension_module") { ":embedded_ui_extension_module", ":service_extension_module", ":ui_extension_module", + ":modular_object_extension_module", ] if (ability_runtime_action_extension) { deps += [ ":action_extension_module" ] @@ -3899,3 +3900,124 @@ ohos_shared_library("app_service_extension_module") { subsystem_name = "ability" part_name = "ability_runtime" } + +config("modular_object_extension_config") { + visibility = [ ":*" ] + include_dirs = [ + "${ability_runtime_path}/interfaces/inner_api", + "${ability_runtime_path}/interfaces/inner_api/runtime/include", + "${ability_runtime_path}/interfaces/kits/native/ability/native/modular_object_extension", + "${ability_runtime_path}/interfaces/kits/native/ability/native", + "${ability_runtime_path}/interfaces/kits/native/ability/ability_runtime", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/context", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime", + "${ability_runtime_ndk_path}", + "${ability_runtime_ndk_path}/ability_runtime", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + ] +} + +ohos_shared_library("modular_object_extension") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + branch_protector_ret = "pac_ret" + + configs = [ + ":modular_object_extension_config", + "${ability_runtime_services_path}/common:optimize_config", + ] + + defines = [ "AMS_LOG_TAG = \"Ability\"" ] + defines += [ "AMS_LOG_DOMAIN = 0xD001300" ] + + sources = [ + "${ability_runtime_native_path}/ability/native/modular_object_extension/modular_object_extension.cpp", + "${ability_runtime_native_path}/ability/native/modular_object_extension/modular_object_extension_context_impl.cpp", + ] + + deps = [ + ":abilitykit_native", + ":abilitykit_utils", + ":extensionkit_native", + "${ability_runtime_innerkits_path}/ability_manager:ability_connect_callback_stub", + "${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}/ability:ability_context_native", + "${ability_runtime_native_path}/ability/native:ability_business_error", + "${ability_runtime_native_path}/appkit:app_context", + ] + + external_deps = [ + "ability_base:ability_base_want", + "ability_base:configuration", + "ability_base:want", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "hitrace:hitrace_meter", + "ipc:ipc_capi", + "ipc:ipc_core", + "ipc:ipc_napi", + "napi:ace_napi", + ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} + + ohos_shared_library("modular_object_extension_module") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + branch_protector_ret = "pac_ret" + + sources = [ "${ability_runtime_native_path}/ability/native/modular_object_extension/modular_object_extension_module_loader.cpp" ] + + configs = [ + ":modular_object_extension_config", + "${ability_runtime_services_path}/common:optimize_config", + ] + + deps = [ + ":modular_object_extension", + "${ability_runtime_innerkits_path}/runtime:runtime", + ] + + external_deps = [ + "ability_base:configuration", + "ability_base:session_info", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "ipc:ipc_capi", + "ipc:ipc_core", + "ipc:ipc_napi", + "json:nlohmann_json_static", + "napi:ace_napi", + ] + + if (ability_runtime_graphics) { + external_deps += [ "window_manager:libwm" ] + } + + relative_install_dir = "extensionability/" + subsystem_name = "ability" + part_name = "ability_runtime" +} \ No newline at end of file diff --git a/frameworks/native/ability/native/extension_ability_thread.cpp b/frameworks/native/ability/native/extension_ability_thread.cpp index 2c91507800..bfccea65ab 100644 --- a/frameworks/native/ability/native/extension_ability_thread.cpp +++ b/frameworks/native/ability/native/extension_ability_thread.cpp @@ -63,6 +63,7 @@ constexpr static char CALLER_INFO_QUERY_EXTENSION[] = "CallerInfoQueryExtension" constexpr static char ASSET_ACCELERATION_EXTENSION[] = "AssetAccelerationExtension"; constexpr static char SELECTION_EXTENSION[] = "SelectionExtensionAbility"; constexpr static char CONTENT_EMBED_EXTENSION[] = "ContentEmbedExtension"; +constexpr static char MODULAR_OBJECT_EXTENSION[] = "ModularObjectExtension"; } const std::map UI_EXTENSION_NAME_MAP = { @@ -183,6 +184,8 @@ void ExtensionAbilityThread::CreateExtensionAbilityName( #endif // SUPPORT_GRAPHICS else if (abilityInfo->extensionAbilityType == AppExecFwk::ExtensionAbilityType::CONTENT_EMBED) { abilityName = CONTENT_EMBED_EXTENSION; + } else if (abilityInfo->extensionAbilityType == AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT) { + abilityName = MODULAR_OBJECT_EXTENSION; } } diff --git a/frameworks/native/ability/native/modular_object_extension/modular_object_extension.cpp b/frameworks/native/ability/native/modular_object_extension/modular_object_extension.cpp new file mode 100644 index 0000000000..13793c1e73 --- /dev/null +++ b/frameworks/native/ability/native/modular_object_extension/modular_object_extension.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension.h" + +#include + +#include "hilog_tag_wrapper.h" +#include "ipc_inner_object.h" +#include "native_runtime.h" +#include "securec.h" +#include "want_manager.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr char PATH_SEPARATOR = '/'; +} + +ModularObjectExtension* ModularObjectExtension::Create() +{ + return new ModularObjectExtension(); +} + +void ModularObjectExtension::Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, + const sptr &token) +{ + ExtensionBase::Init(record, application, handler, token); + + moeInstance_ = std::make_shared(); + moeInstance_->type = AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + moeInstance_->extension = weak_from_this(); + + moeContext_ = std::make_shared(); + if (moeContext_ == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "failed to create modular object extension context"); + return; + } + moeContext_->type = AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto context = GetContext(); + if (context != nullptr) { + moeContext_->context = context->weak_from_this(); + } + moeInstance_->context = moeContext_; + + if (!LoadNativeExtensionModule()) { + TAG_LOGE(AAFwkTag::EXT, "failed to load modular object native extension module"); + } +} + +std::shared_ptr ModularObjectExtension::CreateAndInitContext( + const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, + const sptr &token) +{ + return ExtensionBase::CreateAndInitContext(record, application, handler, token); +} + +void ModularObjectExtension::OnStart(const AAFwk::Want &want) +{ + if (moeInstance_ == nullptr || moeInstance_->onCreateFunc == nullptr) { + return; + } + + AbilityBase_Want cWant; + AbilityBase_Element element; + if (!BuildCWant(want, cWant, element)) { + TAG_LOGE(AAFwkTag::EXT, "failed to build c want for OnStart"); + return; + } + moeInstance_->onCreateFunc(moeInstance_.get(), &cWant); + DestroyElement(element); +} + +void ModularObjectExtension::OnStop() +{ + if (moeInstance_ != nullptr && moeInstance_->onDestroyFunc != nullptr) { + moeInstance_->onDestroyFunc(moeInstance_.get()); + } +} + +sptr ModularObjectExtension::OnConnect(const AAFwk::Want &want) +{ + Extension::OnConnect(want); + if (moeInstance_ == nullptr || moeInstance_->onConnectFunc == nullptr) { + return nullptr; + } + + AbilityBase_Want cWant; + AbilityBase_Element element; + if (!BuildCWant(want, cWant, element)) { + TAG_LOGE(AAFwkTag::EXT, "failed to build c want for OnConnect"); + return nullptr; + } + OHIPCRemoteStub *stub = moeInstance_->onConnectFunc(moeInstance_.get(), &cWant); + DestroyElement(element); + if (stub == nullptr || stub->remote == nullptr) { + TAG_LOGE(AAFwkTag::EXT, "invalid remote stub returned from OnConnect callback"); + return nullptr; + } + return stub->remote; +} + +void ModularObjectExtension::OnDisconnect(const AAFwk::Want &want) +{ + Extension::OnDisconnect(want); + if (moeInstance_ != nullptr && moeInstance_->onDisconnectFunc != nullptr) { + moeInstance_->onDisconnectFunc(moeInstance_.get()); + } +} + +bool ModularObjectExtension::LoadNativeExtensionModule() +{ + if (moeInstance_ == nullptr || abilityInfo_ == nullptr) { + return false; + } + if (abilityInfo_->srcEntrance.empty()) { + TAG_LOGE(AAFwkTag::EXT, "srcEntrance is empty"); + return false; + } + + std::string srcPath = abilityInfo_->moduleName + PATH_SEPARATOR + abilityInfo_->srcEntrance; + std::string bundleModuleName = abilityInfo_->bundleName + PATH_SEPARATOR + abilityInfo_->moduleName; + size_t pos = srcPath.find_last_of(PATH_SEPARATOR); + std::string fileName = pos == std::string::npos ? srcPath : srcPath.substr(pos + 1); + return NativeRuntime::LoadModule(bundleModuleName, fileName, abilityInfo_->name, *moeInstance_); +} + +bool ModularObjectExtension::BuildCWant(const AAFwk::Want &want, AbilityBase_Want &cWant, + AbilityBase_Element &element) const +{ + auto ret = AAFwk::CWantManager::TransformToCWantWithoutElement(want, false, cWant); + if (ret != ABILITY_BASE_ERROR_CODE_NO_ERROR) { + return false; + } + element.bundleName = nullptr; + element.moduleName = nullptr; + element.abilityName = nullptr; + if (!BuildElement(want.GetElement(), element)) { + return false; + } + cWant.element = element; + return true; +} + +bool ModularObjectExtension::BuildElement(const AppExecFwk::ElementName &elementName, AbilityBase_Element &element) +{ + auto copyField = [](const std::string &src, char *&dst) -> bool { + dst = new (std::nothrow) char[src.size() + 1]; + if (dst == nullptr) { + return false; + } + if (strcpy_s(dst, src.size() + 1, src.c_str()) != EOK) { + delete[] dst; + dst = nullptr; + return false; + } + return true; + }; + if (!copyField(elementName.GetBundleName(), element.bundleName)) { + return false; + } + if (!copyField(elementName.GetModuleName(), element.moduleName)) { + delete[] element.bundleName; + element.bundleName = nullptr; + return false; + } + if (!copyField(elementName.GetAbilityName(), element.abilityName)) { + delete[] element.bundleName; + delete[] element.moduleName; + element.bundleName = nullptr; + element.moduleName = nullptr; + return false; + } + return true; +} + +void ModularObjectExtension::DestroyElement(AbilityBase_Element &element) +{ + delete[] element.bundleName; + delete[] element.moduleName; + delete[] element.abilityName; + element.bundleName = nullptr; + element.moduleName = nullptr; + element.abilityName = nullptr; +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/native/ability/native/modular_object_extension/modular_object_extension_context_impl.cpp b/frameworks/native/ability/native/modular_object_extension/modular_object_extension_context_impl.cpp new file mode 100644 index 0000000000..d639a4b347 --- /dev/null +++ b/frameworks/native/ability/native/modular_object_extension/modular_object_extension_context_impl.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_context_impl.h" + +#include "ability_manager_client.h" +#include "hilog_tag_wrapper.h" +#include "hitrace_meter.h" + +namespace OHOS { +namespace AbilityRuntime { +const size_t ModularObjectExtensionContext::CONTEXT_TYPE_ID( + std::hash {} ("ModularObjectExtensionContext")); + +ErrCode ModularObjectExtensionContext::StartSelfUIAbility(const AAFwk::Want &want) const +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + return AAFwk::AbilityManagerClient::GetInstance()->StartSelfUIAbility(want); +} + +ErrCode ModularObjectExtensionContext::StartSelfUIAbilityWithStartOptions(const AAFwk::Want &want, + const AAFwk::StartOptions &startOptions) const +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + return AAFwk::AbilityManagerClient::GetInstance()->StartSelfUIAbilityWithStartOptions(want, startOptions); +} + +ErrCode ModularObjectExtensionContext::TerminateSelf() +{ + return AAFwk::AbilityManagerClient::GetInstance()->TerminateAbility(token_, -1, nullptr); +} +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/frameworks/native/ability/native/modular_object_extension/modular_object_extension_module_loader.cpp b/frameworks/native/ability/native/modular_object_extension/modular_object_extension_module_loader.cpp new file mode 100644 index 0000000000..e716824654 --- /dev/null +++ b/frameworks/native/ability/native/modular_object_extension/modular_object_extension_module_loader.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_module_loader.h" + +#include + +#include "modular_object_extension.h" + +namespace OHOS::AbilityRuntime { +ModularObjectExtensionModuleLoader::ModularObjectExtensionModuleLoader() = default; +ModularObjectExtensionModuleLoader::~ModularObjectExtensionModuleLoader() = default; + +Extension *ModularObjectExtensionModuleLoader::Create(const std::unique_ptr &runtime) const +{ + return ModularObjectExtension::Create(); +} + +std::map ModularObjectExtensionModuleLoader::GetParams() +{ + std::map params; + params.insert(std::pair("type", "39")); + params.insert(std::pair("name", "modularObject")); + return params; +} + +extern "C" __attribute__((visibility("default"))) void* OHOS_EXTENSION_GetExtensionModule() +{ + return &ModularObjectExtensionModuleLoader::GetInstance(); +} +} // namespace OHOS::AbilityRuntime diff --git a/interfaces/inner_api/ability_manager/include/ability_manager_errors.h b/interfaces/inner_api/ability_manager/include/ability_manager_errors.h index 503840099c..f26e795cd9 100644 --- a/interfaces/inner_api/ability_manager/include/ability_manager_errors.h +++ b/interfaces/inner_api/ability_manager/include/ability_manager_errors.h @@ -1138,6 +1138,10 @@ enum { */ ERR_NOT_SUPPORT_SCREEN = 2099411, + ERR_MODULAR_OBJECT_DISABLED = 2099412, + + ERR_NO_RUNNING_ABILITIES_WITH_UI = 2099413, + /** * Native error(3000000) for target bundle not exist. */ diff --git a/interfaces/kits/c/ability_runtime/ability_runtime_common.h b/interfaces/kits/c/ability_runtime/ability_runtime_common.h index a7ad2fdfc1..79029e1b7a 100644 --- a/interfaces/kits/c/ability_runtime/ability_runtime_common.h +++ b/interfaces/kits/c/ability_runtime/ability_runtime_common.h @@ -71,6 +71,21 @@ typedef enum { * @since 15 */ ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE = 16000002, + /** + * @error Cannot start an invisible component. + * @since 26.0.0 + */ + ABILITY_RUNTIME_ERROR_CODE_VISIBILITY_VERIFICATION_FAILED = 16000004, + /** + * @error The specified process does not have the permission. + * @since 26.0.0 + */ + ABILITY_RUNTIME_ERROR_CODE_STATIC_CFG_PERMISSION = 16000005, + /** + * @error Cross-user operations are not allowed. + * @since 26.0.0 + */ + ABILITY_RUNTIME_ERROR_CODE_CROSS_USER_OPERATION = 16000006, /** * @error The crowdtesting application expires. * @since 15 @@ -153,6 +168,26 @@ typedef enum { * @since 21 */ ABILITY_RUNTIME_ERROR_CODE_MAIN_THREAD_NOT_SUPPORTED = 16000134, + /** + * @error The target application does not have running abilities with UI. + * @since 26.0.0 + */ + ABILITY_RUNTIME_ERROR_CODE_NO_RUNNING_ABILITIES_WITH_UI = 16000160, + /** + * @error The API call frequency is too high and exceeds the rate control limit. + * @since 26.0.0 + */ + ABILITY_RUNTIME_ERROR_CODE_UPPER_RATE_LIMIT = 16000161, + /** + * @error The number of connection exceeds limit. + * @since 26.0.0 + */ + ABILITY_RUNTIME_ERROR_CODE_UPPER_CONNECTION_NUMBER_LIMIT = 16000162, + /** + * @error The modular object extension is disabled. + * @since 26.0.0 + */ + ABILITY_RUNTIME_ERROR_CODE_MODULAR_OBJECT_EXTENSION_DISABLED = 16000163, } AbilityRuntime_ErrorCode; #ifdef __cplusplus diff --git a/interfaces/kits/c/ability_runtime/connect_options.h b/interfaces/kits/c/ability_runtime/connect_options.h new file mode 100644 index 0000000000..e10a8ae796 --- /dev/null +++ b/interfaces/kits/c/ability_runtime/connect_options.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2026 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. + */ + + /** + * @addtogroup AbilityRuntime + * @{ + * + * @brief Provides the definition of the C interface for the modular object extension manager. + * + * @since 26.0.0 + */ + +/** + * @file connect_options.h + * + * @brief Declares the connection options. + * + * @library libability_runtime.so + * @kit AbilityKit + * @syscap SystemCapability.Ability.AbilityRuntime.Core + * @since 26.0.0 + */ + +#ifndef ABILITY_RUNTIME_CONNECT_OPTIONS_H +#define ABILITY_RUNTIME_CONNECT_OPTIONS_H + +#include +#include "ability_runtime_common.h" +#include "ipc_cparcel.h" +#include "want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct AbilityBase_Want; +typedef struct AbilityBase_Want AbilityBase_Want; + +struct AbilityBase_Element; +typedef struct AbilityBase_Element AbilityBase_Element; + +/** + * @brief Defines the OH_AbilityRuntime_ConnectOptions structure type. + * + * @since 26.0.0 + */ +typedef struct OH_AbilityRuntime_ConnectOptions OH_AbilityRuntime_ConnectOptions; + +/** + * @brief The callback interface is invoked when the connection succeeds. + * + * @param connectOptions Represents a pointer to an {@link + * OH_AbilityRuntime_ConnectOptions} instance. + * @param element Represents the element name of the modular object extension ability. + * @param proxy Represents the remote object instance. + * + * @since 26.0.0 + */ +typedef void (*OH_AbilityRuntime_ConnectOptions_OnConnectCallback)( + OH_AbilityRuntime_ConnectOptions *connectOptions, AbilityBase_Element *element, OHIPCRemoteProxy *proxy); + +/** + * @brief The callback interface is invoked when the disconnection occurs. + * + * @param connectOptions Represents a pointer to an {@link + * OH_AbilityRuntime_ConnectOptions} instance. + * @param element Represents the element name of the modular object extension ability. + * + * @since 26.0.0 + */ +typedef void (*OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback)( + OH_AbilityRuntime_ConnectOptions *connectOptions, AbilityBase_Element *element); + +/** + * @brief The callback interface is invoked when the connection fails. + * + * @param connectOptions Represents a pointer to an {@link + * OH_AbilityRuntime_ConnectOptions} instance. + * @param code Represents the error code of the failure. + * + * @since 26.0.0 + */ +typedef void (*OH_AbilityRuntime_ConnectOptions_OnFailedCallback)( + OH_AbilityRuntime_ConnectOptions *connectOptions, AbilityRuntime_ErrorCode code); + +/** + * @brief Creates a ConnectOptions object. + * + * + * @return Returns a newly created OH_AbilityRuntime_ConnectOptions object. + * The caller is responsible for destroying the returned object by calling + * {@link OH_AbilityRuntime_DestroyConnectOptions} to avoid memory leaks. + * @since 26.0.0 + */ +OH_AbilityRuntime_ConnectOptions* OH_AbilityRuntime_CreateConnectOptions(); + +/** + * @brief Destroys the specified ConnectOptions. + * + * @param connectOptions The ConnectOptions object to be destroyed. + * @return The error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} if the operation is successful. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} if the connectOptions is invalid. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_DestroyConnectOptions(OH_AbilityRuntime_ConnectOptions *connectOptions); + +/** + * @brief Set the callback {@link OH_AbilityRuntime_ConnectOptions_OnConnectCallback} in + * {@link OH_AbilityRuntime_ConnectOptions}. + * + * @param connectOptions Pointer to an {@link OH_AbilityRuntime_ConnectOptions} instance to be set. + * @param onConnectCallback Represents {@link OH_AbilityRuntime_ConnectOptions_OnConnectCallback} instance + * which will be set in. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectOptions_SetOnConnectCallback( + OH_AbilityRuntime_ConnectOptions *connectOptions, + OH_AbilityRuntime_ConnectOptions_OnConnectCallback onConnectCallback); + +/** + * @brief Set the callback {@link OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback} in + * {@link OH_AbilityRuntime_ConnectOptions}. + * + * @param connectOptions Pointer to an {@link OH_AbilityRuntime_ConnectOptions} instance to be set. + * @param onDisconnectCallback Represents {@link OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback} instance + * which will be set in. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectOptions_SetOnDisconnectCallback( + OH_AbilityRuntime_ConnectOptions *connectOptions, + OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback onDisconnectCallback); + +/** + * @brief Set the callback {@link OH_AbilityRuntime_ConnectOptions_OnFailedCallback} in + * {@link OH_AbilityRuntime_ConnectOptions}. + * + * @param connectOptions Pointer to an {@link OH_AbilityRuntime_ConnectOptions} instance to be set. + * @param onFailedCallback Represents {@link OH_AbilityRuntime_ConnectOptions_OnFailedCallback} instance + * which will be set in. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectOptions_SetOnFailedCallback( + OH_AbilityRuntime_ConnectOptions *connectOptions, + OH_AbilityRuntime_ConnectOptions_OnFailedCallback onFailedCallback); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif // ABILITY_RUNTIME_CONNECT_OPTIONS_H \ No newline at end of file diff --git a/interfaces/kits/c/ability_runtime/modular_object_extension_ability.h b/interfaces/kits/c/ability_runtime/modular_object_extension_ability.h new file mode 100644 index 0000000000..1cd20292a7 --- /dev/null +++ b/interfaces/kits/c/ability_runtime/modular_object_extension_ability.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2026 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. + */ + +/** + * @addtogroup AbilityRuntime + * @{ + * + * @brief Provides the definition of the C interface for the modular object extension ability. + * + * @since 26.0.0 + */ + +/** + * @file modular_object_extension_ability.h + * + * @brief Declares the modular object extension ability. + * + * @library libmodular_object_extension.so + * @kit AbilityKit + * @syscap SystemCapability.Ability.AbilityRuntime.Core + * @since 26.0.0 + */ + +#ifndef ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_ABILITY_H +#define ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_ABILITY_H + +#include "ability_runtime_common.h" +#include "extension_ability.h" +#include "ipc_cparcel.h" +#include "modular_object_extension_context.h" +#include "want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Defines the struct for OH_AbilityRuntime_ModObjExtensionInstance. + * + * @since 26.0.0 + */ +typedef struct OH_AbilityRuntime_ModularObjectExtensionInstance OH_AbilityRuntime_ModObjExtensionInstance; + +/** + * @brief Defines the pointer to OH_AbilityRuntime_ModObjExtensionInstance. + * + * @since 26.0.0 + */ +typedef OH_AbilityRuntime_ModObjExtensionInstance* OH_AbilityRuntime_ModObjExtensionInstanceHandle; + +/** + * @brief Callback invoked when a modular object extension is started for initialization. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * @param want Indicates the want of created modular object extension. + * For details, see {@link AbilityBase_Want}. + * + * @since 26.0.0 + */ +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, AbilityBase_Want *want); + +/** + * @brief Callback invoked before a modular object extension is destroyed. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * + * @since 26.0.0 + */ +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance); + +/** + * @brief Callback invoked when a modular object extension is connected to an ability. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * @param want Indicates the want of created modular object extension. + * + * @since 26.0.0 + */ +typedef OHIPCRemoteStub* (*OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, AbilityBase_Want *want); + +/** + * @brief Callback invoked when all abilities connected to a modular object extension are + * disconnected. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * + * @since 26.0.0 + */ +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance); + +/** + * @brief Registers the function {@link OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc} with + * {@link OH_AbilityRuntime_ModObjExtensionInstance}. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * @param onCreateFunc Represents the onCreate callback function. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - device not supported. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc); + +/** + * @brief Registers the function {@link OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc} with + * {@link OH_AbilityRuntime_ModObjExtensionInstance}. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * @param onDestroyFunc Represents the onDestroy callback function. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - device not supported. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDestroyFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc); + +/** + * @brief Registers the function {@link OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc} with + * {@link OH_AbilityRuntime_ModObjExtensionInstance}. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * @param onConnectFunc Represents the onConnect callback function. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - device not supported. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnConnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc); + +/** + * @brief Registers the function {@link OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc} with + * {@link OH_AbilityRuntime_ModObjExtensionInstance}. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * @param onDisconnectFunc Represents the onDisconnect callback function. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - device not supported. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDisconnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc); + + +/** + * @brief Gets the extension context from the modular object extension instance. + * + * @param instance Points to an {@link OH_AbilityRuntime_ModObjExtensionInstance} instance. + * @param context Represents a pointer to the modular object extension ability context. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - device not supported. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, OH_AbilityRuntime_ModObjExtensionContextHandle* context); + +/** + * @brief Gets the modular object extension instance from a base extension instance. + * + * @param baseExtensionInstance Represents a pointer to a {@link + * AbilityRuntime_ExtensionInstance} base extension instance. + * @param modObjExtensionInstance Represents a pointer to an {@link + * OH_AbilityRuntime_ModObjExtensionInstanceHandle} instance that is an output parameter. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - device not supported. + * {@link ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE} - if the ability instance is not + * a modular object extension. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase( + AbilityRuntime_ExtensionInstanceHandle baseExtensionInstance, + OH_AbilityRuntime_ModObjExtensionInstanceHandle* modObjExtensionInstance); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif // ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_ABILITY_H \ No newline at end of file diff --git a/interfaces/kits/c/ability_runtime/modular_object_extension_context.h b/interfaces/kits/c/ability_runtime/modular_object_extension_context.h new file mode 100644 index 0000000000..bd4f2ae372 --- /dev/null +++ b/interfaces/kits/c/ability_runtime/modular_object_extension_context.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2026 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. + */ + + /** + * @addtogroup AbilityRuntime + * @{ + * + * @brief Provides the definition of the C interface for the modular object extension context. + * + * @since 26.0.0 + */ + +/** + * @file modular_object_extension_context.h + * + * @brief Declares the modular object extension context. + * + * @library libmodular_object_extension.so + * @kit AbilityKit + * @syscap SystemCapability.Ability.AbilityRuntime.Core + * @since 26.0.0 + */ + +#ifndef ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_CONTEXT_H +#define ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_CONTEXT_H + +#include "ability_runtime_common.h" +#include "context.h" +#include "ipc_cremote_object.h" +#include "start_options.h" +#include "want.h" + +#ifdef __cplusplus +extern "C" { +#endif +struct AbilityBase_Want; +typedef struct AbilityBase_Want AbilityBase_Want; + +/** + * @brief Defines a pointer type to OH_AbilityRuntime_ModObjExtensionContextHandle. + * + * @since 26.0.0 + */ +typedef struct OH_AbilityRuntime_ModularObjectExtensionContext* OH_AbilityRuntime_ModObjExtensionContextHandle; + +/** + * @brief Gets the base context from the modular object extension context. + * + * @param modObjExtensionContext Represents a pointer to a modular object extension ability context. + * @param baseContext Represents a pointer to a {@link AbilityRuntime_ContextHandle} base extension ability context. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - success. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - parameter check failed. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - device not supported. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_GetBaseContext( + OH_AbilityRuntime_ModObjExtensionContextHandle modObjExtensionContext, AbilityRuntime_ContextHandle* baseContext); + +/** + * @brief Starts the self UIAbility. + * + * @permission ohos.permission.NDK_START_SELF_UI_ABILITY + * @param context Represents a pointer to a modular object extension ability context. + * @param want The arguments passed to start the self UIAbility. + * For details, see {@link AbilityBase_Want}. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - if the call is successful. + * {@link ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED} - if the caller has no correct permission. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - if the arguments provided is invalid. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - if the device does not support starting self UIAbility. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_SUCH_ABILITY} - if the target ability does not exist. + * {@link ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE} - if the ability type is incorrect. + * {@link ABILITY_RUNTIME_ERROR_CODE_CROWDTEST_EXPIRED} - if the crowdtesting application expires. + * {@link ABILITY_RUNTIME_ERROR_CODE_WUKONG_MODE} - if the ability cannot be started in Wukong mode. + * {@link ABILITY_RUNTIME_ERROR_CODE_CONTROLLED} - if the app is controlled. + * {@link ABILITY_RUNTIME_ERROR_CODE_EDM_CONTROLLED} - if the app is controlled by EDM. + * {@link ABILITY_RUNTIME_ERROR_CODE_CROSS_APP} - if the caller tries to start a different application. + * {@link ABILITY_RUNTIME_ERROR_CODE_INTERNAL} - if an internal error occurs. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_TOP_ABILITY} - if the caller is not top ability. + * {@link ABILITY_RUNTIME_ERROR_CODE_MULTI_APP_NOT_SUPPORTED} - if the app clone or multi-instance is + not supported. + * {@link ABILITY_RUNTIME_ERROR_CODE_INVALID_APP_INSTANCE_KEY} - if the app instance key is invalid. + * {@link ABILITY_RUNTIME_ERROR_CODE_UPPER_LIMIT_REACHED} - if the number of app instances has reached + the limit. + * {@link ABILITY_RUNTIME_ERROR_MULTI_INSTANCE_NOT_SUPPORTED} - if multi-instance is not supported. + * {@link ABILITY_RUNTIME_ERROR_CODE_APP_INSTANCE_KEY_NOT_SUPPORTED} - if the APP_INSTANCE_KEY cannot + be specified. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility( + OH_AbilityRuntime_ModObjExtensionContextHandle context, const AbilityBase_Want *want); + +/** + * @brief Starts the self UIAbility with start options. + * + * @permission ohos.permission.NDK_START_SELF_UI_ABILITY + * @param context Represents a pointer to a modular object extension ability context. + * @param want The arguments passed to start the self UIAbility. + * For details, see {@link AbilityBase_Want}. + * @param options The start options passed to start the self UIAbility. + * For details, see {@link AbilityRuntime_StartOptions}. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - if the call is successful. + * {@link ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED} - if the caller has no correct permission. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - if the arguments provided are invalid. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - if the device does not support starting self UIAbility. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_SUCH_ABILITY} - if the target ability does not exist. + * {@link ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE} - if the ability type is incorrect. + * {@link ABILITY_RUNTIME_ERROR_CODE_CROWDTEST_EXPIRED} - if the crowdtesting application expires. + * {@link ABILITY_RUNTIME_ERROR_CODE_WUKONG_MODE} - if the ability cannot be started in Wukong mode. + * {@link ABILITY_RUNTIME_ERROR_CODE_CONTROLLED} - if the app is controlled. + * {@link ABILITY_RUNTIME_ERROR_CODE_EDM_CONTROLLED} - if the app is controlled by EDM. + * {@link ABILITY_RUNTIME_ERROR_CODE_CROSS_APP} - if the caller tries to start a different application. + * {@link ABILITY_RUNTIME_ERROR_CODE_INTERNAL} - if an internal error occurs. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_TOP_ABILITY} - if the caller is not a foreground process. + * {@link ABILITY_RUNTIME_ERROR_VISIBILITY_SETTING_DISABLED} - if setting visibility is disabled. + * {@link ABILITY_RUNTIME_ERROR_CODE_MULTI_APP_NOT_SUPPORTED} - if the app clone or multi-instance is + not supported. + * {@link ABILITY_RUNTIME_ERROR_CODE_INVALID_APP_INSTANCE_KEY} - if the app instance key is invalid. + * {@link ABILITY_RUNTIME_ERROR_CODE_UPPER_LIMIT_REACHED} - if the number of app instances has reached + the limit. + * {@link ABILITY_RUNTIME_ERROR_MULTI_INSTANCE_NOT_SUPPORTED} - if multi-instance is not supported. + * {@link ABILITY_RUNTIME_ERROR_CODE_APP_INSTANCE_KEY_NOT_SUPPORTED} - if the APP_INSTANCE_KEY cannot + be specified. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions( + OH_AbilityRuntime_ModObjExtensionContextHandle context, const AbilityBase_Want *want, + const AbilityRuntime_StartOptions *options); + +/** + * @brief Destroys the modular object extension. + * + * @param context Represents a pointer to a modular object extension ability context. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - if the call is successful. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - if the arguments provided are invalid. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - if the device does not support starting self UIAbility. + * {@link ABILITY_RUNTIME_ERROR_CODE_WUKONG_MODE} - if the ability cannot be started in Wukong mode. + * {@link ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST} - if the context does not exist. + * {@link ABILITY_RUNTIME_ERROR_CODE_INTERNAL} - if an internal error occurs. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf( + OH_AbilityRuntime_ModObjExtensionContextHandle context); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif // ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_CONTEXT_H \ No newline at end of file diff --git a/interfaces/kits/c/ability_runtime/modular_object_extension_manager.h b/interfaces/kits/c/ability_runtime/modular_object_extension_manager.h index 66872c49c8..7aae68cafa 100644 --- a/interfaces/kits/c/ability_runtime/modular_object_extension_manager.h +++ b/interfaces/kits/c/ability_runtime/modular_object_extension_manager.h @@ -27,7 +27,7 @@ * * @brief Declares the modular object extension manager. * - * @library libmodular_object_extension.so + * @library libability_runtime.so * @kit AbilityKit * @syscap SystemCapability.Ability.AbilityRuntime.Core * @since 26.0.0 @@ -37,7 +37,10 @@ #define ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_MANAGER_H #include + #include "ability_runtime_common.h" +#include "connect_options.h" +#include "context.h" #include "want_manager.h" #ifdef __cplusplus @@ -180,7 +183,7 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoElementN * @brief Gets the disable state of modular object extension. * * @param extensionInfo The modular object extension info. - * @param isDisabled Whether the extension is disabled by the application itself. + * @param isDisabled Whether the extension is disabled. * @return Returns a specific error code. * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} if the operation is successful. * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} if the arguments provided are invalid. @@ -191,7 +194,6 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModularObjectExtensionInfoDisableS /** * @brief Acquires all modular object extension infos within the self application. - * * @param outOwnedAllExtensionInfos Information about all extensions within the self application. * @return Returns a specific error code. @@ -245,6 +247,53 @@ AbilityRuntime_ErrorCode OH_AbilityRuntime_GetModObjExtensionInfoByIndex( OH_AbilityRuntime_AllModObjExtensionInfosHandle allExtensionInfos, size_t index, OH_AbilityRuntime_ModObjExtensionInfoHandle *extensionInfo); +/** + * @brief Connect to a modular object extension ability + * + * @param want Indicates the service extension to connect. + * For details, see {@link AbilityBase_Want}. + * @param connectOptions Indicates the connection options. + * @param connectionId Indicates the connection id that is a output param. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - if the call is successful. + * {@link ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED} - if the caller has no correct permission. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - if the arguments provided are invalid. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - if the device does not support connecting modular + * object extension ability. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_SUCH_ABILITY} - if the target ability does not exist. + * {@link ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE} - if the ability type is incorrect. + * {@link ABILITY_RUNTIME_ERROR_CODE_VISIBILITY_VERIFICATION_FAILED} - Cannot start an invisible component. + * {@link ABILITY_RUNTIME_ERROR_CODE_STATIC_CFG_PERMISSION} - The specified process does not have + the permission. + * {@link ABILITY_RUNTIME_ERROR_CODE_CROSS_USER_OPERATION} - Cross-user operations are not allowed. + * {@link ABILITY_RUNTIME_ERROR_CODE_CROWDTEST_EXPIRED} - if the crowdtesting application expires. + * {@link ABILITY_RUNTIME_ERROR_CODE_INTERNAL} - if an internal error occurs. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_TOP_ABILITY} - if the caller is not a foreground process. + * {@lin ABILITY_RUNTIME_ERROR_CODE_UPPER_LIMIT_REACHED} - The number of ability instances is more than five. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_RUNNING_ABILITIES_WITH_UI} - if the target application does not have + * running abilities with UI. + * {@link ABILITY_RUNTIME_ERROR_CODE_UPPER_RATE_LIMIT} - The API call frequency is too high and + * exceeds 20 times per second. + * {@link ABILITY_RUNTIME_ERROR_CODE_UPPER_CONNECTION_NUMBER_LIMIT} - The number of connections exceeds five. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_ConnectModularObjectExtensionAbility(AbilityBase_Want *want, + OH_AbilityRuntime_ConnectOptions *connectOptions, int64_t *connectionId); + +/** + * @brief Disconnect the modular object extension ability + * + * @param connectionId Indicates the connection ID. + * @return Returns a specific error code. + * {@link ABILITY_RUNTIME_ERROR_CODE_NO_ERROR} - if the call is successful. + * {@link ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID} - if the arguments provided are invalid. + * {@link ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED} - if the device does not support disconnecting modular + * object extension ability. + * {@link ABILITY_RUNTIME_ERROR_CODE_INTERNAL} - if an internal error occurs. + * @since 26.0.0 + */ +AbilityRuntime_ErrorCode OH_AbilityRuntime_DisconnectModularObjectExtensionAbility(int64_t connectionId); + #ifdef __cplusplus } #endif diff --git a/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension.h b/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension.h new file mode 100644 index 0000000000..33e799c2bd --- /dev/null +++ b/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_EXTENSION_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_H + +#include "extension_base.h" +#include "modular_object_extension_context_impl.h" +#include "modular_object_extension_types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +struct AbilityBase_Want; +typedef struct AbilityBase_Want AbilityBase_Want; + +struct AbilityBase_Element; +typedef struct AbilityBase_Element AbilityBase_Element; + +#ifdef __cplusplus +} // extern "C" +#endif + +namespace OHOS { +namespace AbilityRuntime { +class ModularObjectExtension : public ExtensionBase { +public: + ModularObjectExtension() = default; + ~ModularObjectExtension() override = default; + + std::shared_ptr CreateAndInitContext( + const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, + const sptr &token) override; + + void Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, + const sptr &token) override; + + static ModularObjectExtension* Create(); + + void OnStart(const AAFwk::Want &want) override; + + void OnStop() override; + + sptr OnConnect(const AAFwk::Want &want) override; + + void OnDisconnect(const AAFwk::Want &want) override; + +private: + bool LoadNativeExtensionModule(); + bool BuildCWant(const AAFwk::Want &want, AbilityBase_Want &cWant, AbilityBase_Element &element) const; + static bool BuildElement(const AppExecFwk::ElementName &elementName, AbilityBase_Element &element); + static void DestroyElement(AbilityBase_Element &element); + + std::shared_ptr moeInstance_; + std::shared_ptr moeContext_; +}; +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_H diff --git a/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_context_impl.h b/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_context_impl.h new file mode 100644 index 0000000000..9b53861c0e --- /dev/null +++ b/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_context_impl.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H + +#include "extension_context.h" +#include "start_options.h" +#include "want.h" + +namespace OHOS { +namespace AbilityRuntime { +class ModularObjectExtensionContext : public ExtensionContext { +public: + ModularObjectExtensionContext() = default; + ~ModularObjectExtensionContext() override = default; + + ErrCode StartSelfUIAbility(const AAFwk::Want &want) const; + + ErrCode StartSelfUIAbilityWithStartOptions(const AAFwk::Want &want, const AAFwk::StartOptions &startOptions) const; + + ErrCode TerminateSelf(); + + static const size_t CONTEXT_TYPE_ID; + +protected: + bool IsContext(size_t contextTypeId) override + { + return contextTypeId == CONTEXT_TYPE_ID || ExtensionContext::IsContext(contextTypeId); + } +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H diff --git a/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_module_loader.h b/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_module_loader.h new file mode 100644 index 0000000000..f91ee9adf3 --- /dev/null +++ b/interfaces/kits/native/ability/native/modular_object_extension/modular_object_extension_module_loader.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_EXTENSION_MODULE_LOADER_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_MODULE_LOADER_H + +#include "extension_module_loader.h" + +namespace OHOS::AbilityRuntime { +class ModularObjectExtensionModuleLoader + : public ExtensionModuleLoader, public Singleton { + DECLARE_SINGLETON(ModularObjectExtensionModuleLoader); + +public: + Extension *Create(const std::unique_ptr& runtime) const override; + + std::map GetParams() override; +}; +} // namespace OHOS::AbilityRuntime + +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_EXTENSION_MODULE_LOADER_H diff --git a/services/abilitymgr/BUILD.gn b/services/abilitymgr/BUILD.gn index f9b67c28b8..bb4bc14776 100644 --- a/services/abilitymgr/BUILD.gn +++ b/services/abilitymgr/BUILD.gn @@ -583,18 +583,23 @@ ohos_shared_library("modular_object") { ] deps = [ "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/app_manager:app_manager", "${ability_runtime_innerkits_path}/deps_wrapper:ability_deps_wrapper", "${ability_runtime_native_path}/appkit:appkit_manager_helper", + "${ability_runtime_services_path}/common:app_util", ] external_deps = [ "ability_base:want", "c_utils:utils", "common_event_service:cesfwk_innerkits", + "eventhandler:libeventhandler", "ffrt:libffrt", "hilog:libhilog", "hitrace:hitrace_meter", + "hisysevent:libhisysevent", "ipc:ipc_core", + "safwk:system_ability_fwk", "samgr:samgr_proxy", ] diff --git a/services/abilitymgr/abilitymgr.gni b/services/abilitymgr/abilitymgr.gni index cc1e278a1a..d4ffc1484d 100644 --- a/services/abilitymgr/abilitymgr.gni +++ b/services/abilitymgr/abilitymgr.gni @@ -190,6 +190,9 @@ abilityms_files = [ "src/kiosk_status.cpp", "src/kiosk_manager.cpp", "src/utils/udmf_utils.cpp", + + #modular_object utils + "src/modular_object_utils.cpp", ] if (ability_runtime_graphics) { diff --git a/services/abilitymgr/include/ability_manager_service.h b/services/abilitymgr/include/ability_manager_service.h index 1d5c35eef5..f7552917fa 100644 --- a/services/abilitymgr/include/ability_manager_service.h +++ b/services/abilitymgr/include/ability_manager_service.h @@ -2608,7 +2608,11 @@ public: virtual int32_t PreloadApplication(const std::string &bundleName, int32_t userId, int32_t appIndex) override; int StartAbilityWithRemoveIntentFlag(const StartAbilityWrapParam ¶m); - + + std::shared_ptr GetUIAbilityManagerByUserId(int32_t userId) const; + + std::shared_ptr GetUIExtensionAbilityManagerByUserId(int32_t userId); + // MSG 0 - 20 represents timeout message static constexpr uint32_t LOAD_TIMEOUT_MSG = 0; static constexpr uint32_t ACTIVE_TIMEOUT_MSG = 1; @@ -2957,7 +2961,6 @@ private: std::unordered_map> GetUIExtensionAbilityManagers(); std::shared_ptr GetCurrentUIExtensionAbilityManager(); - std::shared_ptr GetUIExtensionAbilityManagerByUserId(int32_t userId); std::shared_ptr GetUIExtensionAbilityManagerByToken(const sptr &token); std::shared_ptr GetUIExtensionAbilityManagerByAbilityRecordId( const int64_t &abilityRecordId); @@ -2974,7 +2977,6 @@ private: std::shared_ptr GetCurrentMissionListManager(); std::unordered_map> GetUIAbilityManagers(); std::shared_ptr GetCurrentUIAbilityManager(); - std::shared_ptr GetUIAbilityManagerByUserId(int32_t userId) const; std::shared_ptr GetUIAbilityManagerByUid(int32_t uid); bool JudgeSelfCalled(const std::shared_ptr &abilityRecord); bool IsAppSelfCalled(const std::shared_ptr &abilityRecord); diff --git a/services/abilitymgr/include/extension_record/extension_record_manager.h b/services/abilitymgr/include/extension_record/extension_record_manager.h index 159e16e64c..77ae749689 100644 --- a/services/abilitymgr/include/extension_record/extension_record_manager.h +++ b/services/abilitymgr/include/extension_record/extension_record_manager.h @@ -87,6 +87,13 @@ public: */ int32_t GetActiveUIExtensionList(const std::string &bundleName, std::vector &extensionList); + /** + * @brief Get extensionList by uid. + * @param uid The application uid. + * @param extensionList UIExtensionAbility name list. + */ + int32_t GetActiveUIExtensionListByUid(int32_t uid, std::vector &extensionList); + int32_t StartAbility(const AAFwk::AbilityRequest &abilityRequest); int32_t CreateExtensionRecord(const AAFwk::AbilityRequest &abilityRequest, const std::string &hostBundleName, diff --git a/services/abilitymgr/include/modular_object/modular_object_manager.h b/services/abilitymgr/include/modular_object/modular_object_manager.h index 3eda62ae21..85860f457e 100644 --- a/services/abilitymgr/include/modular_object/modular_object_manager.h +++ b/services/abilitymgr/include/modular_object/modular_object_manager.h @@ -18,6 +18,7 @@ #include #include "modular_object_extension_info.h" +#include "want.h" namespace OHOS { namespace AbilityRuntime { @@ -30,4 +31,4 @@ public: } } -#endif // OHOS_MODULAR_OBJECT_MANAGER_H \ No newline at end of file +#endif // OHOS_MODULAR_OBJECT_MANAGER_H diff --git a/services/abilitymgr/include/modular_object_utils.h b/services/abilitymgr/include/modular_object_utils.h new file mode 100644 index 0000000000..bdbffa12da --- /dev/null +++ b/services/abilitymgr/include/modular_object_utils.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_UTILS_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_UTILS_H + +#include +#include + +#include "ability_record/ability_request.h" +#include "modular_object_extension_info.h" + +namespace OHOS { +namespace AAFwk { + +class ModularObjectUtils { +public: + ModularObjectUtils() = delete; + + static int32_t CheckPermission(const AbilityRequest &abilityRequest); + +private: + static int32_t CheckExtensionEnabled(const ModularObjectExtensionInfo &info, const AbilityRequest &abilityRequest); + static int32_t CheckCallerForeground(); + static int32_t CheckAppDistributionType(const std::string &callerAppDistributionType, + const std::string &targetAppDistributionType); + static bool HasRunningUIAbilityOrExtension(int32_t targetUid, int32_t userId); + static int32_t CheckTargetHasRunningAbility(int32_t targetUid, int32_t userId, + const std::string &targetBundleName); + static int32_t GetTargetExtensionInfoFromDb(const std::string &bundleName, const std::string &abilityName, + int32_t appIndex, int32_t validUserId, ModularObjectExtensionInfo &targetExtensionInfo); + static int32_t GetCallerAppInfo(AppExecFwk::ApplicationInfo &callerAppInfo); +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_UTILS_H diff --git a/services/abilitymgr/include/ui_extension/ui_extension_ability_manager.h b/services/abilitymgr/include/ui_extension/ui_extension_ability_manager.h index 0369e0068b..1847c6f199 100644 --- a/services/abilitymgr/include/ui_extension/ui_extension_ability_manager.h +++ b/services/abilitymgr/include/ui_extension/ui_extension_ability_manager.h @@ -116,6 +116,13 @@ public: */ int32_t GetActiveUIExtensionList(const std::string &bundleName, std::vector &extensionList); + /** + * @brief Get extensionList by uid. + * @param uid The application uid. + * @param extensionList UIExtensionAbility name list. + */ + int32_t GetActiveUIExtensionListByUid(int32_t uid, std::vector &extensionList); + void BackgroundAbilityWindowLocked(const std::shared_ptr &abilityRecord, const sptr &sessionInfo); diff --git a/services/abilitymgr/src/ability_manager_service.cpp b/services/abilitymgr/src/ability_manager_service.cpp index 0e2ea1b548..17d261f076 100644 --- a/services/abilitymgr/src/ability_manager_service.cpp +++ b/services/abilitymgr/src/ability_manager_service.cpp @@ -81,6 +81,8 @@ #include "mock_session_manager_service.h" #include "modal_system_dialog/modal_system_dialog_ui_extension.h" #include "modal_system_ui_extension.h" +#include "modular_object_manager.h" +#include "modular_object_utils.h" #include "multi_app_utils.h" #include "os_account_manager_wrapper.h" #include "permission_constants.h" @@ -12296,6 +12298,9 @@ int AbilityManagerService::CheckCallOtherExtensionPermission(const AbilityReques if (extensionType == AppExecFwk::ExtensionAbilityType::CALLER_INFO_QUERY) { return CheckCallerInfoQueryExtensionPermission(abilityRequest); } + if (extensionType == AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT) { + return ModularObjectUtils::CheckPermission(abilityRequest); + } TAG_LOGE(AAFwkTag::ABILITYMGR, "not SA, can't start other extension"); return CHECK_PERMISSION_FAILED; } diff --git a/services/abilitymgr/src/extension_record/extension_record_manager.cpp b/services/abilitymgr/src/extension_record/extension_record_manager.cpp index c5702be530..8e1f36de2e 100644 --- a/services/abilitymgr/src/extension_record/extension_record_manager.cpp +++ b/services/abilitymgr/src/extension_record/extension_record_manager.cpp @@ -193,6 +193,23 @@ int32_t ExtensionRecordManager::GetActiveUIExtensionList( return ERR_OK; } +int32_t ExtensionRecordManager::GetActiveUIExtensionListByUid( + int32_t uid, std::vector &extensionList) +{ + TAG_LOGD(AAFwkTag::ABILITYMGR, "called"); + std::lock_guard lock(mutex_); + for (const auto &it : extensionRecords_) { + if (it.second == nullptr || it.second->abilityRecord_ == nullptr || + uid != it.second->abilityRecord_->GetUid()) { + continue; + } + + extensionList.push_back(it.second->abilityRecord_->GetAbilityInfo().moduleName + SEPARATOR + + it.second->abilityRecord_->GetAbilityInfo().name); + } + return ERR_OK; +} + int32_t ExtensionRecordManager::GetOrCreateExtensionRecord(const AAFwk::AbilityRequest &abilityRequest, const std::string &hostBundleName, std::shared_ptr &abilityRecord, bool &isLoaded) { diff --git a/services/abilitymgr/src/modular_object/modular_object_manager.cpp b/services/abilitymgr/src/modular_object/modular_object_manager.cpp index 1f71b9c72a..fb5bd04009 100644 --- a/services/abilitymgr/src/modular_object/modular_object_manager.cpp +++ b/services/abilitymgr/src/modular_object/modular_object_manager.cpp @@ -14,9 +14,11 @@ */ #include "modular_object_manager.h" -#include "ability_manager_errors.h" + +#include "hilog_tag_wrapper.h" #include "modular_object_rdb_storage_mgr.h" -#include "os_account_manager_wrapper.h" + +using namespace OHOS::AAFwk; namespace OHOS { namespace AbilityRuntime { @@ -30,4 +32,4 @@ int32_t ModularObjectManager::QuerySelfModularObjectExtensionInfos(int32_t userI return DelayedSingleton::GetInstance()->QueryData(key, infos); } } -} \ No newline at end of file +} diff --git a/services/abilitymgr/src/modular_object_utils.cpp b/services/abilitymgr/src/modular_object_utils.cpp new file mode 100644 index 0000000000..ff6dc22fad --- /dev/null +++ b/services/abilitymgr/src/modular_object_utils.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2026 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 "modular_object_utils.h" + +#include + +#include "ability_manager_errors.h" +#include "ability_manager_service.h" +#include "ability_util.h" +#include "app_mgr_client.h" +#include "app_utils.h" +#include "bundle_mgr_helper.h" +#include "hilog_tag_wrapper.h" +#include "ipc_skeleton.h" +#include "modular_object_rdb_storage_mgr.h" +#include "os_account_manager_wrapper.h" +#include "parameters.h" +#include "running_process_info.h" +#include "scene_board_judgement.h" + +using namespace OHOS::AppExecFwk; + +namespace OHOS { +namespace AAFwk { +int32_t ModularObjectUtils::CheckPermission(const AbilityRequest &abilityRequest) +{ + if (!AppUtils::GetInstance().IsSupportModularObjectExtension()) { + TAG_LOGE(AAFwkTag::EXT, "device not supported"); + return ERR_CAPABILITY_NOT_SUPPORT; + } + int32_t validUserId = abilityRequest.userId; + auto element = abilityRequest.want.GetElement(); + std::string bundleName = element.GetBundleName(); + std::string abilityName = element.GetAbilityName(); + int32_t appIndex = abilityRequest.want.GetIntParam(Want::PARAM_APP_CLONE_INDEX_KEY, 0); + + ModularObjectExtensionInfo targetExtensionInfo; + auto ret = GetTargetExtensionInfoFromDb(bundleName, abilityName, appIndex, validUserId, targetExtensionInfo); + if (ret != ERR_OK) { + return ret; + } + ret = CheckExtensionEnabled(targetExtensionInfo, abilityRequest); + if (ret != ERR_OK) { + return ret; + } + ret = CheckCallerForeground(); + if (ret != ERR_OK) { + return ret; + } + AppExecFwk::ApplicationInfo callerAppInfo; + ret = GetCallerAppInfo(callerAppInfo); + if (ret != ERR_OK) { + return ret; + } + const auto &targetAppInfo = abilityRequest.appInfo; + ret = CheckAppDistributionType(callerAppInfo.appDistributionType, targetAppInfo.appDistributionType); + if (ret != ERR_OK) { + return ret; + } + return CheckTargetHasRunningAbility(targetAppInfo.uid, validUserId, bundleName); +} + +int32_t ModularObjectUtils::CheckExtensionEnabled(const ModularObjectExtensionInfo &info, + const AbilityRequest &abilityRequest) +{ + if (info.isDisabled && IPCSkeleton::GetCallingUid() != abilityRequest.uid) { + TAG_LOGE(AAFwkTag::EXT, "Extension is disabled: %{public}s/%{public}s. targetUid:%{public}d", + info.bundleName.c_str(), info.abilityName.c_str(), abilityRequest.uid); + return ERR_MODULAR_OBJECT_DISABLED; + } + return ERR_OK; +} + +int32_t ModularObjectUtils::CheckCallerForeground() +{ + pid_t callingPid = IPCSkeleton::GetCallingPid(); + AppExecFwk::RunningProcessInfo processInfo; + auto ret = IN_PROCESS_CALL( + DelayedSingleton::GetInstance()->GetRunningProcessInfoByPid( + callingPid, processInfo)); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::EXT, "GetRunningProcessInfoByPid fail:%{public}d", ret); + return ret; + } + if (processInfo.state_ != AppExecFwk::AppProcessState::APP_STATE_FOREGROUND) { + TAG_LOGE(AAFwkTag::EXT, "Caller not foreground, callingPid: %{public}d, state: %{public}d", + callingPid, static_cast(processInfo.state_)); + return NOT_TOP_ABILITY; + } + if (processInfo.isPreForeground) { + TAG_LOGE(AAFwkTag::EXT, "Caller is preForeground"); + return NOT_TOP_ABILITY; + } + return ERR_OK; +} + +int32_t ModularObjectUtils::CheckAppDistributionType(const std::string &callerAppDistributionType, + const std::string &targetAppDistributionType) +{ + bool isDeveloperMode = system::GetBoolParameter("const.security.developermode.state", false); + if (isDeveloperMode) { + TAG_LOGD(AAFwkTag::EXT, "Developer mode, allow"); + return ERR_OK; + } + + if (callerAppDistributionType == "none") { + TAG_LOGE(AAFwkTag::EXT, "Caller appDistributionType is none, not allowed"); + return ERR_PERMISSION_DENIED; + } + if (targetAppDistributionType == "none") { + TAG_LOGE(AAFwkTag::EXT, "Target appDistributionType is none, not allowed"); + return ERR_PERMISSION_DENIED; + } + return ERR_OK; +} + +bool ModularObjectUtils::HasRunningUIAbilityOrExtension(int32_t targetUid, int32_t userId) +{ + auto service = DelayedSingleton::GetInstance(); + if (service == nullptr) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "service is null"); + return false; + } + std::vector abilityList; + if (Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) { + auto uiAbilityManager = service->GetUIAbilityManagerByUserId(userId); + if (uiAbilityManager) { + uiAbilityManager->GetActiveAbilityList(targetUid, abilityList); + } + } else { + auto missionListManager = service->GetMissionListManagerByUserId(userId); + if (missionListManager) { + missionListManager->GetActiveAbilityList(targetUid, abilityList); + } + } + if (!abilityList.empty()) { + TAG_LOGD(AAFwkTag::ABILITYMGR, "Found running UIAbility for uid: %{public}d", targetUid); + return true; + } + + auto uiExtManager = service->GetUIExtensionAbilityManagerByUserId(userId); + if (uiExtManager) { + std::vector extensionList; + uiExtManager->GetActiveUIExtensionListByUid(targetUid, extensionList); + if (!extensionList.empty()) { + TAG_LOGD(AAFwkTag::ABILITYMGR, "Found running UIExtension for uid: %{public}d", targetUid); + return true; + } + } + + TAG_LOGI(AAFwkTag::ABILITYMGR, "No UIAbility or UIExt for uid: %{public}d", targetUid); + return false; +} + +int32_t ModularObjectUtils::CheckTargetHasRunningAbility( + int32_t targetUid, int32_t userId, const std::string &targetBundleName) +{ + if (!HasRunningUIAbilityOrExtension(targetUid, userId)) { + TAG_LOGE(AAFwkTag::EXT, + "Target has no running UIAbility or UIExtension, uid: %{public}d, bundle: %{public}s", + targetUid, targetBundleName.c_str()); + return ERR_NO_RUNNING_ABILITIES_WITH_UI; + } + return ERR_OK; +} + +int32_t ModularObjectUtils::GetTargetExtensionInfoFromDb(const std::string &bundleName, + const std::string &abilityName, int32_t appIndex, int32_t validUserId, + ModularObjectExtensionInfo &targetExtensionInfo) +{ + std::string key = std::to_string(validUserId) + "_" + bundleName + "_" + std::to_string(appIndex); + std::vector infos; + auto ret = DelayedSingleton::GetInstance()->QueryData(key, infos); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::EXT, "QueryData failed, ret: %{public}d", ret); + return ret; + } + bool found = false; + for (const auto &info : infos) { + if (info.bundleName == bundleName && info.abilityName == abilityName) { + targetExtensionInfo = info; + found = true; + break; + } + } + if (!found) { + TAG_LOGE(AAFwkTag::EXT, "Extension not found: %{public}s/%{public}s", bundleName.c_str(), abilityName.c_str()); + return INNER_ERR; + } + return ERR_OK; +} + +int32_t ModularObjectUtils::GetCallerAppInfo(AppExecFwk::ApplicationInfo &callerAppInfo) +{ + int32_t callingUid = IPCSkeleton::GetCallingUid(); + auto bundleMgrHelper = DelayedSingleton::GetInstance(); + CHECK_POINTER_AND_RETURN(bundleMgrHelper, INNER_ERR); + std::string callerBundleName; + int32_t callerAppIndex = 0; + auto ret = IN_PROCESS_CALL(bundleMgrHelper->GetNameAndIndexForUid(callingUid, callerBundleName, callerAppIndex)); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::EXT, "Get caller info failed, callingUid: %{public}d, ret: %{public}d", callingUid, ret); + return INNER_ERR; + } + int32_t callerUserId = -1; + auto osAccountRet = DelayedSingleton::GetInstance() + ->GetOsAccountLocalIdFromUid(callingUid, callerUserId); + if (osAccountRet != 0) { + TAG_LOGE(AAFwkTag::EXT, "Get caller userId failed, callingUid: %{public}d", callingUid); + return INNER_ERR; + } + if (!IN_PROCESS_CALL(bundleMgrHelper->GetApplicationInfoWithAppIndex( + callerBundleName, callerAppIndex, callerUserId, callerAppInfo))) { + TAG_LOGE(AAFwkTag::EXT, "Get caller appInfo failed, bundle: %{public}s", callerBundleName.c_str()); + return INNER_ERR; + } + return ERR_OK; +} +} // namespace AAFwk +} // namespace OHOS diff --git a/services/abilitymgr/src/ui_extension/ui_extension_ability_manager.cpp b/services/abilitymgr/src/ui_extension/ui_extension_ability_manager.cpp index 7cbb658116..512d8ded00 100644 --- a/services/abilitymgr/src/ui_extension/ui_extension_ability_manager.cpp +++ b/services/abilitymgr/src/ui_extension/ui_extension_ability_manager.cpp @@ -316,6 +316,13 @@ int32_t UIExtensionAbilityManager::GetActiveUIExtensionList( return uiExtensionAbilityRecordMgr_->GetActiveUIExtensionList(bundleName, extensionList); } +int32_t UIExtensionAbilityManager::GetActiveUIExtensionListByUid( + int32_t uid, std::vector &extensionList) +{ + CHECK_POINTER_AND_RETURN(uiExtensionAbilityRecordMgr_, ERR_NULL_OBJECT); + return uiExtensionAbilityRecordMgr_->GetActiveUIExtensionListByUid(uid, extensionList); +} + bool UIExtensionAbilityManager::IsUIExtensionFocused(uint32_t uiExtensionTokenId, const sptr& focusToken) { TAG_LOGD(AAFwkTag::ABILITYMGR, "called"); diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index a78db4e9c6..614e8824e6 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -342,6 +342,17 @@ group("unittest") { "connection_state_manager_test:unittest", "continuation_test:unittest", "control_interceptor_test:unittest", + "connect_options_test:unittest", + "c_modular_object_utils_test:unittest", + "modular_object_connection_manager_test:unittest", + "modular_object_extension_ability_test:unittest", + "modular_object_utils_test:unittest", + "modular_object_extension_manager_connect_test:unittest", + "c_modular_object_connection_callback_test:unittest", + "modular_object_ability_connection_test:unittest", + "modular_object_extension_context_capi_test:unittest", + "modular_object_extension_test:unittest", + "modular_object_extension_context_impl_test:unittest", "data_ability_manager_test:unittest", "data_ability_observer_proxy_test:unittest", "data_ability_observer_stub_test:unittest", diff --git a/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn b/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn index 6c53d0f4a6..d6c2c61861 100644 --- a/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn +++ b/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn @@ -158,6 +158,7 @@ ohos_unittest("ability_manager_service_fourteenth_test") { "${ability_runtime_services_path}/abilitymgr/src/mission/mission_listener_controller.cpp", "${ability_runtime_services_path}/abilitymgr/src/mission/mission_listener_proxy.cpp", "${ability_runtime_services_path}/abilitymgr/src/modal_system_dialog/modal_system_dialog_ui_extension.cpp", + "${ability_runtime_services_path}/abilitymgr/src/modular_object_utils.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_common_event.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_key.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_manager.cpp", diff --git a/test/unittest/ability_manager_service_second_test/BUILD.gn b/test/unittest/ability_manager_service_second_test/BUILD.gn index 2d4d3e3cd8..1d3b4a65bd 100644 --- a/test/unittest/ability_manager_service_second_test/BUILD.gn +++ b/test/unittest/ability_manager_service_second_test/BUILD.gn @@ -163,6 +163,7 @@ ohos_unittest("ability_manager_service_second_test") { "${ability_runtime_services_path}/abilitymgr/src/mission/mission_listener_controller.cpp", "${ability_runtime_services_path}/abilitymgr/src/mission/mission_listener_proxy.cpp", "${ability_runtime_services_path}/abilitymgr/src/modal_system_dialog/modal_system_dialog_ui_extension.cpp", + "${ability_runtime_services_path}/abilitymgr/src/modular_object_utils.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_common_event.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_key.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_manager.cpp", diff --git a/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn b/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn index 21962b6a4a..f2ba7edc97 100644 --- a/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn +++ b/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn @@ -159,6 +159,7 @@ ohos_unittest("ability_manager_service_thirteenth_test") { "${ability_runtime_services_path}/abilitymgr/src/mission/mission_listener_controller.cpp", "${ability_runtime_services_path}/abilitymgr/src/mission/mission_listener_proxy.cpp", "${ability_runtime_services_path}/abilitymgr/src/modal_system_dialog/modal_system_dialog_ui_extension.cpp", + "${ability_runtime_services_path}/abilitymgr/src/modular_object_utils.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_common_event.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_key.cpp", "${ability_runtime_services_path}/abilitymgr/src/pending_want_manager.cpp", diff --git a/test/unittest/c_modular_object_connection_callback_test/BUILD.gn b/test/unittest/c_modular_object_connection_callback_test/BUILD.gn new file mode 100644 index 0000000000..5750fb02fd --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/BUILD.gn @@ -0,0 +1,52 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("c_modular_object_connection_callback_test") { + module_out_path = "ability_runtime/ability_runtime/c_modular_object_connection_callback_test" + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + + sources = [ + "c_modular_object_connection_callback_test.cpp", + "${ability_runtime_path}/frameworks/c/ability_runtime/src/c_modular_object_connection_callback.cpp", + ] + + include_dirs = [ + "mock/include", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_services_path}/common/include", + ] + + deps = [] + + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":c_modular_object_connection_callback_test" ] +} diff --git a/test/unittest/c_modular_object_connection_callback_test/c_modular_object_connection_callback_test.cpp b/test/unittest/c_modular_object_connection_callback_test/c_modular_object_connection_callback_test.cpp new file mode 100644 index 0000000000..8e71b580ca --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/c_modular_object_connection_callback_test.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2026 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 "c_modular_object_connection_callback.h" +#include "c_modular_object_utils.h" +#include "connect_options_impl.h" +#include "ipc_inner_object.h" + +using namespace testing::ext; + +namespace OHOS { +namespace AbilityRuntime { + +// Static mock state definitions +bool CModularObjectUtils::buildElementResult = true; +bool CModularObjectUtils::notifyFailedCalled = false; +int32_t CModularObjectUtils::notifyFailedCode = 0; +int32_t CModularObjectUtils::convertConnectResult = 0; + +namespace { +int32_t g_connectCallbackCount = 0; +int32_t g_disconnectCallbackCount = 0; +int32_t g_failedCallbackCount = 0; + +void ResetCallbackState() +{ + g_connectCallbackCount = 0; + g_disconnectCallbackCount = 0; + g_failedCallbackCount = 0; + CModularObjectUtils::buildElementResult = true; + CModularObjectUtils::notifyFailedCalled = false; + CModularObjectUtils::notifyFailedCode = 0; + CModularObjectUtils::convertConnectResult = 0; +} + +void MockOnConnectCallback(OH_AbilityRuntime_ConnectOptions *owner, + AbilityBase_Element *element, void *proxy) +{ + (void)owner; + (void)proxy; + g_connectCallbackCount++; +} + +void MockOnDisconnectCallback(OH_AbilityRuntime_ConnectOptions *owner, + AbilityBase_Element *element) +{ + (void)owner; + (void)element; + g_disconnectCallbackCount++; +} + +class MockRemoteObject : public IRemoteObject { +public: + MockRemoteObject() : IRemoteObject(u"mock_descriptor") {} + ~MockRemoteObject() = default; + int32_t GetObjectRefCount() override { return 0; } + int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) override { return 0; } + bool IsProxyObject() const override { return true; } + bool CheckObjectLegality() const override { return true; } + bool AddDeathRecipient(const sptr &recipient) override { return true; } + bool RemoveDeathRecipient(const sptr &recipient) override { return true; } + bool Marshalling(Parcel &parcel) const override { return true; } + sptr AsInterface() override { return nullptr; } + int Dump(int fd, const std::vector &args) override { return 0; } +}; +} // namespace + +class CModularObjectConnectionCallbackTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override { ResetCallbackState(); } + void TearDown() override {} +}; + +// ==================== InsertConnection ==================== + +HWTEST_F(CModularObjectConnectionCallbackTest, InsertConnection_NullCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "InsertConnection_NullCallback_001 start"; + auto ret = CModularObjectConnectionUtils::InsertConnection(nullptr); + EXPECT_EQ(ret, -1); + GTEST_LOG_(INFO) << "InsertConnection_NullCallback_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, InsertConnection_ValidCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "InsertConnection_ValidCallback_001 start"; + auto state = std::make_shared(); + auto callback = sptr::MakeSptr(state); + ASSERT_NE(callback, nullptr); + auto ret = CModularObjectConnectionUtils::InsertConnection(callback); + EXPECT_GE(ret, 0); + EXPECT_EQ(callback->GetConnectionId(), ret); + // Clean up + CModularObjectConnectionUtils::RemoveConnectionCallback(ret); + GTEST_LOG_(INFO) << "InsertConnection_ValidCallback_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, InsertConnection_Multiple_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "InsertConnection_Multiple_001 start"; + auto state1 = std::make_shared(); + auto cb1 = sptr::MakeSptr(state1); + auto state2 = std::make_shared(); + auto cb2 = sptr::MakeSptr(state2); + auto id1 = CModularObjectConnectionUtils::InsertConnection(cb1); + auto id2 = CModularObjectConnectionUtils::InsertConnection(cb2); + EXPECT_GE(id1, 0); + EXPECT_GE(id2, 0); + EXPECT_NE(id1, id2); + // Clean up + CModularObjectConnectionUtils::RemoveConnectionCallback(id1); + CModularObjectConnectionUtils::RemoveConnectionCallback(id2); + GTEST_LOG_(INFO) << "InsertConnection_Multiple_001 end"; +} + +// ==================== FindConnection ==================== + +HWTEST_F(CModularObjectConnectionCallbackTest, FindConnection_NotFound_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FindConnection_NotFound_001 start"; + sptr callback; + CModularObjectConnectionUtils::FindConnection(-1, callback); + EXPECT_EQ(callback, nullptr); + GTEST_LOG_(INFO) << "FindConnection_NotFound_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, FindConnection_Found_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FindConnection_Found_001 start"; + auto state = std::make_shared(); + auto cb = sptr::MakeSptr(state); + auto id = CModularObjectConnectionUtils::InsertConnection(cb); + sptr found; + CModularObjectConnectionUtils::FindConnection(id, found); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->GetConnectionId(), id); + // Clean up + CModularObjectConnectionUtils::RemoveConnectionCallback(id); + GTEST_LOG_(INFO) << "FindConnection_Found_001 end"; +} + +// ==================== RemoveConnectionCallback ==================== + +HWTEST_F(CModularObjectConnectionCallbackTest, RemoveConnection_Valid_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RemoveConnection_Valid_001 start"; + auto state = std::make_shared(); + auto cb = sptr::MakeSptr(state); + auto id = CModularObjectConnectionUtils::InsertConnection(cb); + CModularObjectConnectionUtils::RemoveConnectionCallback(id); + // Verify removed + sptr found; + CModularObjectConnectionUtils::FindConnection(id, found); + EXPECT_EQ(found, nullptr); + GTEST_LOG_(INFO) << "RemoveConnection_Valid_001 end"; +} + +// ==================== OnAbilityConnectDone ==================== + +HWTEST_F(CModularObjectConnectionCallbackTest, OnConnectDone_NullRemote_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnectDone_NullRemote_001 start"; + auto state = std::make_shared(); + state->alive = true; + state->onConnectCallback = MockOnConnectCallback; + auto cb = sptr::MakeSptr(state); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityConnectDone(element, nullptr, 0); + EXPECT_EQ(g_connectCallbackCount, 0); + GTEST_LOG_(INFO) << "OnConnectDone_NullRemote_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnConnectDone_ExpiredState_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnectDone_ExpiredState_001 start"; + auto state = std::make_shared(); + state->alive = true; + state->onConnectCallback = MockOnConnectCallback; + auto cb = sptr::MakeSptr(state); + // Reset the shared_ptr so state_ becomes expired + state.reset(); + sptr remote = sptr(new MockRemoteObject()); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityConnectDone(element, remote, 0); + EXPECT_EQ(g_connectCallbackCount, 0); + GTEST_LOG_(INFO) << "OnConnectDone_ExpiredState_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnConnectDone_NotAlive_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnectDone_NotAlive_001 start"; + auto state = std::make_shared(); + state->alive = false; + state->onConnectCallback = MockOnConnectCallback; + auto cb = sptr::MakeSptr(state); + sptr remote = sptr(new MockRemoteObject()); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityConnectDone(element, remote, 0); + EXPECT_EQ(g_connectCallbackCount, 0); + GTEST_LOG_(INFO) << "OnConnectDone_NotAlive_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnConnectDone_NullCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnectDone_NullCallback_001 start"; + auto state = std::make_shared(); + state->alive = true; + state->onConnectCallback = nullptr; + auto cb = sptr::MakeSptr(state); + sptr remote = sptr(new MockRemoteObject()); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityConnectDone(element, remote, 0); + EXPECT_EQ(g_connectCallbackCount, 0); + GTEST_LOG_(INFO) << "OnConnectDone_NullCallback_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnConnectDone_BuildElementFails_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnectDone_BuildElementFails_001 start"; + auto state = std::make_shared(); + state->alive = true; + state->onConnectCallback = MockOnConnectCallback; + CModularObjectUtils::buildElementResult = false; + auto cb = sptr::MakeSptr(state); + sptr remote = sptr(new MockRemoteObject()); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityConnectDone(element, remote, 0); + EXPECT_EQ(g_connectCallbackCount, 0); + EXPECT_TRUE(CModularObjectUtils::notifyFailedCalled); + GTEST_LOG_(INFO) << "OnConnectDone_BuildElementFails_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnConnectDone_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnectDone_Success_001 start"; + OH_AbilityRuntime_ConnectOptions owner; + auto state = std::make_shared(); + state->alive = true; + state->owner = &owner; + state->onConnectCallback = MockOnConnectCallback; + auto cb = sptr::MakeSptr(state); + sptr remote = sptr(new MockRemoteObject()); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityConnectDone(element, remote, 0); + EXPECT_EQ(g_connectCallbackCount, 1); + GTEST_LOG_(INFO) << "OnConnectDone_Success_001 end"; +} + +// ==================== OnAbilityDisconnectDone ==================== + +HWTEST_F(CModularObjectConnectionCallbackTest, OnDisconnectDone_ExpiredState_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnDisconnectDone_ExpiredState_001 start"; + auto state = std::make_shared(); + state->alive = true; + state->onDisconnectCallback = MockOnDisconnectCallback; + auto cb = sptr::MakeSptr(state); + state.reset(); // expire the weak_ptr + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(g_disconnectCallbackCount, 0); + GTEST_LOG_(INFO) << "OnDisconnectDone_ExpiredState_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnDisconnectDone_NotAlive_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnDisconnectDone_NotAlive_001 start"; + auto state = std::make_shared(); + state->alive = false; + state->onDisconnectCallback = MockOnDisconnectCallback; + auto cb = sptr::MakeSptr(state); + sptr remote = sptr(new MockRemoteObject()); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(g_disconnectCallbackCount, 0); + GTEST_LOG_(INFO) << "OnDisconnectDone_NotAlive_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnDisconnectDone_NullCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnDisconnectDone_NullCallback_001 start"; + auto state = std::make_shared(); + state->alive = true; + state->onDisconnectCallback = nullptr; + auto cb = sptr::MakeSptr(state); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(g_disconnectCallbackCount, 0); + GTEST_LOG_(INFO) << "OnDisconnectDone_NullCallback_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnDisconnectDone_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnDisconnectDone_Success_001 start"; + OH_AbilityRuntime_ConnectOptions owner; + auto state = std::make_shared(); + state->alive = true; + state->owner = &owner; + state->onDisconnectCallback = MockOnDisconnectCallback; + auto cb = sptr::MakeSptr(state); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(g_disconnectCallbackCount, 1); + GTEST_LOG_(INFO) << "OnDisconnectDone_Success_001 end"; +} + +HWTEST_F(CModularObjectConnectionCallbackTest, OnDisconnectDone_BuildElementFails_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnDisconnectDone_BuildElementFails_001 start"; + auto state = std::make_shared(); + state->alive = true; + state->onDisconnectCallback = MockOnDisconnectCallback; + CModularObjectUtils::buildElementResult = false; + auto cb = sptr::MakeSptr(state); + AppExecFwk::ElementName element("", "com.test", "Ability"); + cb->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(g_disconnectCallbackCount, 0); + EXPECT_TRUE(CModularObjectUtils::notifyFailedCalled); + GTEST_LOG_(INFO) << "OnDisconnectDone_BuildElementFails_001 end"; +} + +// ==================== SetConnectionId / GetConnectionId ==================== + +HWTEST_F(CModularObjectConnectionCallbackTest, ConnectionId_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConnectionId_001 start"; + auto state = std::make_shared(); + auto cb = sptr::MakeSptr(state); + EXPECT_EQ(cb->GetConnectionId(), 0); + cb->SetConnectionId(42); + EXPECT_EQ(cb->GetConnectionId(), 42); + GTEST_LOG_(INFO) << "ConnectionId_001 end"; +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/ability_connect_callback.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/ability_connect_callback.h new file mode 100644 index 0000000000..6222b1c691 --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/ability_connect_callback.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_CONNECT_CALLBACK_H +#define MOCK_ABILITY_CONNECT_CALLBACK_H + +#include "element_name.h" +#include "iremote_broker.h" +#include "refbase.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AbilityRuntime { + +class AbilityConnectCallback : public RefBase { +public: + AbilityConnectCallback() = default; + virtual ~AbilityConnectCallback() = default; + + virtual void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) = 0; + virtual void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) = 0; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_ABILITY_CONNECT_CALLBACK_H diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_connection_callback.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_connection_callback.h new file mode 100644 index 0000000000..4d4ceded7f --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_connection_callback.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026 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_C_MODULAR_OBJECT_CONNECTION_CALLBACK_H +#define OHOS_ABILITY_RUNTIME_C_MODULAR_OBJECT_CONNECTION_CALLBACK_H + +#include +#include + +#include "ability_connect_callback.h" +#include "connect_options_impl.h" + +namespace OHOS { +namespace AbilityRuntime { + +struct ModularObjectConnectionKey { + int64_t id; +}; + +struct ModularObjectConnectionKeyCompare { + bool operator()(const ModularObjectConnectionKey &key1, const ModularObjectConnectionKey &key2) const + { + return key1.id < key2.id; + } +}; + +class CModularObjectConnectionCallback; + +namespace CModularObjectConnectionUtils { +int64_t InsertConnection(sptr callback); +void RemoveConnectionCallback(int64_t connectionId); +void FindConnection(int64_t connectionId, sptr &callback); +} // namespace CModularObjectConnectionUtils + +class CModularObjectConnectionCallback : public AbilityConnectCallback { +public: + CModularObjectConnectionCallback( + const std::shared_ptr &state); + ~CModularObjectConnectionCallback() override = default; + + void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) override; + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + + void SetConnectionId(int64_t id) { connectionId_ = id; } + int64_t GetConnectionId() const { return connectionId_; } + +private: + int64_t connectionId_ = 0; + std::weak_ptr state_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_C_MODULAR_OBJECT_CONNECTION_CALLBACK_H diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_utils.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_utils.h new file mode 100644 index 0000000000..66f5aa9aca --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/c_modular_object_utils.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026 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 MOCK_C_MODULAR_OBJECT_UTILS_H +#define MOCK_C_MODULAR_OBJECT_UTILS_H + +#include +#include + +#include "element_name.h" +#include "connect_options_impl.h" + +struct AbilityBase_Element { + char *bundleName = nullptr; + char *moduleName = nullptr; + char *abilityName = nullptr; +}; + +namespace OHOS { +namespace AbilityRuntime { + +class CModularObjectUtils { +public: + static bool buildElementResult; + static bool notifyFailedCalled; + static int32_t notifyFailedCode; + static int32_t convertConnectResult; + + static bool BuildElement(const AppExecFwk::ElementName &elementName, AbilityBase_Element &element) + { + if (!buildElementResult) { + return false; + } + std::string bn = elementName.GetBundleName(); + element.bundleName = new char[bn.size() + 1]; + (void)strcpy_s(element.bundleName, bn.size() + 1, bn.c_str()); + std::string an = elementName.GetAbilityName(); + element.abilityName = new char[an.size() + 1]; + (void)strcpy_s(element.abilityName, an.size() + 1, an.c_str()); + return true; + } + + static void DestroyElement(AbilityBase_Element &element) + { + delete[] element.bundleName; + delete[] element.moduleName; + delete[] element.abilityName; + element.bundleName = nullptr; + element.moduleName = nullptr; + element.abilityName = nullptr; + } + + static void NotifyFailed(std::shared_ptr state, int32_t code) + { + notifyFailedCalled = true; + notifyFailedCode = code; + if (state == nullptr || !state->alive || state->onFailedCallback == nullptr) { + return; + } + state->onFailedCallback(state->owner, static_cast(code)); + } + + static AbilityRuntime_ErrorCode ConvertConnectBusinessErrorCode(int32_t errCode) + { + if (convertConnectResult != 0) { + return static_cast(convertConnectResult); + } + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; + } +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_C_MODULAR_OBJECT_UTILS_H diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/connect_options_impl.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/connect_options_impl.h new file mode 100644 index 0000000000..52f3cf9bb2 --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/connect_options_impl.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026 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 MOCK_CONNECT_OPTIONS_IMPL_H +#define MOCK_CONNECT_OPTIONS_IMPL_H + +#include +#include + +struct AbilityBase_Element; +typedef struct AbilityBase_Element AbilityBase_Element; + +enum AbilityRuntime_ErrorCode { + ABILITY_RUNTIME_ERROR_CODE_NO_ERROR = 0, + ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID = 401, + ABILITY_RUNTIME_ERROR_CODE_INTERNAL = 16005000, +}; + +struct OH_AbilityRuntime_ConnectOptions; + +typedef void (*OH_AbilityRuntime_ConnectOptions_OnConnectCallback)( + OH_AbilityRuntime_ConnectOptions *, AbilityBase_Element *, void *); +typedef void (*OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback)( + OH_AbilityRuntime_ConnectOptions *, AbilityBase_Element *); +typedef void (*OH_AbilityRuntime_ConnectOptions_OnFailedCallback)( + OH_AbilityRuntime_ConnectOptions *, AbilityRuntime_ErrorCode); + +struct OH_AbilityRuntime_ConnectOptionsState { + std::mutex mutex; + bool alive = true; + OH_AbilityRuntime_ConnectOptions *owner = nullptr; + OH_AbilityRuntime_ConnectOptions_OnConnectCallback onConnectCallback = nullptr; + OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback onDisconnectCallback = nullptr; + OH_AbilityRuntime_ConnectOptions_OnFailedCallback onFailedCallback = nullptr; +}; + +struct OH_AbilityRuntime_ConnectOptions { + std::shared_ptr state; +}; + +#endif // MOCK_CONNECT_OPTIONS_IMPL_H diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/element_name.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/element_name.h new file mode 100644 index 0000000000..a79ce35445 --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/element_name.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 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 MOCK_ELEMENT_NAME_H +#define MOCK_ELEMENT_NAME_H + +#include + +namespace OHOS { +namespace AppExecFwk { +class ElementName { +public: + ElementName() = default; + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &abilityName) + : bundleName_(bundleName), abilityName_(abilityName) {} + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &moduleName, const std::string &abilityName) + : bundleName_(bundleName), moduleName_(moduleName), abilityName_(abilityName) {} + + std::string GetBundleName() const { return bundleName_; } + std::string GetModuleName() const { return moduleName_; } + std::string GetAbilityName() const { return abilityName_; } + void SetBundleName(const std::string &name) { bundleName_ = name; } + void SetModuleName(const std::string &name) { moduleName_ = name; } + void SetAbilityName(const std::string &name) { abilityName_ = name; } + +private: + std::string bundleName_; + std::string moduleName_; + std::string abilityName_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_ELEMENT_NAME_H \ No newline at end of file diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/ipc_inner_object.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/ipc_inner_object.h new file mode 100644 index 0000000000..46c8142072 --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/ipc_inner_object.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 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 MOCK_IPC_INNER_OBJECT_H +#define MOCK_IPC_INNER_OBJECT_H + +#include + +namespace OHOS { +class IRemoteObject; +} // namespace OHOS + +struct OHIPCRemoteProxy { + OHOS::sptr remote; +}; + +struct OHIPCRemoteStub { + OHOS::sptr remote; +}; + +static inline OHIPCRemoteProxy *CreateIPCRemoteProxy(OHOS::sptr &object) +{ + if (object == nullptr) { + return nullptr; + } + auto *proxy = new (std::nothrow) OHIPCRemoteProxy(); + if (proxy != nullptr) { + proxy->remote = object; + } + return proxy; +} + +#endif // MOCK_IPC_INNER_OBJECT_H diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_connection_manager.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_connection_manager.h new file mode 100644 index 0000000000..6db7c1976a --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_connection_manager.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_CONNECTION_MANAGER_H +#define MOCK_MODULAR_OBJECT_CONNECTION_MANAGER_H + +#include "element_name.h" +#include "ability_connect_callback.h" + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectConnectionManager { +public: + static ModularObjectConnectionManager &GetInstance() + { + static ModularObjectConnectionManager instance; + return instance; + } + int32_t DisconnectModularObjectExtension(const sptr &callback) + { + return 0; + } + bool DisconnectNonexistentService(const AppExecFwk::ElementName &element, + const sptr &connection) + { + return false; + } +private: + ModularObjectConnectionManager() = default; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_CONNECTION_MANAGER_H diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_extension_types.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_extension_types.h new file mode 100644 index 0000000000..9942327744 --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/modular_object_extension_types.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H +#define MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H + +#include +#include +#include "connect_options_impl.h" + +namespace OHOS { +namespace AbilityRuntime { + +struct AbilityRuntime_Context { + int type = 0; + std::weak_ptr context; +}; + +struct OH_AbilityRuntime_ModularObjectExtensionContext : public AbilityRuntime_Context {}; + +struct OH_AbilityRuntime_ExtensionInstance { + int type = 0; + std::weak_ptr extension; + std::shared_ptr context; +}; + +struct OH_AbilityRuntime_ModularObjectExtensionInstance : public OH_AbilityRuntime_ExtensionInstance { + void *onCreateFunc = nullptr; + void *onDestroyFunc = nullptr; + void *(*onConnectFunc)(void *, void *) = nullptr; + void *onDisconnectFunc = nullptr; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H diff --git a/test/unittest/c_modular_object_connection_callback_test/mock/include/want_manager.h b/test/unittest/c_modular_object_connection_callback_test/mock/include/want_manager.h new file mode 100644 index 0000000000..762d6ee09e --- /dev/null +++ b/test/unittest/c_modular_object_connection_callback_test/mock/include/want_manager.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 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 MOCK_WANT_MANAGER_H +#define MOCK_WANT_MANAGER_H + +// Empty mock - not used by c_modular_object_connection_callback.cpp + +#endif // MOCK_WANT_MANAGER_H diff --git a/test/unittest/c_modular_object_utils_test/BUILD.gn b/test/unittest/c_modular_object_utils_test/BUILD.gn new file mode 100644 index 0000000000..4fc88cc83d --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/BUILD.gn @@ -0,0 +1,62 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("c_modular_object_utils_test") { + module_out_path = "ability_runtime/ability_runtime/c_modular_object_utils_test" + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + + sources = [ + "c_modular_object_utils_test.cpp", + "mock/src/mock_ability_business_error_utils.cpp", + "mock/src/mock_my_flag.cpp", + "mock/src/mock_want_manager.cpp", + "mock/src/mock_want_utils.cpp", + "${ability_runtime_path}/frameworks/c/ability_runtime/src/c_modular_object_utils.cpp", + ] + + include_dirs = [ + "mock/include", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_ndk_path}/ability_runtime", + "${ability_runtime_innerkits_path}/ability_manager/include", + "${ability_runtime_services_path}/common/include", + ] + + deps = [] + + external_deps = [ + "c_utils:utils", + "googletest:gmock_main", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] + + cflags_cc = [] + configs = [] +} + +group("unittest") { + testonly = true + deps = [ ":c_modular_object_utils_test" ] +} diff --git a/test/unittest/c_modular_object_utils_test/c_modular_object_utils_test.cpp b/test/unittest/c_modular_object_utils_test/c_modular_object_utils_test.cpp new file mode 100644 index 0000000000..af951ddba2 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/c_modular_object_utils_test.cpp @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2026 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 + +#include +#include +#include +#include + +#include "ability_manager_errors.h" +#include "ability_runtime_common.h" +#include "c_modular_object_utils.h" +#include "element_name.h" +#include "iremote_object.h" +#include "iremote_broker.h" +#include "message_parcel.h" +#include "message_option.h" +#include "mock_context_base.h" +#include "mock_my_flag.h" +#include "native_extension/context_impl.h" +#include "want_manager.h" + +using namespace testing; +using namespace testing::ext; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; + +// Complete the forward-declared AbilityBase_Want at global scope +struct AbilityBase_Want { + AbilityBase_Element element; + int dummy = 0; +}; + +namespace OHOS { +namespace AbilityRuntime { +namespace { + +class MockRemoteObject : public IRemoteObject { +public: + MockRemoteObject() : IRemoteObject(u"mock_descriptor") {} + ~MockRemoteObject() = default; + + int32_t GetObjectRefCount() override { return 0; } + int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override + { + (void)code; + (void)data; + (void)reply; + (void)option; + return 0; + } + bool IsProxyObject() const override { return true; } + bool CheckObjectLegality() const override { return true; } + bool AddDeathRecipient(const sptr &recipient) override + { + (void)recipient; + return true; + } + bool RemoveDeathRecipient(const sptr &recipient) override + { + (void)recipient; + return true; + } + bool Marshalling(Parcel &parcel) const override + { + (void)parcel; + return true; + } + sptr AsInterface() override { return nullptr; } + int Dump(int fd, const std::vector &args) override + { + (void)fd; + (void)args; + return 0; + } + std::u16string GetObjectDescriptor() const { return std::u16string(); } +}; + +} // namespace + +class CModularObjectUtilsTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() override + { + MyFlag::retCheckWant = 0; + MyFlag::retTransformToWant = 0; + MyFlag::retConvertToCommonBusinessErrorCode = 0; + } + void TearDown() override {} +}; + +// ==================== ConvertConnectBusinessErrorCode ==================== + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_001 start"; + // ABILITY_VISIBLE_FALSE_DENY_REQUEST -> VISIBILITY_VERIFICATION_FAILED + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ABILITY_VISIBLE_FALSE_DENY_REQUEST); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_VISIBILITY_VERIFICATION_FAILED); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_001 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_002 start"; + // ERR_STATIC_CFG_PERMISSION -> STATIC_CFG_PERMISSION + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_STATIC_CFG_PERMISSION); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_STATIC_CFG_PERMISSION); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_002 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_003 start"; + // ERR_CROSS_USER -> CROSS_USER_OPERATION + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_CROSS_USER); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_CROSS_USER_OPERATION); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_003 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_004 start"; + // ERR_CHECK_CALL_FROM_BACKGROUND_FAILED -> NO_RUNNING_ABILITIES_WITH_UI + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_CHECK_CALL_FROM_BACKGROUND_FAILED); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_RUNNING_ABILITIES_WITH_UI); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_004 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_005 start"; + // ERR_FREQ_START_ABILITY -> UPPER_RATE_LIMIT + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_FREQ_START_ABILITY); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_UPPER_RATE_LIMIT); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_005 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_006, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_006 start"; + // ERR_REACH_UPPER_LIMIT -> UPPER_CONNECTION_NUMBER_LIMIT + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_REACH_UPPER_LIMIT); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_UPPER_CONNECTION_NUMBER_LIMIT); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_006 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_007, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_007 start"; + // ERR_UPPER_LIMIT -> UPPER_CONNECTION_NUMBER_LIMIT (same as ERR_REACH_UPPER_LIMIT) + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_UPPER_LIMIT); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_UPPER_CONNECTION_NUMBER_LIMIT); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_007 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_008, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_008 start"; + // ERR_MODULAR_OBJECT_DISABLED -> MODULAR_OBJECT_EXTENSION_DISABLED + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_MODULAR_OBJECT_DISABLED); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_MODULAR_OBJECT_EXTENSION_DISABLED); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_008 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_009, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_009 start"; + // ERR_NO_RUNNING_ABILITIES_WITH_UI -> NO_RUNNING_ABILITIES_WITH_UI + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(ERR_NO_RUNNING_ABILITIES_WITH_UI); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_RUNNING_ABILITIES_WITH_UI); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_009 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_010, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_010 start"; + // default case -> calls ConvertToCommonBusinessErrorCode + MyFlag::retConvertToCommonBusinessErrorCode = ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED; + int32_t unknownErrCode = 9999999; + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(unknownErrCode); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_010 end"; +} + +HWTEST_F(CModularObjectUtilsTest, ConvertConnectBusinessErrorCode_011, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_011 start"; + // default case with mock returning default value + MyFlag::retConvertToCommonBusinessErrorCode = 0; + int32_t unknownErrCode = 1; + auto ret = CModularObjectUtils::ConvertConnectBusinessErrorCode(unknownErrCode); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INTERNAL); + GTEST_LOG_(INFO) << "ConvertConnectBusinessErrorCode_011 end"; +} + +// ==================== CopyToCString ==================== + +HWTEST_F(CModularObjectUtilsTest, CopyToCString_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CopyToCString_001 start"; + // success: normal string + char *dst = nullptr; + std::string src = "hello"; + bool ret = CModularObjectUtils::CopyToCString(src, dst); + EXPECT_TRUE(ret); + ASSERT_NE(dst, nullptr); + EXPECT_STREQ(dst, "hello"); + delete[] dst; + GTEST_LOG_(INFO) << "CopyToCString_001 end"; +} + +HWTEST_F(CModularObjectUtilsTest, CopyToCString_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CopyToCString_002 start"; + // success: empty string + char *dst = nullptr; + std::string src = ""; + bool ret = CModularObjectUtils::CopyToCString(src, dst); + EXPECT_TRUE(ret); + ASSERT_NE(dst, nullptr); + EXPECT_STREQ(dst, ""); + delete[] dst; + GTEST_LOG_(INFO) << "CopyToCString_002 end"; +} + +HWTEST_F(CModularObjectUtilsTest, CopyToCString_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CopyToCString_003 start"; + // success: string with special characters + char *dst = nullptr; + std::string src = "com.example.test/Module:Ability"; + bool ret = CModularObjectUtils::CopyToCString(src, dst); + EXPECT_TRUE(ret); + ASSERT_NE(dst, nullptr); + EXPECT_STREQ(dst, src.c_str()); + delete[] dst; + GTEST_LOG_(INFO) << "CopyToCString_003 end"; +} + +// ==================== BuildElement ==================== + +HWTEST_F(CModularObjectUtilsTest, BuildElement_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BuildElement_001 start"; + // success: all fields populated + ElementName elementName("", "com.test.bundle", "com.test.module", "TestAbility"); + AbilityBase_Element element = {nullptr, nullptr, nullptr}; + bool ret = CModularObjectUtils::BuildElement(elementName, element); + EXPECT_TRUE(ret); + ASSERT_NE(element.bundleName, nullptr); + EXPECT_STREQ(element.bundleName, "com.test.bundle"); + ASSERT_NE(element.moduleName, nullptr); + EXPECT_STREQ(element.moduleName, "com.test.module"); + ASSERT_NE(element.abilityName, nullptr); + EXPECT_STREQ(element.abilityName, "TestAbility"); + CModularObjectUtils::DestroyElement(element); + GTEST_LOG_(INFO) << "BuildElement_001 end"; +} + +HWTEST_F(CModularObjectUtilsTest, BuildElement_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BuildElement_002 start"; + // success: fields with empty strings + ElementName elementName("", "", "", ""); + AbilityBase_Element element = {nullptr, nullptr, nullptr}; + bool ret = CModularObjectUtils::BuildElement(elementName, element); + EXPECT_TRUE(ret); + ASSERT_NE(element.bundleName, nullptr); + EXPECT_STREQ(element.bundleName, ""); + ASSERT_NE(element.moduleName, nullptr); + EXPECT_STREQ(element.moduleName, ""); + ASSERT_NE(element.abilityName, nullptr); + EXPECT_STREQ(element.abilityName, ""); + CModularObjectUtils::DestroyElement(element); + GTEST_LOG_(INFO) << "BuildElement_002 end"; +} + +// ==================== DestroyElement ==================== + +HWTEST_F(CModularObjectUtilsTest, DestroyElement_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DestroyElement_001 start"; + // destroy populated element + AbilityBase_Element element; + element.bundleName = new char[5]; + (void)strcpy_s(element.bundleName, 5, "test"); + element.moduleName = new char[4]; + (void)strcpy_s(element.moduleName, 4, "mod"); + element.abilityName = new char[4]; + (void)strcpy_s(element.abilityName, 4, "abc"); + + CModularObjectUtils::DestroyElement(element); + EXPECT_EQ(element.bundleName, nullptr); + EXPECT_EQ(element.moduleName, nullptr); + EXPECT_EQ(element.abilityName, nullptr); + GTEST_LOG_(INFO) << "DestroyElement_001 end"; +} + +HWTEST_F(CModularObjectUtilsTest, DestroyElement_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DestroyElement_002 start"; + // destroy element with null fields (no crash) + AbilityBase_Element element = {nullptr, nullptr, nullptr}; + CModularObjectUtils::DestroyElement(element); + EXPECT_EQ(element.bundleName, nullptr); + EXPECT_EQ(element.moduleName, nullptr); + EXPECT_EQ(element.abilityName, nullptr); + GTEST_LOG_(INFO) << "DestroyElement_002 end"; +} + +// ==================== NotifyFailed ==================== + +// Global callback tracking for NotifyFailed tests +namespace { +OH_AbilityRuntime_ConnectOptions *g_capturedOwner = nullptr; +AbilityRuntime_ErrorCode g_capturedErrorCode = ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +int32_t g_callbackCallCount = 0; + +void ResetCallbackState() +{ + g_capturedOwner = nullptr; + g_capturedErrorCode = ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; + g_callbackCallCount = 0; +} + +void MockOnFailedCallback(OH_AbilityRuntime_ConnectOptions *owner, AbilityRuntime_ErrorCode code) +{ + g_capturedOwner = owner; + g_capturedErrorCode = code; + g_callbackCallCount++; +} +} // namespace + +HWTEST_F(CModularObjectUtilsTest, NotifyFailed_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "NotifyFailed_001 start"; + // state is nullptr -> early return, no crash + ResetCallbackState(); + CModularObjectUtils::NotifyFailed(nullptr, ERR_MODULAR_OBJECT_DISABLED); + EXPECT_EQ(g_callbackCallCount, 0); + GTEST_LOG_(INFO) << "NotifyFailed_001 end"; +} + +HWTEST_F(CModularObjectUtilsTest, NotifyFailed_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "NotifyFailed_002 start"; + // state alive is false -> early return + ResetCallbackState(); + auto state = std::make_shared(); + state->alive = false; + state->onFailedCallback = MockOnFailedCallback; + CModularObjectUtils::NotifyFailed(state, ERR_MODULAR_OBJECT_DISABLED); + EXPECT_EQ(g_callbackCallCount, 0); + GTEST_LOG_(INFO) << "NotifyFailed_002 end"; +} + +HWTEST_F(CModularObjectUtilsTest, NotifyFailed_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "NotifyFailed_003 start"; + // callback is nullptr -> no call + ResetCallbackState(); + auto state = std::make_shared(); + state->alive = true; + state->onFailedCallback = nullptr; + CModularObjectUtils::NotifyFailed(state, ERR_MODULAR_OBJECT_DISABLED); + EXPECT_EQ(g_callbackCallCount, 0); + GTEST_LOG_(INFO) << "NotifyFailed_003 end"; +} + +HWTEST_F(CModularObjectUtilsTest, NotifyFailed_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "NotifyFailed_004 start"; + // callback is non-null -> callback invoked with correct error code + ResetCallbackState(); + OH_AbilityRuntime_ConnectOptions owner; + owner.state = nullptr; + + auto state = std::make_shared(); + state->alive = true; + state->owner = &owner; + state->onFailedCallback = MockOnFailedCallback; + + CModularObjectUtils::NotifyFailed(state, ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED); + EXPECT_EQ(g_callbackCallCount, 1); + EXPECT_EQ(g_capturedOwner, &owner); + EXPECT_EQ(g_capturedErrorCode, ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED); + GTEST_LOG_(INFO) << "NotifyFailed_004 end"; +} + +HWTEST_F(CModularObjectUtilsTest, NotifyFailed_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "NotifyFailed_005 start"; + // verify error code is cast correctly from int32_t + ResetCallbackState(); + auto state = std::make_shared(); + state->alive = true; + state->owner = nullptr; + state->onFailedCallback = MockOnFailedCallback; + + int32_t businessCode = ABILITY_RUNTIME_ERROR_CODE_MODULAR_OBJECT_EXTENSION_DISABLED; + CModularObjectUtils::NotifyFailed(state, businessCode); + EXPECT_EQ(g_callbackCallCount, 1); + EXPECT_EQ(g_capturedErrorCode, ABILITY_RUNTIME_ERROR_CODE_MODULAR_OBJECT_EXTENSION_DISABLED); + GTEST_LOG_(INFO) << "NotifyFailed_005 end"; +} + +// ==================== TransformWant ==================== + +HWTEST_F(CModularObjectUtilsTest, TransformWant_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TransformWant_001 start"; + // CheckWant returns error -> propagate error + MyFlag::retCheckWant = ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + AbilityBase_Want want; + want.element = {nullptr, nullptr, nullptr}; + AAFwk::Want abilityWant; + auto ret = CModularObjectUtils::TransformWant(reinterpret_cast(&want), abilityWant); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "TransformWant_001 end"; +} + +HWTEST_F(CModularObjectUtilsTest, TransformWant_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TransformWant_002 start"; + // CheckWant succeeds, TransformToWant returns error + MyFlag::retCheckWant = 0; + MyFlag::retTransformToWant = ABILITY_BASE_ERROR_CODE_PARAM_INVALID; + AbilityBase_Want want; + want.element = {nullptr, nullptr, nullptr}; + AAFwk::Want abilityWant; + auto ret = CModularObjectUtils::TransformWant(reinterpret_cast(&want), abilityWant); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "TransformWant_002 end"; +} + +HWTEST_F(CModularObjectUtilsTest, TransformWant_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TransformWant_003 start"; + // success path + MyFlag::retCheckWant = 0; + MyFlag::retTransformToWant = 0; + AbilityBase_Want want; + want.element = {nullptr, nullptr, nullptr}; + AAFwk::Want abilityWant; + auto ret = CModularObjectUtils::TransformWant(reinterpret_cast(&want), abilityWant); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + GTEST_LOG_(INFO) << "TransformWant_003 end"; +} + +// ==================== CheckContextAndToken ==================== + +HWTEST_F(CModularObjectUtilsTest, CheckContextAndToken_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckContextAndToken_001 start"; + // context is nullptr + sptr token; + auto ret = CModularObjectUtils::CheckContextAndToken(nullptr, token); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "CheckContextAndToken_001 end"; +} + +HWTEST_F(CModularObjectUtilsTest, CheckContextAndToken_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckContextAndToken_002 start"; + // context->context.lock() returns nullptr (expired weak_ptr) + AbilityRuntime_Context context; + context.type = 0; + // weak_ptr is default-constructed (expired) + context.context = std::weak_ptr(); + + sptr token; + auto ret = CModularObjectUtils::CheckContextAndToken(&context, token); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST); + GTEST_LOG_(INFO) << "CheckContextAndToken_002 end"; +} + +HWTEST_F(CModularObjectUtilsTest, CheckContextAndToken_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckContextAndToken_003 start"; + // GetToken returns nullptr + auto mockContext = std::make_shared(); + EXPECT_CALL(*mockContext, GetToken()).Times(1).WillOnce(Return(sptr(nullptr))); + + AbilityRuntime_Context context; + context.type = 0; + context.context = mockContext; + + sptr token; + auto ret = CModularObjectUtils::CheckContextAndToken(&context, token); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST); + GTEST_LOG_(INFO) << "CheckContextAndToken_003 end"; +} + +HWTEST_F(CModularObjectUtilsTest, CheckContextAndToken_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckContextAndToken_004 start"; + // success path: GetToken returns valid token + sptr expectedToken = sptr(new (std::nothrow) MockRemoteObject()); + ASSERT_NE(expectedToken, nullptr); + auto mockContext = std::make_shared(); + EXPECT_CALL(*mockContext, GetToken()).Times(1).WillOnce(Return(expectedToken)); + + AbilityRuntime_Context context; + context.type = 0; + context.context = mockContext; + + sptr token; + auto ret = CModularObjectUtils::CheckContextAndToken(&context, token); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_EQ(token.GetRefPtr(), expectedToken.GetRefPtr()); + GTEST_LOG_(INFO) << "CheckContextAndToken_004 end"; +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/test/unittest/c_modular_object_utils_test/mock/include/connect_options.h b/test/unittest/c_modular_object_utils_test/mock/include/connect_options.h new file mode 100644 index 0000000000..aa0ae6a23f --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/include/connect_options.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026 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 ABILITY_RUNTIME_CONNECT_OPTIONS_H +#define ABILITY_RUNTIME_CONNECT_OPTIONS_H + +#include +#include "ability_runtime_common.h" +#include "want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OHIPCRemoteProxy OHIPCRemoteProxy; + +typedef struct OH_AbilityRuntime_ConnectOptions OH_AbilityRuntime_ConnectOptions; + +typedef void (*OH_AbilityRuntime_ConnectOptions_OnConnectCallback)( + OH_AbilityRuntime_ConnectOptions *, AbilityBase_Element *, OHIPCRemoteProxy *); + +typedef void (*OH_AbilityRuntime_ConnectOptions_OnDisconnectCallback)( + OH_AbilityRuntime_ConnectOptions *, AbilityBase_Element *); + +typedef void (*OH_AbilityRuntime_ConnectOptions_OnFailedCallback)( + OH_AbilityRuntime_ConnectOptions *, AbilityRuntime_ErrorCode); + +#ifdef __cplusplus +} +#endif + +#endif // ABILITY_RUNTIME_CONNECT_OPTIONS_H diff --git a/test/unittest/c_modular_object_utils_test/mock/include/element_name.h b/test/unittest/c_modular_object_utils_test/mock/include/element_name.h new file mode 100644 index 0000000000..26ab3d1fa6 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/include/element_name.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2026 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 MOCK_ELEMENT_NAME_H +#define MOCK_ELEMENT_NAME_H + +#include + +namespace OHOS { +namespace AppExecFwk { +class ElementName { +public: + ElementName() = default; + ElementName(const std::string &deviceId, const std::string &bundleName, const std::string &abilityName) + : deviceId_(deviceId), bundleName_(bundleName), abilityName_(abilityName) {} + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &moduleName, const std::string &abilityName) + : deviceId_(deviceId), bundleName_(bundleName), moduleName_(moduleName), abilityName_(abilityName) {} + + std::string GetBundleName() const { return bundleName_; } + std::string GetModuleName() const { return moduleName_; } + std::string GetAbilityName() const { return abilityName_; } + std::string GetDeviceID() const { return deviceId_; } + +private: + std::string deviceId_; + std::string bundleName_; + std::string moduleName_; + std::string abilityName_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_ELEMENT_NAME_H diff --git a/test/unittest/c_modular_object_utils_test/mock/include/mock_context_base.h b/test/unittest/c_modular_object_utils_test/mock/include/mock_context_base.h new file mode 100644 index 0000000000..6982f4d484 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/include/mock_context_base.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026 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 MOCK_CONTEXT_BASE_H +#define MOCK_CONTEXT_BASE_H + +#include +#include "iremote_object.h" + +namespace OHOS { +namespace AbilityRuntime { + +class ContextBase { +public: + virtual ~ContextBase() = default; + virtual sptr GetToken() = 0; +}; + +class MockContext : public ContextBase { +public: + MOCK_METHOD(sptr, GetToken, (), (override)); +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_CONTEXT_BASE_H diff --git a/test/unittest/c_modular_object_utils_test/mock/include/mock_my_flag.h b/test/unittest/c_modular_object_utils_test/mock/include/mock_my_flag.h new file mode 100644 index 0000000000..c03f07a177 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/include/mock_my_flag.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2026 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 MOCK_MY_FLAG_H +#define MOCK_MY_FLAG_H + +#include + +class MyFlag { +public: + // CheckWant return value (0 = ABILITY_RUNTIME_ERROR_CODE_NO_ERROR) + static int32_t retCheckWant; + // CWantManager::TransformToWant return value (0 = ABILITY_BASE_ERROR_CODE_NO_ERROR) + static int32_t retTransformToWant; + // ConvertToCommonBusinessErrorCode return value + static int32_t retConvertToCommonBusinessErrorCode; +}; + +#endif // MOCK_MY_FLAG_H diff --git a/test/unittest/c_modular_object_utils_test/mock/include/native_extension/context_impl.h b/test/unittest/c_modular_object_utils_test/mock/include/native_extension/context_impl.h new file mode 100644 index 0000000000..05d8235e8d --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/include/native_extension/context_impl.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2026 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 ABILITY_RUNTIME_CONTEXT_IMPL_H +#define ABILITY_RUNTIME_CONTEXT_IMPL_H + +#include +#include "mock_context_base.h" + +struct AbilityRuntime_Context { + int type; + std::weak_ptr context; +}; + +#endif // ABILITY_RUNTIME_CONTEXT_IMPL_H diff --git a/test/unittest/c_modular_object_utils_test/mock/include/want.h b/test/unittest/c_modular_object_utils_test/mock/include/want.h new file mode 100644 index 0000000000..45089130a6 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/include/want.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026 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 ABILITY_BASE_WANT_H +#define ABILITY_BASE_WANT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct AbilityBase_Element { + char *bundleName; + char *moduleName; + char *abilityName; +} AbilityBase_Element; + +struct AbilityBase_Want; +typedef struct AbilityBase_Want AbilityBase_Want; + +typedef enum { + ABILITY_BASE_ERROR_CODE_NO_ERROR = 0, + ABILITY_BASE_ERROR_CODE_PARAM_INVALID = 401, +} AbilityBase_ErrorCode; + +#ifdef __cplusplus +} +#endif + +// Forward-declare AAFwk::Want for c_modular_object_utils.h +namespace OHOS { +namespace AAFwk { +class Want; +} // namespace AAFwk +} // namespace OHOS + +#endif // ABILITY_BASE_WANT_H \ No newline at end of file diff --git a/test/unittest/c_modular_object_utils_test/mock/include/want_manager.h b/test/unittest/c_modular_object_utils_test/mock/include/want_manager.h new file mode 100644 index 0000000000..41c975bfd6 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/include/want_manager.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 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 WANT_MANAGER_H +#define WANT_MANAGER_H + +#include "want.h" + +namespace OHOS { +namespace AAFwk { + +class Want {}; + +class CWantManager { +public: + static AbilityBase_ErrorCode TransformToWant(AbilityBase_Want &cWant, bool flag, Want &abilityWant); +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // WANT_MANAGER_H diff --git a/test/unittest/c_modular_object_utils_test/mock/src/mock_ability_business_error_utils.cpp b/test/unittest/c_modular_object_utils_test/mock/src/mock_ability_business_error_utils.cpp new file mode 100644 index 0000000000..8a33269bc4 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/src/mock_ability_business_error_utils.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2026 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_business_error_utils.h" +#include "mock_my_flag.h" + +AbilityRuntime_ErrorCode ConvertToCommonBusinessErrorCode(int32_t abilityManagerErrorCode) +{ + if (MyFlag::retConvertToCommonBusinessErrorCode != 0) { + return static_cast(MyFlag::retConvertToCommonBusinessErrorCode); + } + return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; +} diff --git a/test/unittest/c_modular_object_utils_test/mock/src/mock_my_flag.cpp b/test/unittest/c_modular_object_utils_test/mock/src/mock_my_flag.cpp new file mode 100644 index 0000000000..f3aec56210 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/src/mock_my_flag.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2026 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 "mock_my_flag.h" + +int32_t MyFlag::retCheckWant = 0; +int32_t MyFlag::retTransformToWant = 0; +int32_t MyFlag::retConvertToCommonBusinessErrorCode = 0; diff --git a/test/unittest/c_modular_object_utils_test/mock/src/mock_want_manager.cpp b/test/unittest/c_modular_object_utils_test/mock/src/mock_want_manager.cpp new file mode 100644 index 0000000000..a94e524137 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/src/mock_want_manager.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2026 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 "want_manager.h" +#include "mock_my_flag.h" + +namespace OHOS { +namespace AAFwk { + +AbilityBase_ErrorCode CWantManager::TransformToWant(AbilityBase_Want &cWant, bool flag, Want &abilityWant) +{ + if (MyFlag::retTransformToWant != 0) { + return static_cast(MyFlag::retTransformToWant); + } + return ABILITY_BASE_ERROR_CODE_NO_ERROR; +} + +} // namespace AAFwk +} // namespace OHOS diff --git a/test/unittest/c_modular_object_utils_test/mock/src/mock_want_utils.cpp b/test/unittest/c_modular_object_utils_test/mock/src/mock_want_utils.cpp new file mode 100644 index 0000000000..13099a1b41 --- /dev/null +++ b/test/unittest/c_modular_object_utils_test/mock/src/mock_want_utils.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2026 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 "want_utils.h" +#include "mock_my_flag.h" + +AbilityRuntime_ErrorCode CheckWant(AbilityBase_Want *want) +{ + if (MyFlag::retCheckWant != 0) { + return static_cast(MyFlag::retCheckWant); + } + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; +} diff --git a/test/unittest/connect_options_test/BUILD.gn b/test/unittest/connect_options_test/BUILD.gn new file mode 100644 index 0000000000..5dd8a91e72 --- /dev/null +++ b/test/unittest/connect_options_test/BUILD.gn @@ -0,0 +1,48 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("connect_options_test") { + module_out_path = "ability_runtime/ability_runtime/connect_options_test" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + sources = [ + "connect_options_test.cpp", + "${ability_runtime_path}/frameworks/c/ability_runtime/src/connect_options.cpp", + ] + include_dirs = [ + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_ndk_path}/ability_runtime", + "${ability_runtime_services_path}/common/include", + ] + external_deps = [ + "ability_base:ability_base_want", + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_capi", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":connect_options_test" ] +} diff --git a/test/unittest/connect_options_test/connect_options_test.cpp b/test/unittest/connect_options_test/connect_options_test.cpp new file mode 100644 index 0000000000..40868c6058 --- /dev/null +++ b/test/unittest/connect_options_test/connect_options_test.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2026 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 "connect_options.h" +#include "connect_options_impl.h" + +using namespace testing::ext; + +namespace { + +static void OnConnectCallback(OH_AbilityRuntime_ConnectOptions *opts, + AbilityBase_Element *element, OHIPCRemoteProxy *proxy) {} + +static void OnDisconnectCallback(OH_AbilityRuntime_ConnectOptions *opts, + AbilityBase_Element *element) {} + +static void OnFailedCallback(OH_AbilityRuntime_ConnectOptions *opts, AbilityRuntime_ErrorCode code) {} + +} // namespace + +class ConnectOptionsTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() override {} + void TearDown() override {} +}; + +// ==================== CreateConnectOptions ==================== + +HWTEST_F(ConnectOptionsTest, CreateConnectOptions_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CreateConnectOptions_001 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + EXPECT_NE(opts->state, nullptr); + EXPECT_TRUE(opts->state->alive); + EXPECT_EQ(opts->state->owner, opts); + EXPECT_EQ(opts->state->onConnectCallback, nullptr); + EXPECT_EQ(opts->state->onDisconnectCallback, nullptr); + EXPECT_EQ(opts->state->onFailedCallback, nullptr); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "CreateConnectOptions_001 end"; +} + +// ==================== DestroyConnectOptions ==================== + +HWTEST_F(ConnectOptionsTest, DestroyConnectOptions_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DestroyConnectOptions_001 start"; + auto ret = OH_AbilityRuntime_DestroyConnectOptions(nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "DestroyConnectOptions_001 end"; +} + +HWTEST_F(ConnectOptionsTest, DestroyConnectOptions_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DestroyConnectOptions_002 start"; + OH_AbilityRuntime_ConnectOptions opts; + opts.state = nullptr; + auto ret = OH_AbilityRuntime_DestroyConnectOptions(&opts); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "DestroyConnectOptions_002 end"; +} + +HWTEST_F(ConnectOptionsTest, DestroyConnectOptions_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DestroyConnectOptions_003 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + auto ret = OH_AbilityRuntime_DestroyConnectOptions(opts); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + GTEST_LOG_(INFO) << "DestroyConnectOptions_003 end"; +} + +// ==================== SetOnConnectCallback ==================== + +HWTEST_F(ConnectOptionsTest, SetOnConnectCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnConnectCallback_001 start"; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnConnectCallback(nullptr, OnConnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "SetOnConnectCallback_001 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnConnectCallback_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnConnectCallback_002 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnConnectCallback(opts, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnConnectCallback_002 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnConnectCallback_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnConnectCallback_003 start"; + OH_AbilityRuntime_ConnectOptions opts; + opts.state = nullptr; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnConnectCallback(&opts, OnConnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "SetOnConnectCallback_003 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnConnectCallback_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnConnectCallback_004 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + opts->state->alive = false; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnConnectCallback(opts, OnConnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnConnectCallback_004 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnConnectCallback_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnConnectCallback_005 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnConnectCallback(opts, OnConnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_EQ(opts->state->onConnectCallback, OnConnectCallback); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnConnectCallback_005 end"; +} + +// ==================== SetOnDisconnectCallback ==================== + +HWTEST_F(ConnectOptionsTest, SetOnDisconnectCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_001 start"; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnDisconnectCallback(nullptr, OnDisconnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_001 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnDisconnectCallback_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_002 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnDisconnectCallback(opts, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_002 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnDisconnectCallback_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_003 start"; + OH_AbilityRuntime_ConnectOptions opts; + opts.state = nullptr; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnDisconnectCallback(&opts, OnDisconnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_003 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnDisconnectCallback_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_004 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + opts->state->alive = false; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnDisconnectCallback(opts, OnDisconnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_004 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnDisconnectCallback_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_005 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnDisconnectCallback(opts, OnDisconnectCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_EQ(opts->state->onDisconnectCallback, OnDisconnectCallback); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnDisconnectCallback_005 end"; +} + +// ==================== SetOnFailedCallback ==================== + +HWTEST_F(ConnectOptionsTest, SetOnFailedCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnFailedCallback_001 start"; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnFailedCallback(nullptr, OnFailedCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "SetOnFailedCallback_001 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnFailedCallback_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnFailedCallback_002 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnFailedCallback(opts, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnFailedCallback_002 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnFailedCallback_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnFailedCallback_003 start"; + OH_AbilityRuntime_ConnectOptions opts; + opts.state = nullptr; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnFailedCallback(&opts, OnFailedCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "SetOnFailedCallback_003 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnFailedCallback_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnFailedCallback_004 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + opts->state->alive = false; + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnFailedCallback(opts, OnFailedCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnFailedCallback_004 end"; +} + +HWTEST_F(ConnectOptionsTest, SetOnFailedCallback_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SetOnFailedCallback_005 start"; + auto *opts = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(opts, nullptr); + auto ret = OH_AbilityRuntime_ConnectOptions_SetOnFailedCallback(opts, OnFailedCallback); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_EQ(opts->state->onFailedCallback, OnFailedCallback); + OH_AbilityRuntime_DestroyConnectOptions(opts); + GTEST_LOG_(INFO) << "SetOnFailedCallback_005 end"; +} diff --git a/test/unittest/modular_object_ability_connection_test/BUILD.gn b/test/unittest/modular_object_ability_connection_test/BUILD.gn new file mode 100644 index 0000000000..1af7730626 --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("modular_object_ability_connection_test") { + module_out_path = "ability_runtime/ability_runtime/modular_object_ability_connection_test" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + sources = [ + "modular_object_ability_connection_test.cpp", + "${ability_runtime_path}/frameworks/c/ability_runtime/src/modular_object_ability_connection.cpp", + ] + include_dirs = [ + "mock/include", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_services_path}/common/include", + ] + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_ability_connection_test" ] +} diff --git a/test/unittest/modular_object_ability_connection_test/mock/include/ability_connect_callback.h b/test/unittest/modular_object_ability_connection_test/mock/include/ability_connect_callback.h new file mode 100644 index 0000000000..de35fd9dab --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/mock/include/ability_connect_callback.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_CONNECT_CALLBACK_H +#define MOCK_ABILITY_CONNECT_CALLBACK_H + +#include "element_name.h" +#include "refbase.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AbilityRuntime { +class AbilityConnectCallback : public RefBase { +public: + AbilityConnectCallback() = default; + virtual ~AbilityConnectCallback() = default; + + virtual void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) = 0; + virtual void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) = 0; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_ABILITY_CONNECT_CALLBACK_H \ No newline at end of file diff --git a/test/unittest/modular_object_ability_connection_test/mock/include/ability_connection.h b/test/unittest/modular_object_ability_connection_test/mock/include/ability_connection.h new file mode 100644 index 0000000000..f25b9f8ff0 --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/mock/include/ability_connection.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_CONNECTION_H +#define MOCK_ABILITY_CONNECTION_H + +#include +#include +#include + +#include "ability_connect_callback.h" +#include "refbase.h" + +namespace OHOS { +namespace AbilityRuntime { +enum { + CONNECTION_STATE_DISCONNECTED = -1, + CONNECTION_STATE_CONNECTED = 0, + CONNECTION_STATE_CONNECTING = 1 +}; + +class AbilityConnection : public RefBase { +public: + AbilityConnection() = default; + virtual ~AbilityConnection() = default; + + virtual void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) {} + + virtual void OnAbilityDisconnectDone( + const AppExecFwk::ElementName &element, int resultCode) {} + + void AddConnectCallback(const sptr &cb) + { + std::lock_guard lock(mutex_); + callbackList_.push_back(cb); + } + + void RemoveConnectCallback(const sptr &cb) + { + std::lock_guard lock(mutex_); + auto it = std::find(callbackList_.begin(), callbackList_.end(), cb); + if (it != callbackList_.end()) { + callbackList_.erase(it); + } + } + + void SetRemoteObject(const sptr &obj) { remoteObject_ = obj; } + void SetResultCode(int code) { resultCode_ = code; } + void SetConnectionState(int state) { connectionState_ = state; } + sptr GetRemoteObject() const { return remoteObject_; } + int GetResultCode() const { return resultCode_; } + int GetConnectionState() const { return connectionState_; } + std::vector> GetCallbackList() { return callbackList_; } + +private: + std::vector> callbackList_; + sptr remoteObject_; + int resultCode_ = -1; + int connectionState_ = CONNECTION_STATE_DISCONNECTED; + std::mutex mutex_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_ABILITY_CONNECTION_H diff --git a/test/unittest/modular_object_ability_connection_test/mock/include/connection_manager.h b/test/unittest/modular_object_ability_connection_test/mock/include/connection_manager.h new file mode 100644 index 0000000000..7b4dc5b72f --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/mock/include/connection_manager.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 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 MOCK_CONNECTION_MANAGER_H +#define MOCK_CONNECTION_MANAGER_H + +#endif // MOCK_CONNECTION_MANAGER_H diff --git a/test/unittest/modular_object_ability_connection_test/mock/include/element_name.h b/test/unittest/modular_object_ability_connection_test/mock/include/element_name.h new file mode 100644 index 0000000000..123ce26fa2 --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/mock/include/element_name.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 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 MOCK_ELEMENT_NAME_H +#define MOCK_ELEMENT_NAME_H + +#include + +namespace OHOS { +namespace AppExecFwk { + +class ElementName { +public: + ElementName() = default; + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &abilityName) + : bundleName_(bundleName), abilityName_(abilityName) {} + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &moduleName, const std::string &abilityName) + : bundleName_(bundleName), moduleName_(moduleName), abilityName_(abilityName) {} + + std::string GetBundleName() const { return bundleName_; } + std::string GetModuleName() const { return moduleName_; } + std::string GetAbilityName() const { return abilityName_; } + void SetBundleName(const std::string &name) { bundleName_ = name; } + void SetModuleName(const std::string &name) { moduleName_ = name; } + void SetAbilityName(const std::string &name) { abilityName_ = name; } + +private: + std::string bundleName_; + std::string moduleName_; + std::string abilityName_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_ELEMENT_NAME_H diff --git a/test/unittest/modular_object_ability_connection_test/mock/include/modular_object_ability_connection.h b/test/unittest/modular_object_ability_connection_test/mock/include/modular_object_ability_connection.h new file mode 100644 index 0000000000..a97a85ffb7 --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/mock/include/modular_object_ability_connection.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_ABILITY_CONNECTION_H +#define MOCK_MODULAR_OBJECT_ABILITY_CONNECTION_H + +#include +#include "ability_connection.h" + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectAbilityConnection : public AbilityConnection { +public: + ModularObjectAbilityConnection() = default; + ~ModularObjectAbilityConnection() override = default; + + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + +private: + std::mutex modularMutex_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_ABILITY_CONNECTION_H diff --git a/test/unittest/modular_object_ability_connection_test/mock/include/modular_object_connection_manager.h b/test/unittest/modular_object_ability_connection_test/mock/include/modular_object_connection_manager.h new file mode 100644 index 0000000000..c3c18a94ff --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/mock/include/modular_object_connection_manager.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_CONNECTION_MANAGER_H +#define MOCK_MODULAR_OBJECT_CONNECTION_MANAGER_H + +#include "element_name.h" +#include "modular_object_ability_connection.h" +#include "refbase.h" + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectConnectionManager { +public: + static ModularObjectConnectionManager &GetInstance() + { + static ModularObjectConnectionManager instance; + return instance; + } + + bool DisconnectNonexistentService(const AppExecFwk::ElementName &element, + const sptr &connection) + { + return g_disconnectNonexistentResult; + } + + bool RemoveConnection(const sptr &connection) + { + g_removeConnectionCalled = true; + return true; + } + + static bool g_disconnectNonexistentResult; + static bool g_removeConnectionCalled; + + static void Reset() + { + g_disconnectNonexistentResult = false; + g_removeConnectionCalled = false; + } + +private: + ModularObjectConnectionManager() = default; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_CONNECTION_MANAGER_H diff --git a/test/unittest/modular_object_ability_connection_test/modular_object_ability_connection_test.cpp b/test/unittest/modular_object_ability_connection_test/modular_object_ability_connection_test.cpp new file mode 100644 index 0000000000..b4026cbcae --- /dev/null +++ b/test/unittest/modular_object_ability_connection_test/modular_object_ability_connection_test.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2026 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 "modular_object_ability_connection.h" +#include "modular_object_connection_manager.h" + +using namespace testing::ext; + +namespace OHOS { +namespace AbilityRuntime { + +bool ModularObjectConnectionManager::g_disconnectNonexistentResult = false; +bool ModularObjectConnectionManager::g_removeConnectionCalled = false; + +class MockConnectCallback : public AbilityConnectCallback { +public: + bool connectCalled = false; + bool disconnectCalled = false; + int lastResultCode = 0; + + void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) override + { + connectCalled = true; + lastResultCode = resultCode; + } + + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override + { + disconnectCalled = true; + lastResultCode = resultCode; + } +}; + +class ModularObjectAbilityConnectionTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override + { + ModularObjectConnectionManager::Reset(); + } + void TearDown() override {} +}; + +// ==================== OnAbilityConnectDone ==================== + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityConnectDone_EmptyCallbackList_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityConnectDone_EmptyCallbackList_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 0); + // Should return early without crash + EXPECT_EQ(conn->GetConnectionState(), CONNECTION_STATE_DISCONNECTED); + GTEST_LOG_(INFO) << "OnAbilityConnectDone_EmptyCallbackList_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityConnectDone_WithCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityConnectDone_WithCallback_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 0); + + EXPECT_TRUE(cb->connectCalled); + EXPECT_EQ(conn->GetConnectionState(), CONNECTION_STATE_CONNECTED); + GTEST_LOG_(INFO) << "OnAbilityConnectDone_WithCallback_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityConnectDone_SetsResultCode_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityConnectDone_SetsResultCode_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 42); + + EXPECT_EQ(cb->lastResultCode, 42); + EXPECT_EQ(conn->GetResultCode(), 42); + GTEST_LOG_(INFO) << "OnAbilityConnectDone_SetsResultCode_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityConnectDone_SetsRemoteObject_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityConnectDone_SetsRemoteObject_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 0); + + EXPECT_EQ(conn->GetRemoteObject(), remote); + GTEST_LOG_(INFO) << "OnAbilityConnectDone_SetsRemoteObject_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityConnectDone_DisconnectNonexistent_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityConnectDone_DisconnectNonexistent_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + ModularObjectConnectionManager::g_disconnectNonexistentResult = true; + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 0); + + // Should NOT call callback because DisconnectNonexistentService returns true + EXPECT_FALSE(cb->connectCalled); + GTEST_LOG_(INFO) << "OnAbilityConnectDone_DisconnectNonexistent_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityConnectDone_MultipleCallbacks_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityConnectDone_MultipleCallbacks_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb1 = sptr(new MockConnectCallback()); + auto cb2 = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb1); + conn->AddConnectCallback(cb2); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 0); + + EXPECT_TRUE(cb1->connectCalled); + EXPECT_TRUE(cb2->connectCalled); + GTEST_LOG_(INFO) << "OnAbilityConnectDone_MultipleCallbacks_001 end"; +} + +// ==================== OnAbilityDisconnectDone ==================== + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityDisconnectDone_EmptyCallbackList_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_EmptyCallbackList_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + conn->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(conn->GetConnectionState(), CONNECTION_STATE_DISCONNECTED); + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_EmptyCallbackList_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityDisconnectDone_WithCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_WithCallback_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + conn->OnAbilityDisconnectDone(element, 0); + + EXPECT_TRUE(cb->disconnectCalled); + EXPECT_EQ(conn->GetConnectionState(), CONNECTION_STATE_DISCONNECTED); + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_WithCallback_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityDisconnectDone_SetsDisconnectedState_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_SetsDisconnectedState_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + // First connect + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 0); + EXPECT_EQ(conn->GetConnectionState(), CONNECTION_STATE_CONNECTED); + + // Then disconnect + conn->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(conn->GetConnectionState(), CONNECTION_STATE_DISCONNECTED); + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_SetsDisconnectedState_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityDisconnectDone_DiedResultCode_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_DiedResultCode_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + conn->OnAbilityDisconnectDone(element, -1); // DIED + + // DIED (-1) triggers RemoveConnection and changes resultCode to 0 + EXPECT_TRUE(ModularObjectConnectionManager::g_removeConnectionCalled); + EXPECT_EQ(cb->lastResultCode, 0); // DIED + 1 = 0 + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_DiedResultCode_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityDisconnectDone_NormalResultCode_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_NormalResultCode_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + conn->OnAbilityDisconnectDone(element, 5); + + EXPECT_FALSE(ModularObjectConnectionManager::g_removeConnectionCalled); + EXPECT_EQ(cb->lastResultCode, 5); + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_NormalResultCode_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityDisconnectDone_ClearsRemoteObject_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_ClearsRemoteObject_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + sptr remote; + conn->OnAbilityConnectDone(element, remote, 0); + + conn->OnAbilityDisconnectDone(element, 0); + EXPECT_EQ(conn->GetRemoteObject(), nullptr); + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_ClearsRemoteObject_001 end"; +} + +HWTEST_F(ModularObjectAbilityConnectionTest, OnAbilityDisconnectDone_MultipleCallbacks_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_MultipleCallbacks_001 start"; + auto conn = sptr(new ModularObjectAbilityConnection()); + auto cb1 = sptr(new MockConnectCallback()); + auto cb2 = sptr(new MockConnectCallback()); + conn->AddConnectCallback(cb1); + conn->AddConnectCallback(cb2); + + AppExecFwk::ElementName element("device", "bundle", "module", "ability"); + conn->OnAbilityDisconnectDone(element, 0); + + EXPECT_TRUE(cb1->disconnectCalled); + EXPECT_TRUE(cb2->disconnectCalled); + GTEST_LOG_(INFO) << "OnAbilityDisconnectDone_MultipleCallbacks_001 end"; +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/test/unittest/modular_object_connection_manager_test/BUILD.gn b/test/unittest/modular_object_connection_manager_test/BUILD.gn new file mode 100644 index 0000000000..f45d2b251d --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("modular_object_connection_manager_test") { + module_out_path = "ability_runtime/ability_runtime/modular_object_connection_manager_test" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + sources = [ + "modular_object_connection_manager_test.cpp", + "${ability_runtime_path}/frameworks/c/ability_runtime/src/modular_object_connection_manager.cpp", + ] + include_dirs = [ + "mock/include", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_services_path}/common/include", + ] + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_connection_manager_test" ] +} diff --git a/test/unittest/modular_object_connection_manager_test/mock/include/ability_connect_callback.h b/test/unittest/modular_object_connection_manager_test/mock/include/ability_connect_callback.h new file mode 100644 index 0000000000..dce3efde7a --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/mock/include/ability_connect_callback.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_CONNECT_CALLBACK_H +#define MOCK_ABILITY_CONNECT_CALLBACK_H + +#include "element_name.h" +#include "refbase.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AbilityRuntime { + +class AbilityConnectCallback : public RefBase { +public: + AbilityConnectCallback() = default; + virtual ~AbilityConnectCallback() = default; + + virtual void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) = 0; + virtual void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) = 0; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_ABILITY_CONNECT_CALLBACK_H diff --git a/test/unittest/modular_object_connection_manager_test/mock/include/ability_connection.h b/test/unittest/modular_object_connection_manager_test/mock/include/ability_connection.h new file mode 100644 index 0000000000..83a9a11567 --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/mock/include/ability_connection.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_CONNECTION_H +#define MOCK_ABILITY_CONNECTION_H + +#include +#include +#include + +#include "ability_connect_callback.h" +#include "refbase.h" + +namespace OHOS { +namespace AbilityRuntime { + +enum { + CONNECTION_STATE_DISCONNECTED = -1, + CONNECTION_STATE_CONNECTED = 0, + CONNECTION_STATE_CONNECTING = 1 +}; + +class AbilityConnection : public RefBase { +public: + AbilityConnection() = default; + virtual ~AbilityConnection() = default; + + virtual void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) {} + + virtual void OnAbilityDisconnectDone( + const AppExecFwk::ElementName &element, int resultCode) {} + + void AddConnectCallback(const sptr &cb) + { + std::lock_guard lock(mutex_); + callbackList_.push_back(cb); + } + + void RemoveConnectCallback(const sptr &cb) + { + std::lock_guard lock(mutex_); + auto it = std::find(callbackList_.begin(), callbackList_.end(), cb); + if (it != callbackList_.end()) { + callbackList_.erase(it); + } + } + + void SetRemoteObject(const sptr &obj) { remoteObject_ = obj; } + void SetResultCode(int code) { resultCode_ = code; } + void SetConnectionState(int state) { connectionState_ = state; } + sptr GetRemoteObject() const { return remoteObject_; } + int GetResultCode() const { return resultCode_; } + int GetConnectionState() const { return connectionState_; } + std::vector> GetCallbackList() { return callbackList_; } + +private: + std::vector> callbackList_; + sptr remoteObject_; + int resultCode_ = -1; + int connectionState_ = CONNECTION_STATE_DISCONNECTED; + std::mutex mutex_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_ABILITY_CONNECTION_H diff --git a/test/unittest/modular_object_connection_manager_test/mock/include/ability_manager_client.h b/test/unittest/modular_object_connection_manager_test/mock/include/ability_manager_client.h new file mode 100644 index 0000000000..785cfc672e --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/mock/include/ability_manager_client.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_MANAGER_CLIENT_H +#define MOCK_ABILITY_MANAGER_CLIENT_H + +#include +#include "errors.h" +#include "refbase.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +enum ExtensionAbilityType { + MODULAR_OBJECT = 99, +}; +} // namespace AppExecFwk + +namespace AAFwk { +class Want; + +constexpr int32_t DEFAULT_INVAL_VALUE = -1; +constexpr int CONNECTION_NOT_EXIST = 2097162; + +class AbilityManagerClient { +public: + static std::shared_ptr GetInstance() + { + static auto instance = std::make_shared(); + return instance; + } + + template + ErrCode ConnectAbilityWithExtensionType(const AAFwk::Want &want, + const sptr &connect, const sptr &callerToken, + int32_t userId, int32_t extensionType) + { + g_connectCalled = true; + return g_connectResult; + } + + template + ErrCode DisconnectAbility(const sptr &connect) + { + g_disconnectCalled = true; + return g_disconnectResult; + } + + static bool g_connectCalled; + static bool g_disconnectCalled; + static ErrCode g_connectResult; + static ErrCode g_disconnectResult; + + static void Reset() + { + g_connectCalled = false; + g_disconnectCalled = false; + g_connectResult = ERR_OK; + g_disconnectResult = ERR_OK; + } +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_ABILITY_MANAGER_CLIENT_H diff --git a/test/unittest/modular_object_connection_manager_test/mock/include/element_name.h b/test/unittest/modular_object_connection_manager_test/mock/include/element_name.h new file mode 100644 index 0000000000..66649c9e38 --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/mock/include/element_name.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 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 MOCK_APP_EXEC_FWK_ELEMENT_NAME_H +#define MOCK_APP_EXEC_FWK_ELEMENT_NAME_H + +#include + +namespace OHOS { +namespace AppExecFwk { + +class ElementName { +public: + ElementName() = default; + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &abilityName) + : bundleName_(bundleName), abilityName_(abilityName) {} + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &moduleName, const std::string &abilityName) + : bundleName_(bundleName), moduleName_(moduleName), abilityName_(abilityName) {} + + std::string GetBundleName() const { return bundleName_; } + std::string GetModuleName() const { return moduleName_; } + std::string GetAbilityName() const { return abilityName_; } + void SetBundleName(const std::string &name) { bundleName_ = name; } + void SetModuleName(const std::string &name) { moduleName_ = name; } + void SetAbilityName(const std::string &name) { abilityName_ = name; } + +private: + std::string bundleName_; + std::string moduleName_; + std::string abilityName_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_APP_EXEC_FWK_ELEMENT_NAME_H diff --git a/test/unittest/modular_object_connection_manager_test/mock/include/operation.h b/test/unittest/modular_object_connection_manager_test/mock/include/operation.h new file mode 100644 index 0000000000..c0c321106c --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/mock/include/operation.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026 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 MOCK_AAFWK_OPERATION_H +#define MOCK_AAFWK_OPERATION_H + +#include + +namespace OHOS { +namespace AAFwk { + +class Operation { +public: + std::string GetBundleName() const { return bundleName_; } + std::string GetModuleName() const { return moduleName_; } + std::string GetAbilityName() const { return abilityName_; } + void SetBundleName(const std::string &name) { bundleName_ = name; } + void SetModuleName(const std::string &name) { moduleName_ = name; } + void SetAbilityName(const std::string &name) { abilityName_ = name; } + + bool operator<(const Operation &other) const + { + if (bundleName_ < other.bundleName_) return true; + if (bundleName_ > other.bundleName_) return false; + if (moduleName_ < other.moduleName_) return true; + if (moduleName_ > other.moduleName_) return false; + return abilityName_ < other.abilityName_; + } + +private: + std::string bundleName_; + std::string moduleName_; + std::string abilityName_; +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_AAFWK_OPERATION_H diff --git a/test/unittest/modular_object_connection_manager_test/mock/include/want.h b/test/unittest/modular_object_connection_manager_test/mock/include/want.h new file mode 100644 index 0000000000..799c3182fb --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/mock/include/want.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026 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 MOCK_AAFWK_WANT_H +#define MOCK_AAFWK_WANT_H + +#include "operation.h" + +namespace OHOS { +namespace AAFwk { + +class Want { +public: + Operation GetOperation() const { return operation_; } + void SetOperation(const Operation &operation) { operation_ = operation; } + +private: + Operation operation_; +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_AAFWK_WANT_H diff --git a/test/unittest/modular_object_connection_manager_test/modular_object_connection_manager_test.cpp b/test/unittest/modular_object_connection_manager_test/modular_object_connection_manager_test.cpp new file mode 100644 index 0000000000..cd7bc79fea --- /dev/null +++ b/test/unittest/modular_object_connection_manager_test/modular_object_connection_manager_test.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2026 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 "modular_object_connection_manager.h" +#include "modular_object_ability_connection.h" +#include "ability_manager_client.h" + +using namespace testing::ext; + +namespace OHOS { +namespace AAFwk { +bool AbilityManagerClient::g_connectCalled = false; +bool AbilityManagerClient::g_disconnectCalled = false; +ErrCode AbilityManagerClient::g_connectResult = ERR_OK; +ErrCode AbilityManagerClient::g_disconnectResult = ERR_OK; +} // namespace AAFwk + +namespace AbilityRuntime { + +// Provide stub implementations for virtual methods (avoid linking modular_object_ability_connection.cpp) +void ModularObjectAbilityConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) {} + +void ModularObjectAbilityConnection::OnAbilityDisconnectDone( + const AppExecFwk::ElementName &element, int resultCode) {} + +namespace { + +class MockConnectCallback : public AbilityConnectCallback { +public: + void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, int resultCode) override {} + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override {} +}; + +AAFwk::Want BuildWant(const std::string &bundle, const std::string &module, const std::string &ability) +{ + AAFwk::Want want; + AAFwk::Operation op; + op.SetBundleName(bundle); + op.SetModuleName(module); + op.SetAbilityName(ability); + want.SetOperation(op); + return want; +} + +} // namespace + +class ModularObjectConnectionManagerTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() override + { + AAFwk::AbilityManagerClient::Reset(); + // Clean up any leftover state by disconnecting + auto &mgr = ModularObjectConnectionManager::GetInstance(); + auto cb1 = sptr::MakeSptr(); + mgr.DisconnectModularObjectExtension(cb1); + } + void TearDown() override {} +}; + +// ==================== ConnectModularObjectExtension ==================== + +HWTEST_F(ModularObjectConnectionManagerTest, Connect_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Connect_001 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + auto ret = mgr.ConnectModularObjectExtension(AAFwk::Want(), nullptr); + EXPECT_EQ(ret, ERR_INVALID_VALUE); + GTEST_LOG_(INFO) << "Connect_001 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, Connect_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Connect_002 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::g_connectResult = -1; + auto callback = sptr::MakeSptr(); + auto ret = mgr.ConnectModularObjectExtension(BuildWant("b", "m", "a"), callback); + EXPECT_EQ(ret, -1); + AAFwk::AbilityManagerClient::g_connectResult = ERR_OK; + GTEST_LOG_(INFO) << "Connect_002 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, Connect_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Connect_003 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::Reset(); + auto callback = sptr::MakeSptr(); + auto ret = mgr.ConnectModularObjectExtension(BuildWant("b", "m", "a"), callback); + EXPECT_EQ(ret, ERR_OK); + EXPECT_TRUE(AAFwk::AbilityManagerClient::g_connectCalled); + // Clean up + mgr.DisconnectModularObjectExtension(callback); + GTEST_LOG_(INFO) << "Connect_003 end"; +} + +// ==================== DisconnectModularObjectExtension ==================== + +HWTEST_F(ModularObjectConnectionManagerTest, Disconnect_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Disconnect_001 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + auto ret = mgr.DisconnectModularObjectExtension(nullptr); + EXPECT_EQ(ret, ERR_INVALID_VALUE); + GTEST_LOG_(INFO) << "Disconnect_001 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, Disconnect_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Disconnect_002 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::Reset(); + auto callback = sptr::MakeSptr(); + auto ret = mgr.DisconnectModularObjectExtension(callback); + EXPECT_EQ(ret, AAFwk::CONNECTION_NOT_EXIST); + GTEST_LOG_(INFO) << "Disconnect_002 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, Disconnect_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Disconnect_003 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::Reset(); + auto callback = sptr::MakeSptr(); + // Connect first + auto ret = mgr.ConnectModularObjectExtension(BuildWant("b2", "m2", "a2"), callback); + EXPECT_EQ(ret, ERR_OK); + // Disconnect + AAFwk::AbilityManagerClient::Reset(); + ret = mgr.DisconnectModularObjectExtension(callback); + EXPECT_EQ(ret, ERR_OK); + EXPECT_TRUE(AAFwk::AbilityManagerClient::g_disconnectCalled); + GTEST_LOG_(INFO) << "Disconnect_003 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, Disconnect_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Disconnect_004 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::Reset(); + auto callback1 = sptr::MakeSptr(); + auto callback2 = sptr::MakeSptr(); + // Connect same want twice with different callbacks + auto ret = mgr.ConnectModularObjectExtension(BuildWant("b3", "m3", "a3"), callback1); + EXPECT_EQ(ret, ERR_OK); + ret = mgr.ConnectModularObjectExtension(BuildWant("b3", "m3", "a3"), callback2); + EXPECT_EQ(ret, ERR_OK); + // Disconnect first callback - record should remain + AAFwk::AbilityManagerClient::Reset(); + ret = mgr.DisconnectModularObjectExtension(callback1); + EXPECT_EQ(ret, ERR_OK); + EXPECT_TRUE(AAFwk::AbilityManagerClient::g_disconnectCalled); + // Clean up + mgr.DisconnectModularObjectExtension(callback2); + GTEST_LOG_(INFO) << "Disconnect_004 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, Disconnect_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Disconnect_005 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::g_disconnectResult = -2; + auto callback = sptr::MakeSptr(); + // Connect first + mgr.ConnectModularObjectExtension(BuildWant("b4", "m4", "a4"), callback); + // Disconnect should return error + auto ret = mgr.DisconnectModularObjectExtension(callback); + EXPECT_EQ(ret, -2); + AAFwk::AbilityManagerClient::g_disconnectResult = ERR_OK; + GTEST_LOG_(INFO) << "Disconnect_005 end"; +} + +// ==================== RemoveConnection ==================== + +HWTEST_F(ModularObjectConnectionManagerTest, RemoveConnection_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RemoveConnection_001 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + auto connection = sptr::MakeSptr(); + auto ret = mgr.RemoveConnection(connection); + EXPECT_FALSE(ret); + GTEST_LOG_(INFO) << "RemoveConnection_001 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, RemoveConnection_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RemoveConnection_002 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::Reset(); + auto callback = sptr::MakeSptr(); + // Connect first + auto ret = mgr.ConnectModularObjectExtension(BuildWant("b5", "m5", "a5"), callback); + EXPECT_EQ(ret, ERR_OK); + // RemoveConnection with wrong connection should return false + auto wrongConnection = sptr::MakeSptr(); + ret = mgr.RemoveConnection(wrongConnection); + EXPECT_FALSE(ret); + // Clean up + mgr.DisconnectModularObjectExtension(callback); + GTEST_LOG_(INFO) << "RemoveConnection_002 end"; +} + +// ==================== DisconnectNonexistentService ==================== + +HWTEST_F(ModularObjectConnectionManagerTest, DisconnectNonexistent_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DisconnectNonexistent_001 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::Reset(); + auto connection = sptr::MakeSptr(); + AppExecFwk::ElementName element("", "com.test.noexist", "Ability"); + // No records exist, should disconnect + auto ret = mgr.DisconnectNonexistentService(element, connection); + EXPECT_TRUE(ret); + EXPECT_TRUE(AAFwk::AbilityManagerClient::g_disconnectCalled); + GTEST_LOG_(INFO) << "DisconnectNonexistent_001 end"; +} + +HWTEST_F(ModularObjectConnectionManagerTest, DisconnectNonexistent_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DisconnectNonexistent_002 start"; + auto &mgr = ModularObjectConnectionManager::GetInstance(); + AAFwk::AbilityManagerClient::Reset(); + auto callback = sptr::MakeSptr(); + // Connect first + auto want = BuildWant("com.test.exist", "module", "Ability"); + auto ret = mgr.ConnectModularObjectExtension(want, callback); + EXPECT_EQ(ret, ERR_OK); + // Check with matching bundle name - should find it (not disconnect) + AppExecFwk::ElementName element("", "com.test.exist", "Ability"); + // We need the connection object used internally. RemoveConnection cleans up. + // Since DisconnectNonexistentService checks by connection pointer AND bundleName, + // passing a different connection won't match + auto otherConnection = sptr::MakeSptr(); + auto result = mgr.DisconnectNonexistentService(element, otherConnection); + EXPECT_TRUE(result); // not found -> disconnect + // Clean up + mgr.DisconnectModularObjectExtension(callback); + GTEST_LOG_(INFO) << "DisconnectNonexistent_002 end"; +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/test/unittest/modular_object_extension_ability_test/BUILD.gn b/test/unittest/modular_object_extension_ability_test/BUILD.gn new file mode 100644 index 0000000000..7a50f3d162 --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("modular_object_extension_ability_test") { + module_out_path = "ability_runtime/ability_runtime/modular_object_extension_ability_test" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + sources = [ + "modular_object_extension_ability_test.cpp", + "${ability_runtime_path}/frameworks/c/ability_runtime/src/modular_object_extension_ability.cpp", + ] + include_dirs = [ + "mock/include", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_services_path}/common/include", + ] + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_extension_ability_test" ] +} diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/ability_runtime_common.h b/test/unittest/modular_object_extension_ability_test/mock/include/ability_runtime_common.h new file mode 100644 index 0000000000..86d6d5473d --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/ability_runtime_common.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_RUNTIME_COMMON_H +#define MOCK_ABILITY_RUNTIME_COMMON_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ABILITY_RUNTIME_ERROR_CODE_NO_ERROR = 0, + ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED = 201, + ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID = 401, + ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED = 801, + ABILITY_RUNTIME_ERROR_CODE_NO_SUCH_ABILITY = 16000001, + ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE = 16000002, + ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST = 16000011, + ABILITY_RUNTIME_ERROR_CODE_INTERNAL = 16000050, + ABILITY_RUNTIME_ERROR_CODE_MODULAR_OBJECT_EXTENSION_DISABLED = 16000163, +} AbilityRuntime_ErrorCode; + +typedef struct AbilityRuntime_Context *AbilityRuntime_ContextHandle; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/extension_ability.h b/test/unittest/modular_object_extension_ability_test/mock/include/extension_ability.h new file mode 100644 index 0000000000..b01b655d6c --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/extension_ability.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_ABILITY_H +#define MOCK_EXTENSION_ABILITY_H + +#include "native_extension/extension_ability_impl.h" + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/extension_ability_info.h b/test/unittest/modular_object_extension_ability_test/mock/include/extension_ability_info.h new file mode 100644 index 0000000000..52a6e8606e --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/extension_ability_info.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_ABILITY_INFO_H +#define MOCK_EXTENSION_ABILITY_INFO_H + +#include + +namespace OHOS { +namespace AppExecFwk { +enum ExtensionAbilityType { + UNSPECIFIED = 0, + SERVICE = 1, + MODULAR_OBJECT = 99, +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/ipc_cparcel.h b/test/unittest/modular_object_extension_ability_test/mock/include/ipc_cparcel.h new file mode 100644 index 0000000000..2ad7928346 --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/ipc_cparcel.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 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 MOCK_IPC_CPARCEL_H +#define MOCK_IPC_CPARCEL_H + +struct OHIPCRemoteStub { + int dummy = 0; +}; + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_ability.h b/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_ability.h new file mode 100644 index 0000000000..08fb7d161e --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_ability.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H +#define MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H + +#include "ability_runtime_common.h" +#include "extension_ability.h" +#include "ipc_cparcel.h" +#include "modular_object_extension_context.h" +#include "want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OH_AbilityRuntime_ModularObjectExtensionInstance OH_AbilityRuntime_ModObjExtensionInstance; +typedef OH_AbilityRuntime_ModObjExtensionInstance *OH_AbilityRuntime_ModObjExtensionInstanceHandle; + +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, AbilityBase_Want *want); +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance); +typedef OHIPCRemoteStub *(*OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, AbilityBase_Want *want); +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance); + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDestroyFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnConnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDisconnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionContextHandle *context); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase( + AbilityRuntime_ExtensionInstanceHandle baseExtensionInstance, + OH_AbilityRuntime_ModObjExtensionInstanceHandle *modObjExtensionInstance); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_context.h b/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_context.h new file mode 100644 index 0000000000..742bdddc38 --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_context.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_H +#define MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_H + +#include "ability_runtime_common.h" + +struct OH_AbilityRuntime_ModularObjectExtensionContext; + +typedef struct OH_AbilityRuntime_ModularObjectExtensionContext *OH_AbilityRuntime_ModObjExtensionContextHandle; + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_types.h b/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_types.h new file mode 100644 index 0000000000..2dd74711fb --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/modular_object_extension_types.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H +#define MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H + +#include +#include "extension_ability_info.h" +#include "modular_object_extension_ability.h" +#include "native_extension/context_impl.h" +#include "native_extension/extension_ability_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct OH_AbilityRuntime_ModularObjectExtensionContext : public AbilityRuntime_Context {}; + +struct OH_AbilityRuntime_ModularObjectExtensionInstance : public AbilityRuntime_ExtensionInstance { + std::shared_ptr context; + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc = nullptr; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/native_extension/context_impl.h b/test/unittest/modular_object_extension_ability_test/mock/include/native_extension/context_impl.h new file mode 100644 index 0000000000..60ce60b605 --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/native_extension/context_impl.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 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 MOCK_NATIVE_CONTEXT_IMPL_H +#define MOCK_NATIVE_CONTEXT_IMPL_H + +#include +#include "extension_ability_info.h" + +namespace OHOS { +namespace AbilityRuntime { +class Context {}; +} // namespace AbilityRuntime +} // namespace OHOS + +struct AbilityRuntime_Context { + OHOS::AppExecFwk::ExtensionAbilityType type; + std::weak_ptr context; +}; + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/native_extension/extension_ability_impl.h b/test/unittest/modular_object_extension_ability_test/mock/include/native_extension/extension_ability_impl.h new file mode 100644 index 0000000000..3aa65d802f --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/native_extension/extension_ability_impl.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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 MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H +#define MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H + +#include +#include "extension_ability_info.h" + +namespace OHOS { +namespace AbilityRuntime { +class Extension {}; +} // namespace AbilityRuntime +} // namespace OHOS + +#ifdef __cplusplus +extern "C" { +#endif + +struct AbilityRuntime_ExtensionInstance { + OHOS::AppExecFwk::ExtensionAbilityType type; + std::weak_ptr extension; +}; + +typedef struct AbilityRuntime_ExtensionInstance *AbilityRuntime_ExtensionInstanceHandle; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/mock/include/want.h b/test/unittest/modular_object_extension_ability_test/mock/include/want.h new file mode 100644 index 0000000000..0fc20bd5b2 --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/mock/include/want.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2026 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 MOCK_C_WANT_H +#define MOCK_C_WANT_H + +typedef struct AbilityBase_Element { + char *bundleName; + char *moduleName; + char *abilityName; +} AbilityBase_Element; + +typedef struct AbilityBase_Want AbilityBase_Want; + +#endif diff --git a/test/unittest/modular_object_extension_ability_test/modular_object_extension_ability_test.cpp b/test/unittest/modular_object_extension_ability_test/modular_object_extension_ability_test.cpp new file mode 100644 index 0000000000..420b942f84 --- /dev/null +++ b/test/unittest/modular_object_extension_ability_test/modular_object_extension_ability_test.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_ability.h" +#include "modular_object_extension_types.h" + +using namespace testing::ext; + +namespace { + +static void MockOnCreateFunc(OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, AbilityBase_Want *want) {} +static void MockOnDestroyFunc(OH_AbilityRuntime_ModObjExtensionInstanceHandle instance) {} +static OHIPCRemoteStub *MockOnConnectFunc(OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + AbilityBase_Want *want) { return nullptr; } +static void MockOnDisconnectFunc(OH_AbilityRuntime_ModObjExtensionInstanceHandle instance) {} + +OH_AbilityRuntime_ModObjExtensionInstanceHandle CreateValidInstance() +{ + auto *inst = new OH_AbilityRuntime_ModularObjectExtensionInstance(); + inst->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + inst->context = std::make_shared(); + return inst; +} + +void DestroyInstance(OH_AbilityRuntime_ModObjExtensionInstanceHandle inst) +{ + delete reinterpret_cast(inst); +} + +} // namespace + +class ModularObjectExtensionAbilityTest : public testing::Test { +public: + void SetUp() override {} + void TearDown() override {} +}; + +// ==================== RegisterOnCreateFunc ==================== + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnCreateFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_001 start"; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc(nullptr, MockOnCreateFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnCreateFunc_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_002 start"; + auto *inst = CreateValidInstance(); + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc(inst, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_002 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnCreateFunc_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_003 start"; + auto *inst = CreateValidInstance(); + inst->type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc(inst, MockOnCreateFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_003 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnCreateFunc_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_004 start"; + auto *inst = CreateValidInstance(); + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc(inst, MockOnCreateFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_NE(inst->onCreateFunc, nullptr); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "RegisterOnCreateFunc_004 end"; +} + +// ==================== RegisterOnDestroyFunc ==================== + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnDestroyFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnDestroyFunc_001 start"; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDestroyFunc(nullptr, MockOnDestroyFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "RegisterOnDestroyFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnDestroyFunc_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnDestroyFunc_002 start"; + auto *inst = CreateValidInstance(); + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDestroyFunc(inst, MockOnDestroyFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_NE(inst->onDestroyFunc, nullptr); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "RegisterOnDestroyFunc_002 end"; +} + +// ==================== RegisterOnConnectFunc ==================== + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnConnectFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnConnectFunc_001 start"; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnConnectFunc(nullptr, MockOnConnectFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "RegisterOnConnectFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnConnectFunc_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnConnectFunc_002 start"; + auto *inst = CreateValidInstance(); + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnConnectFunc(inst, MockOnConnectFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_NE(inst->onConnectFunc, nullptr); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "RegisterOnConnectFunc_002 end"; +} + +// ==================== RegisterOnDisconnectFunc ==================== + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnDisconnectFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnDisconnectFunc_001 start"; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDisconnectFunc(nullptr, MockOnDisconnectFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "RegisterOnDisconnectFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, RegisterOnDisconnectFunc_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "RegisterOnDisconnectFunc_002 start"; + auto *inst = CreateValidInstance(); + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDisconnectFunc(inst, MockOnDisconnectFunc); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_NE(inst->onDisconnectFunc, nullptr); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "RegisterOnDisconnectFunc_002 end"; +} + +// ==================== GetContextFromInstance ==================== + +HWTEST_F(ModularObjectExtensionAbilityTest, GetContextFromInstance_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetContextFromInstance_001 start"; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance(nullptr, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetContextFromInstance_001 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetContextFromInstance_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetContextFromInstance_002 start"; + OH_AbilityRuntime_ModObjExtensionContextHandle ctx = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance(nullptr, &ctx); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetContextFromInstance_002 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetContextFromInstance_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetContextFromInstance_003 start"; + auto *inst = CreateValidInstance(); + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance(inst, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "GetContextFromInstance_003 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetContextFromInstance_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetContextFromInstance_004 start"; + auto *inst = CreateValidInstance(); + inst->type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + OH_AbilityRuntime_ModObjExtensionContextHandle ctx = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance(inst, &ctx); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "GetContextFromInstance_004 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetContextFromInstance_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetContextFromInstance_005 start"; + auto *inst = CreateValidInstance(); + inst->context = nullptr; + OH_AbilityRuntime_ModObjExtensionContextHandle ctx = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance(inst, &ctx); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "GetContextFromInstance_005 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetContextFromInstance_006, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetContextFromInstance_006 start"; + auto *inst = CreateValidInstance(); + OH_AbilityRuntime_ModObjExtensionContextHandle ctx = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetContextFromInstance(inst, &ctx); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_NE(ctx, nullptr); + DestroyInstance(inst); + GTEST_LOG_(INFO) << "GetContextFromInstance_006 end"; +} + +// ==================== GetInstanceFromBase ==================== + +HWTEST_F(ModularObjectExtensionAbilityTest, GetInstanceFromBase_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetInstanceFromBase_001 start"; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase(nullptr, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetInstanceFromBase_001 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetInstanceFromBase_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetInstanceFromBase_002 start"; + OH_AbilityRuntime_ModObjExtensionInstanceHandle out = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase(nullptr, &out); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetInstanceFromBase_002 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetInstanceFromBase_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetInstanceFromBase_003 start"; + AbilityRuntime_ExtensionInstance base; + base.type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase(&base, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetInstanceFromBase_003 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetInstanceFromBase_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetInstanceFromBase_004 start"; + AbilityRuntime_ExtensionInstance base; + base.type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + OH_AbilityRuntime_ModObjExtensionInstanceHandle out = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase(&base, &out); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE); + GTEST_LOG_(INFO) << "GetInstanceFromBase_004 end"; +} + +HWTEST_F(ModularObjectExtensionAbilityTest, GetInstanceFromBase_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetInstanceFromBase_005 start"; + AbilityRuntime_ExtensionInstance base; + base.type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + OH_AbilityRuntime_ModObjExtensionInstanceHandle out = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionAbility_GetInstanceFromBase(&base, &out); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_NE(out, nullptr); + GTEST_LOG_(INFO) << "GetInstanceFromBase_005 end"; +} diff --git a/test/unittest/modular_object_extension_context_capi_test/BUILD.gn b/test/unittest/modular_object_extension_context_capi_test/BUILD.gn new file mode 100644 index 0000000000..b3af3c700e --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("modular_object_extension_context_capi_test") { + module_out_path = "ability_runtime/ability_runtime/modular_object_extension_context_capi_test" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + sources = [ + "modular_object_extension_context_capi_test.cpp", + "${ability_runtime_path}/frameworks/c/ability_runtime/src/modular_object_extension_context.cpp", + ] + include_dirs = [ + "mock/include", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_services_path}/common/include", + ] + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_extension_context_capi_test" ] +} diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_base_error.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_base_error.h new file mode 100644 index 0000000000..73b7281b83 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_base_error.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_BASE_ERROR_H +#define MOCK_ABILITY_BASE_ERROR_H + +constexpr int ABILITY_BASE_ERROR_CODE_NO_ERROR = 0; +constexpr int ABILITY_BASE_ERROR_CODE_PARAM_INVALID = 1; + +#endif // MOCK_ABILITY_BASE_ERROR_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_business_error_utils.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_business_error_utils.h new file mode 100644 index 0000000000..3448e511b4 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_business_error_utils.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_BUSINESS_ERROR_UTILS_H +#define MOCK_ABILITY_BUSINESS_ERROR_UTILS_H + +#include "ability_runtime_common.h" +#include + +inline AbilityRuntime_ErrorCode ConvertToCommonBusinessErrorCode(int32_t err) +{ + if (err == 0) { + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; + } + return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; +} + +inline AbilityRuntime_ErrorCode ConvertToAPI17BusinessErrorCode(int32_t err) +{ + if (err == 0) { + return ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; + } + return ABILITY_RUNTIME_ERROR_CODE_INTERNAL; +} + +#endif // MOCK_ABILITY_BUSINESS_ERROR_UTILS_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_manager_client.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_manager_client.h new file mode 100644 index 0000000000..84b78cbc51 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_manager_client.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_MANAGER_CLIENT_H +#define MOCK_ABILITY_MANAGER_CLIENT_H + +#endif // MOCK_ABILITY_MANAGER_CLIENT_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_runtime_common.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_runtime_common.h new file mode 100644 index 0000000000..ecb5b2c3e1 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/ability_runtime_common.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_RUNTIME_COMMON_H +#define MOCK_ABILITY_RUNTIME_COMMON_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ABILITY_RUNTIME_ERROR_CODE_NO_ERROR = 0, + ABILITY_RUNTIME_ERROR_CODE_PERMISSION_DENIED = 201, + ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID = 401, + ABILITY_RUNTIME_ERROR_CODE_NOT_SUPPORTED = 801, + ABILITY_RUNTIME_ERROR_CODE_NO_SUCH_ABILITY = 16000001, + ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE = 16000002, + ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST = 16000011, + ABILITY_RUNTIME_ERROR_CODE_INTERNAL = 16000050, + ABILITY_RUNTIME_ERROR_CODE_MODULAR_OBJECT_EXTENSION_DISABLED = 16000163, +} AbilityRuntime_ErrorCode; + +typedef struct AbilityRuntime_Context *AbilityRuntime_ContextHandle; + +#ifdef __cplusplus +} +#endif + +#endif // MOCK_ABILITY_RUNTIME_COMMON_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/errors.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/errors.h new file mode 100644 index 0000000000..f13d5aea02 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/errors.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 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 MOCK_ERRORS_H +#define MOCK_ERRORS_H + +#include + +using ErrCode = int32_t; +constexpr ErrCode ERR_OK = 0; + +#endif // MOCK_ERRORS_H \ No newline at end of file diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability.h new file mode 100644 index 0000000000..38d9edd8e0 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_ABILITY_H +#define MOCK_EXTENSION_ABILITY_H + +#include "native_extension/extension_ability_impl.h" + +#endif // MOCK_EXTENSION_ABILITY_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability_info.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability_info.h new file mode 100644 index 0000000000..e6fd9b8918 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/extension_ability_info.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_ABILITY_INFO_H +#define MOCK_EXTENSION_ABILITY_INFO_H + +namespace OHOS { +namespace AppExecFwk { +enum ExtensionAbilityType { + UNSPECIFIED = 0, + SERVICE = 1, + MODULAR_OBJECT = 99, +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_EXTENSION_ABILITY_INFO_H \ No newline at end of file diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/ipc_cparcel.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/ipc_cparcel.h new file mode 100644 index 0000000000..f2220d18c0 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/ipc_cparcel.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 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 MOCK_IPC_CPARCEL_H +#define MOCK_IPC_CPARCEL_H + +struct OHIPCRemoteStub { + int dummy; +}; + +#endif // MOCK_IPC_CPARCEL_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/mock_types.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/mock_types.h new file mode 100644 index 0000000000..7e2fc0f38e --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/mock_types.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2026 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 MOCK_TYPES_H +#define MOCK_TYPES_H + +namespace OHOS { +namespace AAFwk { +class Want {}; +class StartOptions {}; +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_TYPES_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_ability.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_ability.h new file mode 100644 index 0000000000..9321aac65d --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_ability.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H +#define MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H + +#include "ability_runtime_common.h" + +struct AbilityBase_Want; + +typedef struct OH_AbilityRuntime_ModularObjectExtensionInstance *OH_AbilityRuntime_ModObjExtensionInstanceHandle; + +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, struct AbilityBase_Want *); +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle); +typedef struct OHIPCRemoteStub *(*OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, struct AbilityBase_Want *); +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle); + +#ifdef __cplusplus +extern "C" { +#endif + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDestroyFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnConnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDisconnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle instance, + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc); + +#ifdef __cplusplus +} +#endif + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context.h new file mode 100644 index 0000000000..97bfcd5aac --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_H +#define MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_H + +#include "ability_runtime_common.h" + +struct AbilityBase_Want; +typedef struct AbilityBase_Want AbilityBase_Want; +struct AbilityRuntime_StartOptions; +typedef struct AbilityRuntime_StartOptions AbilityRuntime_StartOptions; + +typedef struct OH_AbilityRuntime_ModularObjectExtensionContext *OH_AbilityRuntime_ModObjExtensionContextHandle; + +#ifdef __cplusplus +extern "C" { +#endif + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_GetBaseContext( + OH_AbilityRuntime_ModObjExtensionContextHandle modObjExtensionContext, AbilityRuntime_ContextHandle* baseContext); + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility( + OH_AbilityRuntime_ModObjExtensionContextHandle context, const AbilityBase_Want *want); + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions( + OH_AbilityRuntime_ModObjExtensionContextHandle context, const AbilityBase_Want *want, + const AbilityRuntime_StartOptions *options); + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf( + OH_AbilityRuntime_ModObjExtensionContextHandle context); + +#ifdef __cplusplus +} +#endif + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context_impl.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context_impl.h new file mode 100644 index 0000000000..e7afb09e60 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_context_impl.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H +#define MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H + +#include "native_extension/context_impl.h" +#include "errors.h" +#include "mock_types.h" + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectExtensionContext : public Context { +public: + static ErrCode g_startSelfResult; + static ErrCode g_startSelfWithOptionsResult; + static ErrCode g_terminateResult; + + ErrCode StartSelfUIAbility(const AAFwk::Want &want) const { return g_startSelfResult; } + ErrCode StartSelfUIAbilityWithStartOptions(const AAFwk::Want &want, + const AAFwk::StartOptions &options) const { return g_startSelfWithOptionsResult; } + ErrCode TerminateSelf() { return g_terminateResult; } +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_types.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_types.h new file mode 100644 index 0000000000..91f69b7be7 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/modular_object_extension_types.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H +#define MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H + +#include +#include "extension_ability_info.h" +#include "modular_object_extension_ability.h" +#include "native_extension/context_impl.h" +#include "native_extension/extension_ability_impl.h" + +struct OH_AbilityRuntime_ModularObjectExtensionContext : public AbilityRuntime_Context {}; + +struct OH_AbilityRuntime_ModularObjectExtensionInstance : public AbilityRuntime_ExtensionInstance { + std::shared_ptr context; + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc = nullptr; +}; + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H \ No newline at end of file diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/context_impl.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/context_impl.h new file mode 100644 index 0000000000..66d8e6c47a --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/context_impl.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 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 MOCK_NATIVE_CONTEXT_IMPL_H +#define MOCK_NATIVE_CONTEXT_IMPL_H + +#include +#include "extension_ability_info.h" + +namespace OHOS { +namespace AbilityRuntime { +class Context {}; +} // namespace AbilityRuntime +} // namespace OHOS + +struct AbilityRuntime_Context { + OHOS::AppExecFwk::ExtensionAbilityType type; + std::weak_ptr context; +}; + +#endif // MOCK_NATIVE_CONTEXT_IMPL_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/extension_ability_impl.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/extension_ability_impl.h new file mode 100644 index 0000000000..7a696a75e5 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/native_extension/extension_ability_impl.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 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 MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H +#define MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H + +#include +#include "extension_ability_info.h" + +namespace OHOS { +namespace AbilityRuntime { +class Extension {}; +} // namespace AbilityRuntime +} // namespace OHOS + +struct AbilityRuntime_ExtensionInstance { + OHOS::AppExecFwk::ExtensionAbilityType type; + std::weak_ptr extension; +}; + +typedef struct AbilityRuntime_ExtensionInstance *AbilityRuntime_ExtensionInstanceHandle; + +#endif // MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/start_options_impl.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/start_options_impl.h new file mode 100644 index 0000000000..6200de49db --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/start_options_impl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2026 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 MOCK_START_OPTIONS_IMPL_H +#define MOCK_START_OPTIONS_IMPL_H + +#include "mock_types.h" + +struct AbilityRuntime_StartOptions { + OHOS::AAFwk::StartOptions GetInnerStartOptions() { return OHOS::AAFwk::StartOptions(); } +}; + +#endif // MOCK_START_OPTIONS_IMPL_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/want.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/want.h new file mode 100644 index 0000000000..30a75fd161 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/want.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2026 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 MOCK_WANT_H +#define MOCK_WANT_H + +typedef struct AbilityBase_Element { + char *bundleName; + char *moduleName; + char *abilityName; +} AbilityBase_Element; + +typedef struct AbilityBase_Want AbilityBase_Want; + +#endif // MOCK_WANT_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/want_manager.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/want_manager.h new file mode 100644 index 0000000000..cb837641a4 --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/want_manager.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026 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 MOCK_WANT_MANAGER_H +#define MOCK_WANT_MANAGER_H + +#include "want.h" +#include "ability_base_error.h" +#include "mock_types.h" +#include +#include + +struct AbilityBase_Want { + AbilityBase_Element element; + std::map params; + int flag = 0; +}; + +namespace OHOS { +namespace AAFwk { +class CWantManager { +public: + static int TransformToWant(const AbilityBase_Want &cWant, bool flag, Want &abilityWant) + { + return g_transformResult; + } + + static int TransformToCWantWithoutElement(const Want &want, bool flag, AbilityBase_Want &cWant) + { + return g_transformResult; + } + + static int g_transformResult; +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_WANT_MANAGER_H diff --git a/test/unittest/modular_object_extension_context_capi_test/mock/include/want_utils.h b/test/unittest/modular_object_extension_context_capi_test/mock/include/want_utils.h new file mode 100644 index 0000000000..4ab73a8aac --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/mock/include/want_utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2026 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 MOCK_WANT_UTILS_H +#define MOCK_WANT_UTILS_H + +#include "ability_runtime_common.h" + +struct AbilityBase_Want; + +extern AbilityRuntime_ErrorCode g_checkWantResult; + +AbilityRuntime_ErrorCode CheckWant(AbilityBase_Want *want); + +#endif // MOCK_WANT_UTILS_H diff --git a/test/unittest/modular_object_extension_context_capi_test/modular_object_extension_context_capi_test.cpp b/test/unittest/modular_object_extension_context_capi_test/modular_object_extension_context_capi_test.cpp new file mode 100644 index 0000000000..6d686834ab --- /dev/null +++ b/test/unittest/modular_object_extension_context_capi_test/modular_object_extension_context_capi_test.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_context.h" +#include "modular_object_extension_types.h" +#include "modular_object_extension_context_impl.h" +#include "want_manager.h" +#include "want_utils.h" +#include "start_options_impl.h" + +using namespace testing::ext; + +namespace OHOS { +namespace AbilityRuntime { + +ErrCode ModularObjectExtensionContext::g_startSelfResult = ERR_OK; +ErrCode ModularObjectExtensionContext::g_startSelfWithOptionsResult = ERR_OK; +ErrCode ModularObjectExtensionContext::g_terminateResult = ERR_OK; + +} // namespace AbilityRuntime +} // namespace OHOS + +int OHOS::AAFwk::CWantManager::g_transformResult = 0; +AbilityRuntime_ErrorCode g_checkWantResult = ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; + +AbilityRuntime_ErrorCode CheckWant(AbilityBase_Want *want) +{ + return g_checkWantResult; +} + +class ModularObjectExtensionContextCapiTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override + { + OHOS::AbilityRuntime::ModularObjectExtensionContext::g_startSelfResult = ERR_OK; + OHOS::AbilityRuntime::ModularObjectExtensionContext::g_startSelfWithOptionsResult = ERR_OK; + OHOS::AbilityRuntime::ModularObjectExtensionContext::g_terminateResult = ERR_OK; + OHOS::AAFwk::CWantManager::g_transformResult = 0; + g_checkWantResult = ABILITY_RUNTIME_ERROR_CODE_NO_ERROR; + } + void TearDown() override {} +}; + +// ==================== GetBaseContext ==================== + +HWTEST_F(ModularObjectExtensionContextCapiTest, GetBaseContext_NullContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetBaseContext_NullContext_001 start"; + AbilityRuntime_ContextHandle baseContext = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_GetBaseContext(nullptr, &baseContext); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetBaseContext_NullContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, GetBaseContext_NullBaseContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetBaseContext_NullBaseContext_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_GetBaseContext(ctx.get(), nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetBaseContext_NullBaseContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, GetBaseContext_WrongType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetBaseContext_WrongType_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + AbilityRuntime_ContextHandle baseContext = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_GetBaseContext(ctx.get(), &baseContext); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE); + GTEST_LOG_(INFO) << "GetBaseContext_WrongType_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, GetBaseContext_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetBaseContext_Success_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + AbilityRuntime_ContextHandle baseContext = nullptr; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_GetBaseContext(ctx.get(), &baseContext); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + EXPECT_NE(baseContext, nullptr); + GTEST_LOG_(INFO) << "GetBaseContext_Success_001 end"; +} + +// ==================== StartSelfUIAbility ==================== + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfUIAbility_NullContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_NullContext_001 start"; + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility(nullptr, &want); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "StartSelfUIAbility_NullContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfUIAbility_WrongType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_WrongType_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility(ctx.get(), &want); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE); + GTEST_LOG_(INFO) << "StartSelfUIAbility_WrongType_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfUIAbility_ExpiredContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_ExpiredContext_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + // context is default-constructed weak_ptr, lock() returns nullptr + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility(ctx.get(), &want); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST); + GTEST_LOG_(INFO) << "StartSelfUIAbility_ExpiredContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfUIAbility_InvalidWant_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_InvalidWant_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + g_checkWantResult = ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID; + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility(ctx.get(), &want); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "StartSelfUIAbility_InvalidWant_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfUIAbility_TransformFail_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_TransformFail_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + OHOS::AAFwk::CWantManager::g_transformResult = 1; // non-zero = failure + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility(ctx.get(), &want); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "StartSelfUIAbility_TransformFail_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfUIAbility_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_Success_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility(ctx.get(), &want); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + GTEST_LOG_(INFO) << "StartSelfUIAbility_Success_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfUIAbility_StartError_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_StartError_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + OHOS::AbilityRuntime::ModularObjectExtensionContext::g_startSelfResult = -1; + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbility(ctx.get(), &want); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INTERNAL); + GTEST_LOG_(INFO) << "StartSelfUIAbility_StartError_001 end"; +} + +// ==================== StartSelfUIAbilityWithStartOptions ==================== + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfWithOpts_NullOptions_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfWithOpts_NullOptions_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + AbilityBase_Want want; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions(ctx.get(), &want, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "StartSelfWithOpts_NullOptions_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfWithOpts_NullContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfWithOpts_NullContext_001 start"; + AbilityBase_Want want; + AbilityRuntime_StartOptions options; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions(nullptr, &want, &options); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "StartSelfWithOpts_NullContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfWithOpts_WrongType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfWithOpts_WrongType_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + AbilityBase_Want want; + AbilityRuntime_StartOptions options; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions(ctx.get(), &want, &options); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE); + GTEST_LOG_(INFO) << "StartSelfWithOpts_WrongType_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfWithOpts_ExpiredContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfWithOpts_ExpiredContext_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + AbilityBase_Want want; + AbilityRuntime_StartOptions options; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions(ctx.get(), &want, &options); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST); + GTEST_LOG_(INFO) << "StartSelfWithOpts_ExpiredContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfWithOpts_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfWithOpts_Success_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + AbilityBase_Want want; + AbilityRuntime_StartOptions options; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions(ctx.get(), &want, &options); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + GTEST_LOG_(INFO) << "StartSelfWithOpts_Success_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, StartSelfWithOpts_TransformFail_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfWithOpts_TransformFail_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + OHOS::AAFwk::CWantManager::g_transformResult = 1; + AbilityBase_Want want; + AbilityRuntime_StartOptions options; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_StartSelfUIAbilityWithStartOptions(ctx.get(), &want, &options); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "StartSelfWithOpts_TransformFail_001 end"; +} + +// ==================== TerminateSelf ==================== + +HWTEST_F(ModularObjectExtensionContextCapiTest, TerminateSelf_NullContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_NullContext_001 start"; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf(nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "TerminateSelf_NullContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, TerminateSelf_WrongType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_WrongType_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::SERVICE; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf(ctx.get()); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE); + GTEST_LOG_(INFO) << "TerminateSelf_WrongType_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, TerminateSelf_ExpiredContext_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_ExpiredContext_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf(ctx.get()); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST); + GTEST_LOG_(INFO) << "TerminateSelf_ExpiredContext_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, TerminateSelf_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_Success_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf(ctx.get()); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + GTEST_LOG_(INFO) << "TerminateSelf_Success_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextCapiTest, TerminateSelf_Error_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_Error_001 start"; + auto ctx = std::make_shared(); + ctx->type = OHOS::AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT; + auto cppCtx = std::make_shared(); + ctx->context = cppCtx; + OHOS::AbilityRuntime::ModularObjectExtensionContext::g_terminateResult = -1; + auto ret = OH_AbilityRuntime_ModObjExtensionContext_TerminateSelf(ctx.get()); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_INTERNAL); + GTEST_LOG_(INFO) << "TerminateSelf_Error_001 end"; +} diff --git a/test/unittest/modular_object_extension_context_impl_test/BUILD.gn b/test/unittest/modular_object_extension_context_impl_test/BUILD.gn new file mode 100644 index 0000000000..f51941a07b --- /dev/null +++ b/test/unittest/modular_object_extension_context_impl_test/BUILD.gn @@ -0,0 +1,43 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("modular_object_extension_context_impl_test") { + module_out_path = "ability_runtime/ability_runtime/modular_object_extension_context_impl_test" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + sources = [ + "modular_object_extension_context_impl_test.cpp", + ] + include_dirs = [ + "mock/include", + ] + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_extension_context_impl_test" ] +} diff --git a/test/unittest/modular_object_extension_context_impl_test/mock/include/errors.h b/test/unittest/modular_object_extension_context_impl_test/mock/include/errors.h new file mode 100644 index 0000000000..e8e1ec698d --- /dev/null +++ b/test/unittest/modular_object_extension_context_impl_test/mock/include/errors.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 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 MOCK_ERRORS_H +#define MOCK_ERRORS_H + +#include +using ErrCode = int32_t; +constexpr ErrCode ERR_OK = 0; + +#endif // MOCK_ERRORS_H diff --git a/test/unittest/modular_object_extension_context_impl_test/mock/include/extension_context.h b/test/unittest/modular_object_extension_context_impl_test/mock/include/extension_context.h new file mode 100644 index 0000000000..3ec47f0f80 --- /dev/null +++ b/test/unittest/modular_object_extension_context_impl_test/mock/include/extension_context.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_CONTEXT_H +#define MOCK_EXTENSION_CONTEXT_H + +#include +#include "iremote_broker.h" +#include "refbase.h" +#include "iremote_object.h" +#include "errors.h" + +namespace OHOS { +namespace AbilityRuntime { + +class Context : public std::enable_shared_from_this { +public: + Context() = default; + virtual ~Context() = default; +}; + +} // namespace AbilityRuntime + +namespace AAFwk { +class Want {}; + +class StartOptions {}; + +class AbilityManagerClient { +public: + static std::shared_ptr GetInstance() + { + static auto instance = std::make_shared(); + return instance; + } + + ErrCode StartSelfUIAbility(const Want &want) + { + return g_startSelfUIAbilityResult; + } + + ErrCode StartSelfUIAbilityWithStartOptions(const Want &want, const StartOptions &options) + { + return g_startSelfUIAbilityWithStartOptionsResult; + } + + ErrCode TerminateAbility(const sptr &token, int32_t resultCode, const Want *resultWant) + { + g_terminateCalled = true; + g_lastToken = token.GetRefPtr(); + return g_terminateResult; + } + + static ErrCode g_startSelfUIAbilityResult; + static ErrCode g_startSelfUIAbilityWithStartOptionsResult; + static ErrCode g_terminateResult; + static bool g_terminateCalled; + static IRemoteObject *g_lastToken; + + static void Reset() + { + g_startSelfUIAbilityResult = ERR_OK; + g_startSelfUIAbilityWithStartOptionsResult = ERR_OK; + g_terminateResult = ERR_OK; + g_terminateCalled = false; + g_lastToken = nullptr; + } +}; + +} // namespace AAFwk + +namespace AbilityRuntime { + +class ExtensionContext : public Context { +public: + sptr token_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_EXTENSION_CONTEXT_H diff --git a/test/unittest/modular_object_extension_context_impl_test/mock/include/hitrace_meter.h b/test/unittest/modular_object_extension_context_impl_test/mock/include/hitrace_meter.h new file mode 100644 index 0000000000..0a3347899b --- /dev/null +++ b/test/unittest/modular_object_extension_context_impl_test/mock/include/hitrace_meter.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 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 MOCK_HITRACE_METER_H +#define MOCK_HITRACE_METER_H + +#define HITRACE_METER_NAME(tag, name) +#define HITRACE_TAG_ABILITY_MANAGER 0 + +#endif // MOCK_HITRACE_METER_H diff --git a/test/unittest/modular_object_extension_context_impl_test/mock/include/modular_object_extension_context_impl.h b/test/unittest/modular_object_extension_context_impl_test/mock/include/modular_object_extension_context_impl.h new file mode 100644 index 0000000000..bfed546773 --- /dev/null +++ b/test/unittest/modular_object_extension_context_impl_test/mock/include/modular_object_extension_context_impl.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H +#define MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H + +#include "extension_context.h" +#include + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectExtensionContext : public ExtensionContext { +public: + static const size_t CONTEXT_TYPE_ID; + + ErrCode StartSelfUIAbility(const AAFwk::Want &want) const + { + return AAFwk::AbilityManagerClient::GetInstance()->StartSelfUIAbility(want); + } + + ErrCode StartSelfUIAbilityWithStartOptions(const AAFwk::Want &want, + const AAFwk::StartOptions &startOptions) const + { + return AAFwk::AbilityManagerClient::GetInstance()->StartSelfUIAbilityWithStartOptions(want, startOptions); + } + + ErrCode TerminateSelf() + { + return AAFwk::AbilityManagerClient::GetInstance()->TerminateAbility(token_, -1, nullptr); + } + + bool IsContext(size_t contextTypeId) { return contextTypeId == CONTEXT_TYPE_ID; } +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H diff --git a/test/unittest/modular_object_extension_context_impl_test/modular_object_extension_context_impl_test.cpp b/test/unittest/modular_object_extension_context_impl_test/modular_object_extension_context_impl_test.cpp new file mode 100644 index 0000000000..2ec8727b86 --- /dev/null +++ b/test/unittest/modular_object_extension_context_impl_test/modular_object_extension_context_impl_test.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_context_impl.h" +#include "extension_context.h" + +using namespace testing::ext; + +namespace OHOS { +class MockRemoteObject : public IRemoteObject { +public: + explicit MockRemoteObject(std::u16string desc) : IRemoteObject(desc) {} + int GetObjectRefCount() override { return 1; } + int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override + { + return 0; + } + bool AddDeathRecipient(const sptr &recipient) override { return true; } + bool RemoveDeathRecipient(const sptr &recipient) override { return true; } + int Dump(int fd, const std::vector &args) override { return 0; } +}; +} // namespace OHOS + +namespace OHOS { +namespace AbilityRuntime { + +const size_t ModularObjectExtensionContext::CONTEXT_TYPE_ID = + std::hash {} ("ModularObjectExtensionContext"); + +} // namespace AbilityRuntime + +namespace AAFwk { +ErrCode AbilityManagerClient::g_startSelfUIAbilityResult = ERR_OK; +ErrCode AbilityManagerClient::g_startSelfUIAbilityWithStartOptionsResult = ERR_OK; +ErrCode AbilityManagerClient::g_terminateResult = ERR_OK; +bool AbilityManagerClient::g_terminateCalled = false; +IRemoteObject *AbilityManagerClient::g_lastToken = nullptr; +} // namespace AAFwk + +namespace AbilityRuntime { + +class ModularObjectExtensionContextImplTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override + { + AAFwk::AbilityManagerClient::Reset(); + } + void TearDown() override {} +}; + +// ==================== StartSelfUIAbility ==================== + +HWTEST_F(ModularObjectExtensionContextImplTest, StartSelfUIAbility_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_Success_001 start"; + auto context = std::make_shared(); + AAFwk::Want want; + auto ret = context->StartSelfUIAbility(want); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "StartSelfUIAbility_Success_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextImplTest, StartSelfUIAbility_Error_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbility_Error_001 start"; + auto context = std::make_shared(); + AAFwk::AbilityManagerClient::g_startSelfUIAbilityResult = -1; + AAFwk::Want want; + auto ret = context->StartSelfUIAbility(want); + EXPECT_EQ(ret, -1); + GTEST_LOG_(INFO) << "StartSelfUIAbility_Error_001 end"; +} + +// ==================== StartSelfUIAbilityWithStartOptions ==================== + +HWTEST_F(ModularObjectExtensionContextImplTest, StartSelfUIAbilityWithStartOptions_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbilityWithStartOptions_Success_001 start"; + auto context = std::make_shared(); + AAFwk::Want want; + AAFwk::StartOptions options; + auto ret = context->StartSelfUIAbilityWithStartOptions(want, options); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "StartSelfUIAbilityWithStartOptions_Success_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextImplTest, StartSelfUIAbilityWithStartOptions_Error_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "StartSelfUIAbilityWithStartOptions_Error_001 start"; + auto context = std::make_shared(); + AAFwk::AbilityManagerClient::g_startSelfUIAbilityWithStartOptionsResult = -2; + AAFwk::Want want; + AAFwk::StartOptions options; + auto ret = context->StartSelfUIAbilityWithStartOptions(want, options); + EXPECT_EQ(ret, -2); + GTEST_LOG_(INFO) << "StartSelfUIAbilityWithStartOptions_Error_001 end"; +} + +// ==================== TerminateSelf ==================== + +HWTEST_F(ModularObjectExtensionContextImplTest, TerminateSelf_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_Success_001 start"; + auto context = std::make_shared(); + auto ret = context->TerminateSelf(); + EXPECT_EQ(ret, ERR_OK); + EXPECT_TRUE(AAFwk::AbilityManagerClient::g_terminateCalled); + GTEST_LOG_(INFO) << "TerminateSelf_Success_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextImplTest, TerminateSelf_Error_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_Error_001 start"; + auto context = std::make_shared(); + AAFwk::AbilityManagerClient::g_terminateResult = -3; + auto ret = context->TerminateSelf(); + EXPECT_EQ(ret, -3); + GTEST_LOG_(INFO) << "TerminateSelf_Error_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextImplTest, TerminateSelf_TokenPassed_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "TerminateSelf_TokenPassed_001 start"; + auto context = std::make_shared(); + sptr token = sptr(new MockRemoteObject(u"test_token")); + context->token_ = token; + auto ret = context->TerminateSelf(); + EXPECT_EQ(ret, ERR_OK); + EXPECT_EQ(AAFwk::AbilityManagerClient::g_lastToken, token.GetRefPtr()); + GTEST_LOG_(INFO) << "TerminateSelf_TokenPassed_001 end"; +} + +// ==================== CONTEXT_TYPE_ID ==================== + +HWTEST_F(ModularObjectExtensionContextImplTest, ContextTypeId_NonZero_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ContextTypeId_NonZero_001 start"; + EXPECT_NE(ModularObjectExtensionContext::CONTEXT_TYPE_ID, static_cast(0)); + GTEST_LOG_(INFO) << "ContextTypeId_NonZero_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextImplTest, IsContext_SelfType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "IsContext_SelfType_001 start"; + auto context = std::make_shared(); + EXPECT_TRUE(context->IsContext(ModularObjectExtensionContext::CONTEXT_TYPE_ID)); + GTEST_LOG_(INFO) << "IsContext_SelfType_001 end"; +} + +HWTEST_F(ModularObjectExtensionContextImplTest, IsContext_InvalidType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "IsContext_InvalidType_001 start"; + auto context = std::make_shared(); + EXPECT_FALSE(context->IsContext(0)); + EXPECT_FALSE(context->IsContext(99999)); + GTEST_LOG_(INFO) << "IsContext_InvalidType_001 end"; +} + +} // namespace AbilityRuntime +} // namespace OHOS diff --git a/test/unittest/modular_object_extension_manager_connect_test/BUILD.gn b/test/unittest/modular_object_extension_manager_connect_test/BUILD.gn new file mode 100644 index 0000000000..e2e2b69920 --- /dev/null +++ b/test/unittest/modular_object_extension_manager_connect_test/BUILD.gn @@ -0,0 +1,58 @@ +# Copyright (c) 2026 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/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +module_output_path = "ability_runtime/ability_runtime/capi_ability_runtime" + +ohos_unittest("modular_object_extension_manager_connect_test") { + module_out_path = module_output_path + + cflags_cc = [] + include_dirs = [] + + sources = [ "modular_object_extension_manager_connect_test.cpp" ] + + include_dirs = [ + "${ability_runtime_ndk_path}/ability_runtime", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_path}/interfaces/inner_api/", + "${ability_runtime_path}/interfaces/inner_api/ability_manager/include", + "${ability_runtime_path}/interfaces/kits/native/appkit/ability_runtime/", + "${ability_runtime_path}/services/common/include", + ] + + deps = [ + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_path}/frameworks/c/ability_runtime:ability_runtime", + ] + + external_deps = [ + "ability_base:ability_base_want", + "ability_base:want", + "c_utils:utils", + "googletest:gmock_main", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_capi", + "ipc:ipc_core", + "napi:ace_napi", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_extension_manager_connect_test" ] +} diff --git a/test/unittest/modular_object_extension_manager_connect_test/modular_object_extension_manager_connect_test.cpp b/test/unittest/modular_object_extension_manager_connect_test/modular_object_extension_manager_connect_test.cpp new file mode 100644 index 0000000000..c2589fed9d --- /dev/null +++ b/test/unittest/modular_object_extension_manager_connect_test/modular_object_extension_manager_connect_test.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension_manager.h" +#include "ability_manager/include/modular_object_extension_info.h" +#include "connect_options.h" +#include "connect_options_impl.h" + +using namespace testing::ext; + +class ModularObjectExtensionManagerConnectTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() {} + void TearDown() {} +}; + +// ==================== Connect - Parameter Validation ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, Connect_NullConnectOptions_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Connect_NullConnectOptions_001 start"; + int64_t connectionId = 0; + auto ret = OH_AbilityRuntime_ConnectModularObjectExtensionAbility(nullptr, nullptr, &connectionId); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "Connect_NullConnectOptions_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, Connect_NullConnectionId_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Connect_NullConnectionId_001 start"; + OH_AbilityRuntime_ConnectOptions *options = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(options, nullptr); + auto ret = OH_AbilityRuntime_ConnectModularObjectExtensionAbility(nullptr, options, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(options); + GTEST_LOG_(INFO) << "Connect_NullConnectionId_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, Connect_NullState_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Connect_NullState_001 start"; + OH_AbilityRuntime_ConnectOptions options; + options.state = nullptr; + int64_t connectionId = 0; + auto ret = OH_AbilityRuntime_ConnectModularObjectExtensionAbility(nullptr, &options, &connectionId); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "Connect_NullState_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, Connect_StateNotAlive_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Connect_StateNotAlive_001 start"; + OH_AbilityRuntime_ConnectOptions *options = OH_AbilityRuntime_CreateConnectOptions(); + ASSERT_NE(options, nullptr); + ASSERT_NE(options->state, nullptr); + options->state->alive = false; + int64_t connectionId = 0; + auto ret = OH_AbilityRuntime_ConnectModularObjectExtensionAbility(nullptr, options, &connectionId); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + OH_AbilityRuntime_DestroyConnectOptions(options); + GTEST_LOG_(INFO) << "Connect_StateNotAlive_001 end"; +} + +// ==================== Disconnect - Connection Not Found ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, Disconnect_ConnectionNotFound_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Disconnect_ConnectionNotFound_001 start"; + auto ret = OH_AbilityRuntime_DisconnectModularObjectExtensionAbility(-1); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "Disconnect_ConnectionNotFound_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, Disconnect_ConnectionNotFound_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Disconnect_ConnectionNotFound_002 start"; + auto ret = OH_AbilityRuntime_DisconnectModularObjectExtensionAbility(99999); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "Disconnect_ConnectionNotFound_002 end"; +} + +// ==================== ReleaseAllExtensionInfos ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, ReleaseAllExtensionInfos_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ReleaseAllExtensionInfos_Null_001 start"; + auto ret = OH_AbilityRuntime_ReleaseAllExtensionInfos(nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + GTEST_LOG_(INFO) << "ReleaseAllExtensionInfos_Null_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, ReleaseAllExtensionInfos_NullPointer_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ReleaseAllExtensionInfos_NullPointer_001 start"; + OH_AbilityRuntime_AllModObjExtensionInfosHandle handle = nullptr; + auto ret = OH_AbilityRuntime_ReleaseAllExtensionInfos(&handle); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_NO_ERROR); + GTEST_LOG_(INFO) << "ReleaseAllExtensionInfos_NullPointer_001 end"; +} + +// ==================== GetCount null checks ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetCount_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetCount_Null_001 start"; + size_t count = 0; + auto ret = OH_AbilityRuntime_GetCountFromAllModObjExtensionInfos(nullptr, &count); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetCount_Null_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetCount_NullCount_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetCount_NullCount_001 start"; + struct AllInfos { + int dummy; + }; + AllInfos infos; + auto ret = OH_AbilityRuntime_GetCountFromAllModObjExtensionInfos( + reinterpret_cast(&infos), nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetCount_NullCount_001 end"; +} + +// ==================== GetModObjExtensionInfoByIndex null checks ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetByIndex_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetByIndex_Null_001 start"; + OH_AbilityRuntime_ModObjExtensionInfoHandle handle = nullptr; + auto ret = OH_AbilityRuntime_GetModObjExtensionInfoByIndex(nullptr, 0, &handle); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetByIndex_Null_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetByIndex_NullOutHandle_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetByIndex_NullOutHandle_001 start"; + struct AllInfos { + int dummy; + }; + AllInfos infos; + auto ret = OH_AbilityRuntime_GetModObjExtensionInfoByIndex( + reinterpret_cast(&infos), 0, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetByIndex_NullOutHandle_001 end"; +} + +// ==================== AcquireSelf null check ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, AcquireSelf_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AcquireSelf_Null_001 start"; + auto ret = OH_AbilityRuntime_AcquireSelfModularObjectExtensionInfos(nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "AcquireSelf_Null_001 end"; +} + +// ==================== GetLaunchMode/ProcessMode/ThreadMode null checks ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetLaunchMode_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetLaunchMode_Null_001 start"; + OH_AbilityRuntime_LaunchMode mode; + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoLaunchMode(nullptr, &mode); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetLaunchMode_Null_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetLaunchMode_NullMode_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetLaunchMode_NullMode_001 start"; + OH_AbilityRuntime_ModObjExtensionInfoHandle handle = reinterpret_cast(1); + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoLaunchMode(handle, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetLaunchMode_NullMode_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetProcessMode_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetProcessMode_Null_001 start"; + OH_AbilityRuntime_ProcessMode mode; + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoProcessMode(nullptr, &mode); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetProcessMode_Null_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetThreadMode_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetThreadMode_Null_001 start"; + OH_AbilityRuntime_ThreadMode mode; + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoThreadMode(nullptr, &mode); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetThreadMode_Null_001 end"; +} + +// ==================== GetElementName null checks ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetElementName_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetElementName_Null_001 start"; + AbilityBase_Element element; + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoElementName(nullptr, &element); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetElementName_Null_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetElementName_NullElement_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetElementName_NullElement_001 start"; + OH_AbilityRuntime_ModObjExtensionInfoHandle handle = + reinterpret_cast(1); + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoElementName(handle, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetElementName_NullElement_001 end"; +} + +// ==================== GetDisableState null checks ==================== + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetDisableState_Null_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetDisableState_Null_001 start"; + bool isDisabled = false; + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoDisableState(nullptr, &isDisabled); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetDisableState_Null_001 end"; +} + +HWTEST_F(ModularObjectExtensionManagerConnectTest, GetDisableState_NullOut_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetDisableState_NullOut_001 start"; + OH_AbilityRuntime_ModObjExtensionInfoHandle handle = + reinterpret_cast(1); + auto ret = OH_AbilityRuntime_GetModularObjectExtensionInfoDisableState(handle, nullptr); + EXPECT_EQ(ret, ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID); + GTEST_LOG_(INFO) << "GetDisableState_NullOut_001 end"; +} diff --git a/test/unittest/modular_object_extension_manager_test/BUILD.gn b/test/unittest/modular_object_extension_manager_test/BUILD.gn index ff0e9f736d..940502e903 100755 --- a/test/unittest/modular_object_extension_manager_test/BUILD.gn +++ b/test/unittest/modular_object_extension_manager_test/BUILD.gn @@ -46,6 +46,7 @@ ohos_unittest("modular_object_extension_manager_test") { "googletest:gmock_main", "googletest:gtest_main", "hilog:libhilog", + "ipc:ipc_capi", "ipc:ipc_core", "napi:ace_napi", ] diff --git a/test/unittest/modular_object_extension_test/BUILD.gn b/test/unittest/modular_object_extension_test/BUILD.gn new file mode 100644 index 0000000000..da0c90ad12 --- /dev/null +++ b/test/unittest/modular_object_extension_test/BUILD.gn @@ -0,0 +1,47 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("modular_object_extension_test") { + module_out_path = "ability_runtime/ability_runtime/modular_object_extension_test" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + sources = [ + "modular_object_extension_test.cpp", + "${ability_runtime_path}/frameworks/native/ability/native/modular_object_extension/modular_object_extension.cpp", + ] + include_dirs = [ + "mock/include", + "${ability_runtime_path}/frameworks/c/ability_runtime/include", + "${ability_runtime_services_path}/common/include", + ] + cflags = [ "-Dprivate=public" ] + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_extension_test" ] +} diff --git a/test/unittest/modular_object_extension_test/mock/include/ability_base_error.h b/test/unittest/modular_object_extension_test/mock/include/ability_base_error.h new file mode 100644 index 0000000000..998ac4a60b --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/ability_base_error.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_BASE_ERROR_H +#define MOCK_ABILITY_BASE_ERROR_H + +constexpr int ABILITY_BASE_ERROR_CODE_NO_ERROR = 0; + +#endif // MOCK_ABILITY_BASE_ERROR_H diff --git a/test/unittest/modular_object_extension_test/mock/include/ability_runtime_common.h b/test/unittest/modular_object_extension_test/mock/include/ability_runtime_common.h new file mode 100644 index 0000000000..ff20d34976 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/ability_runtime_common.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_RUNTIME_COMMON_H +#define MOCK_ABILITY_RUNTIME_COMMON_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ABILITY_RUNTIME_ERROR_CODE_NO_ERROR = 0, + ABILITY_RUNTIME_ERROR_CODE_PARAM_INVALID = 401, + ABILITY_RUNTIME_ERROR_CODE_INCORRECT_ABILITY_TYPE = 16000002, + ABILITY_RUNTIME_ERROR_CODE_CONTEXT_NOT_EXIST = 16000011, + ABILITY_RUNTIME_ERROR_CODE_INTERNAL = 16000050, +} AbilityRuntime_ErrorCode; + +typedef struct AbilityRuntime_Context *AbilityRuntime_ContextHandle; + +#ifdef __cplusplus +} +#endif + +#endif // MOCK_ABILITY_RUNTIME_COMMON_H diff --git a/test/unittest/modular_object_extension_test/mock/include/element_name.h b/test/unittest/modular_object_extension_test/mock/include/element_name.h new file mode 100644 index 0000000000..ea7ab4437c --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/element_name.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026 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 MOCK_ELEMENT_NAME_H +#define MOCK_ELEMENT_NAME_H + +#include + +namespace OHOS { +namespace AppExecFwk { + +class ElementName { +public: + ElementName() = default; + ElementName(const std::string &device, const std::string &bundle, + const std::string &module, const std::string &ability) + : bundleName_(bundle), moduleName_(module), abilityName_(ability) {} + + std::string GetBundleName() const { return bundleName_; } + std::string GetModuleName() const { return moduleName_; } + std::string GetAbilityName() const { return abilityName_; } + void SetBundleName(const std::string &s) { bundleName_ = s; } + void SetModuleName(const std::string &s) { moduleName_ = s; } + void SetAbilityName(const std::string &s) { abilityName_ = s; } + +private: + std::string bundleName_; + std::string moduleName_; + std::string abilityName_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_ELEMENT_NAME_H diff --git a/test/unittest/modular_object_extension_test/mock/include/errors.h b/test/unittest/modular_object_extension_test/mock/include/errors.h new file mode 100644 index 0000000000..cec8b1e1c1 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/errors.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 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 MOCK_ERRORS_H +#define MOCK_ERRORS_H + +#include +using ErrCode = int32_t; +constexpr ErrCode ERR_OK = 0; + +#endif // MOCK_ERRORS_H \ No newline at end of file diff --git a/test/unittest/modular_object_extension_test/mock/include/extension.h b/test/unittest/modular_object_extension_test/mock/include/extension.h new file mode 100644 index 0000000000..301b95afc0 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/extension.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_H +#define MOCK_EXTENSION_H + +#include +#include +#include "mock_types.h" +#include "refbase.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AbilityRuntime { + +class AbilityLocalRecord {}; +class OHOSApplication {}; +class AbilityHandler {}; + +struct AbilityInfo { + std::string srcEntrance; + std::string moduleName; + std::string bundleName; + std::string name; +}; + +class Extension : public std::enable_shared_from_this { +public: + Extension() = default; + virtual ~Extension() = default; + + virtual void Init(const std::shared_ptr &, + const std::shared_ptr &, + std::shared_ptr &, + const sptr &) {} + + virtual void OnStart(const AAFwk::Want &want) {} + virtual void OnStop() {} + virtual sptr OnConnect(const AAFwk::Want &want) { return nullptr; } + virtual void OnDisconnect(const AAFwk::Want &want) {} + + std::shared_ptr abilityInfo_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_EXTENSION_H diff --git a/test/unittest/modular_object_extension_test/mock/include/extension_ability.h b/test/unittest/modular_object_extension_test/mock/include/extension_ability.h new file mode 100644 index 0000000000..62eb34f2f5 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/extension_ability.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_ABILITY_H +#define MOCK_EXTENSION_ABILITY_H + +#include "native_extension/extension_ability_impl.h" + +#endif // MOCK_EXTENSION_ABILITY_H \ No newline at end of file diff --git a/test/unittest/modular_object_extension_test/mock/include/extension_ability_info.h b/test/unittest/modular_object_extension_test/mock/include/extension_ability_info.h new file mode 100644 index 0000000000..9c5523aa2f --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/extension_ability_info.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_ABILITY_INFO_H +#define MOCK_EXTENSION_ABILITY_INFO_H + +namespace OHOS { +namespace AppExecFwk { + +enum ExtensionAbilityType { + UNSPECIFIED = 0, + SERVICE = 1, + MODULAR_OBJECT = 99, +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_EXTENSION_ABILITY_INFO_H diff --git a/test/unittest/modular_object_extension_test/mock/include/extension_base.h b/test/unittest/modular_object_extension_test/mock/include/extension_base.h new file mode 100644 index 0000000000..a3ef4216c6 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/extension_base.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 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 MOCK_EXTENSION_BASE_H +#define MOCK_EXTENSION_BASE_H + +#include "extension.h" + +namespace OHOS { +namespace AbilityRuntime { + +template +class ExtensionBase : public Extension { +public: + ExtensionBase() = default; + virtual ~ExtensionBase() = default; + + void Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, + const sptr &token) override + { + Extension::Init(record, application, handler, token); + } + + virtual std::shared_ptr CreateAndInitContext(const std::shared_ptr &, + const std::shared_ptr &, + std::shared_ptr &, + const sptr &) { return nullptr; } + + std::shared_ptr GetContext() { return context_; } + std::shared_ptr context_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_EXTENSION_BASE_H diff --git a/test/unittest/modular_object_extension_test/mock/include/ipc_cparcel.h b/test/unittest/modular_object_extension_test/mock/include/ipc_cparcel.h new file mode 100644 index 0000000000..5bd3d31bc9 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/ipc_cparcel.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2026 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 MOCK_IPC_CPARCEL_H +#define MOCK_IPC_CPARCEL_H + +#include "refbase.h" +#include "iremote_object.h" + +struct OHIPCRemoteStub { + OHOS::sptr remote; +}; + +#endif // MOCK_IPC_CPARCEL_H diff --git a/test/unittest/modular_object_extension_test/mock/include/ipc_inner_object.h b/test/unittest/modular_object_extension_test/mock/include/ipc_inner_object.h new file mode 100644 index 0000000000..2fafc9791e --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/ipc_inner_object.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 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 MOCK_IPC_INNER_OBJECT_H +#define MOCK_IPC_INNER_OBJECT_H + +#include "ipc_cparcel.h" + +#endif // MOCK_IPC_INNER_OBJECT_H diff --git a/test/unittest/modular_object_extension_test/mock/include/mock_types.h b/test/unittest/modular_object_extension_test/mock/include/mock_types.h new file mode 100644 index 0000000000..8179287c50 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/mock_types.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026 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 MOCK_TYPES_H +#define MOCK_TYPES_H + +#include "element_name.h" +#include + +namespace OHOS { +namespace AAFwk { + +class Want { +public: + AppExecFwk::ElementName GetElement() const { return element_; } + void SetElement(const AppExecFwk::ElementName &element) { element_ = element; } + +private: + AppExecFwk::ElementName element_; +}; + +class StartOptions {}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_TYPES_H diff --git a/test/unittest/modular_object_extension_test/mock/include/modular_object_extension.h b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension.h new file mode 100644 index 0000000000..8779f9d025 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_H +#define MOCK_MODULAR_OBJECT_EXTENSION_H + +#include "extension_base.h" +#include "modular_object_extension_context_impl.h" +#include "modular_object_extension_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct AbilityBase_Want; +typedef struct AbilityBase_Want AbilityBase_Want; +struct AbilityBase_Element; +typedef struct AbilityBase_Element AbilityBase_Element; + +#ifdef __cplusplus +} +#endif + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectExtension : public ExtensionBase { +public: + ModularObjectExtension() = default; + ~ModularObjectExtension() override = default; + + std::shared_ptr CreateAndInitContext( + const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, + const sptr &token) override; + + void Init(const std::shared_ptr &record, + const std::shared_ptr &application, + std::shared_ptr &handler, + const sptr &token) override; + + static ModularObjectExtension *Create(); + + void OnStart(const AAFwk::Want &want) override; + void OnStop() override; + sptr OnConnect(const AAFwk::Want &want) override; + void OnDisconnect(const AAFwk::Want &want) override; + +private: + bool LoadNativeExtensionModule(); + bool BuildCWant(const AAFwk::Want &want, AbilityBase_Want &cWant, AbilityBase_Element &element) const; + static bool BuildElement(const AppExecFwk::ElementName &elementName, AbilityBase_Element &element); + static void DestroyElement(AbilityBase_Element &element); + + std::shared_ptr moeInstance_; + std::shared_ptr moeContext_; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_H diff --git a/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_ability.h b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_ability.h new file mode 100644 index 0000000000..8399df64ca --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_ability.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H +#define MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H + +#include "ability_runtime_common.h" + +struct AbilityBase_Want; +struct OHIPCRemoteStub; + +typedef struct OH_AbilityRuntime_ModularObjectExtensionInstance *OH_AbilityRuntime_ModObjExtensionInstanceHandle; + +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, struct AbilityBase_Want *); +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle); +typedef struct OHIPCRemoteStub *(*OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, struct AbilityBase_Want *); +typedef void (*OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc)( + OH_AbilityRuntime_ModObjExtensionInstanceHandle); + +#ifdef __cplusplus +extern "C" { +#endif + +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnCreateFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDestroyFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnConnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc); +AbilityRuntime_ErrorCode OH_AbilityRuntime_ModObjExtensionAbility_RegisterOnDisconnectFunc( + OH_AbilityRuntime_ModObjExtensionInstanceHandle, OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc); + +#ifdef __cplusplus +} +#endif + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_ABILITY_H diff --git a/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_context_impl.h b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_context_impl.h new file mode 100644 index 0000000000..ba35759e66 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_context_impl.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H +#define MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H + +#include "native_extension/context_impl.h" +#include "errors.h" +#include "mock_types.h" + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectExtensionContext : public Context { +public: + ModularObjectExtensionContext() = default; +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_CONTEXT_IMPL_H diff --git a/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_types.h b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_types.h new file mode 100644 index 0000000000..10a0ea997b --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/modular_object_extension_types.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H +#define MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H + +#include +#include "extension_ability_info.h" +#include "modular_object_extension_ability.h" +#include "native_extension/context_impl.h" +#include "native_extension/extension_ability_impl.h" + +struct OH_AbilityRuntime_ModularObjectExtensionContext : public AbilityRuntime_Context {}; + +struct OH_AbilityRuntime_ModularObjectExtensionInstance : public AbilityRuntime_ExtensionInstance { + std::shared_ptr context; + OH_AbilityRuntime_ModObjExtensionAbility_OnCreateFunc onCreateFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDestroyFunc onDestroyFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnConnectFunc onConnectFunc = nullptr; + OH_AbilityRuntime_ModObjExtensionAbility_OnDisconnectFunc onDisconnectFunc = nullptr; +}; + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_TYPES_H diff --git a/test/unittest/modular_object_extension_test/mock/include/native_extension/context_impl.h b/test/unittest/modular_object_extension_test/mock/include/native_extension/context_impl.h new file mode 100644 index 0000000000..bfbba7b439 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/native_extension/context_impl.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 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 MOCK_NATIVE_CONTEXT_IMPL_H +#define MOCK_NATIVE_CONTEXT_IMPL_H + +#include +#include "extension_ability_info.h" + +namespace OHOS { +namespace AbilityRuntime { +class Context : public std::enable_shared_from_this {}; +} // namespace AbilityRuntime +} // namespace OHOS + +struct AbilityRuntime_Context { + OHOS::AppExecFwk::ExtensionAbilityType type; + std::weak_ptr context; +}; + +#endif // MOCK_NATIVE_CONTEXT_IMPL_H diff --git a/test/unittest/modular_object_extension_test/mock/include/native_extension/extension_ability_impl.h b/test/unittest/modular_object_extension_test/mock/include/native_extension/extension_ability_impl.h new file mode 100644 index 0000000000..8bfcfc2f5f --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/native_extension/extension_ability_impl.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 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 MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H +#define MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H + +#include +#include "extension_ability_info.h" + +namespace OHOS { +namespace AbilityRuntime { +class Extension; +} // namespace AbilityRuntime +} // namespace OHOS + +struct AbilityRuntime_ExtensionInstance { + OHOS::AppExecFwk::ExtensionAbilityType type; + std::weak_ptr extension; +}; + +typedef struct AbilityRuntime_ExtensionInstance *AbilityRuntime_ExtensionInstanceHandle; + +#endif // MOCK_NATIVE_EXTENSION_ABILITY_IMPL_H diff --git a/test/unittest/modular_object_extension_test/mock/include/native_runtime.h b/test/unittest/modular_object_extension_test/mock/include/native_runtime.h new file mode 100644 index 0000000000..1223a51172 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/native_runtime.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 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 MOCK_NATIVE_RUNTIME_H +#define MOCK_NATIVE_RUNTIME_H + +#include +#include "native_extension/extension_ability_impl.h" + +namespace OHOS { +namespace AbilityRuntime { + +class NativeRuntime { +public: + static bool g_loadModuleResult; + static bool LoadModule(const std::string &bundleModuleName, const std::string &fileName, + const std::string &abilityName, AbilityRuntime_ExtensionInstance &instance) + { + return g_loadModuleResult; + } +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +#endif // MOCK_NATIVE_RUNTIME_H diff --git a/test/unittest/modular_object_extension_test/mock/include/want.h b/test/unittest/modular_object_extension_test/mock/include/want.h new file mode 100644 index 0000000000..09040fc870 --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/want.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2026 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 MOCK_WANT_H +#define MOCK_WANT_H + +typedef struct AbilityBase_Element { + char *bundleName; + char *moduleName; + char *abilityName; +} AbilityBase_Element; + +typedef struct AbilityBase_Want AbilityBase_Want; +#endif // MOCK_WANT_H diff --git a/test/unittest/modular_object_extension_test/mock/include/want_manager.h b/test/unittest/modular_object_extension_test/mock/include/want_manager.h new file mode 100644 index 0000000000..d5c3d373cc --- /dev/null +++ b/test/unittest/modular_object_extension_test/mock/include/want_manager.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2026 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 MOCK_WANT_MANAGER_H +#define MOCK_WANT_MANAGER_H + +#include "want.h" +#include "ability_base_error.h" +#include "mock_types.h" +#include +#include + +struct AbilityBase_Want { + AbilityBase_Element element; + std::map params; + int flag = 0; +}; + +namespace OHOS { +namespace AAFwk { + +class CWantManager { +public: + static int TransformToWant(const AbilityBase_Want &cWant, bool flag, Want &abilityWant) + { + return g_transformResult; + } + + static int TransformToCWantWithoutElement(const Want &want, bool flag, AbilityBase_Want &cWant) + { + return g_transformResult; + } + + static int g_transformResult; +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_WANT_MANAGER_H diff --git a/test/unittest/modular_object_extension_test/modular_object_extension_test.cpp b/test/unittest/modular_object_extension_test/modular_object_extension_test.cpp new file mode 100644 index 0000000000..1631131630 --- /dev/null +++ b/test/unittest/modular_object_extension_test/modular_object_extension_test.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2026 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 "modular_object_extension.h" +#include "native_runtime.h" +#include "want_manager.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AbilityRuntime; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; + +namespace OHOS { +namespace AbilityRuntime { + +bool NativeRuntime::g_loadModuleResult = true; + +} // namespace AbilityRuntime + +namespace AAFwk { +int CWantManager::g_transformResult = 0; +} // namespace AAFwk +} // namespace OHOS + +// Static flags for callbacks +static bool g_onCreateCalled = false; +static bool g_onDestroyCalled = false; +static bool g_onDisconnectCalled = false; +static OHIPCRemoteStub *g_connectStubResult = nullptr; + +static void OnCreateCallback(OH_AbilityRuntime_ModObjExtensionInstanceHandle, AbilityBase_Want *) +{ + g_onCreateCalled = true; +} + +static void OnDestroyCallback(OH_AbilityRuntime_ModObjExtensionInstanceHandle) +{ + g_onDestroyCalled = true; +} + +static OHIPCRemoteStub *OnConnectCallback(OH_AbilityRuntime_ModObjExtensionInstanceHandle, AbilityBase_Want *) +{ + return g_connectStubResult; +} + +static void OnDisconnectCallback(OH_AbilityRuntime_ModObjExtensionInstanceHandle) +{ + g_onDisconnectCalled = true; +} + +class ModularObjectExtensionTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override + { + NativeRuntime::g_loadModuleResult = true; + CWantManager::g_transformResult = 0; + g_onCreateCalled = false; + g_onDestroyCalled = false; + g_onDisconnectCalled = false; + g_connectStubResult = nullptr; + } + void TearDown() override {} +}; + +// ==================== Create ==================== + +HWTEST_F(ModularObjectExtensionTest, Create_ReturnsNonNull_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Create_ReturnsNonNull_001 start"; + auto *ext = ModularObjectExtension::Create(); + EXPECT_NE(ext, nullptr); + delete ext; + GTEST_LOG_(INFO) << "Create_ReturnsNonNull_001 end"; +} + +// ==================== BuildElement ==================== + +HWTEST_F(ModularObjectExtensionTest, BuildElement_Success_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BuildElement_Success_001 start"; + AppExecFwk::ElementName elementName("", "com.test", "entry", "MainAbility"); + AbilityBase_Element element = {nullptr, nullptr, nullptr}; + bool ret = ModularObjectExtension::BuildElement(elementName, element); + EXPECT_TRUE(ret); + EXPECT_STREQ(element.bundleName, "com.test"); + EXPECT_STREQ(element.moduleName, "entry"); + EXPECT_STREQ(element.abilityName, "MainAbility"); + ModularObjectExtension::DestroyElement(element); + GTEST_LOG_(INFO) << "BuildElement_Success_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, BuildElement_EmptyStrings_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BuildElement_EmptyStrings_001 start"; + AppExecFwk::ElementName elementName("", "", "", ""); + AbilityBase_Element element = {nullptr, nullptr, nullptr}; + bool ret = ModularObjectExtension::BuildElement(elementName, element); + EXPECT_TRUE(ret); + ModularObjectExtension::DestroyElement(element); + GTEST_LOG_(INFO) << "BuildElement_EmptyStrings_001 end"; +} + +// ==================== DestroyElement ==================== + +HWTEST_F(ModularObjectExtensionTest, DestroyElement_NullPtrs_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DestroyElement_NullPtrs_001 start"; + AbilityBase_Element element = {nullptr, nullptr, nullptr}; + ModularObjectExtension::DestroyElement(element); + EXPECT_EQ(element.bundleName, nullptr); + EXPECT_EQ(element.moduleName, nullptr); + EXPECT_EQ(element.abilityName, nullptr); + GTEST_LOG_(INFO) << "DestroyElement_NullPtrs_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, DestroyElement_AllocatedPtrs_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "DestroyElement_AllocatedPtrs_001 start"; + AppExecFwk::ElementName elementName("", "bundle", "module", "ability"); + AbilityBase_Element element = {nullptr, nullptr, nullptr}; + ModularObjectExtension::BuildElement(elementName, element); + ModularObjectExtension::DestroyElement(element); + EXPECT_EQ(element.bundleName, nullptr); + EXPECT_EQ(element.moduleName, nullptr); + EXPECT_EQ(element.abilityName, nullptr); + GTEST_LOG_(INFO) << "DestroyElement_AllocatedPtrs_001 end"; +} + +// ==================== Init ==================== + +HWTEST_F(ModularObjectExtensionTest, Init_SetsUpInstance_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Init_SetsUpInstance_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + EXPECT_NE(ext->moeInstance_, nullptr); + EXPECT_NE(ext->moeContext_, nullptr); + GTEST_LOG_(INFO) << "Init_SetsUpInstance_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, Init_SetsExtensionType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Init_SetsExtensionType_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + EXPECT_EQ(ext->moeInstance_->type, AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT); + EXPECT_EQ(ext->moeContext_->type, AppExecFwk::ExtensionAbilityType::MODULAR_OBJECT); + GTEST_LOG_(INFO) << "Init_SetsExtensionType_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, Init_LoadModuleFails_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "Init_LoadModuleFails_001 start"; + NativeRuntime::g_loadModuleResult = false; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + EXPECT_NE(ext->moeInstance_, nullptr); + GTEST_LOG_(INFO) << "Init_LoadModuleFails_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnStart_NullOnCreateFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnStart_NullOnCreateFunc_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + ext->moeInstance_->onCreateFunc = nullptr; + Want want; + ext->OnStart(want); + EXPECT_FALSE(g_onCreateCalled); + GTEST_LOG_(INFO) << "OnStart_NullOnCreateFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnStart_WithCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnStart_WithCallback_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + ext->moeInstance_->onCreateFunc = OnCreateCallback; + Want want; + ext->OnStart(want); + EXPECT_TRUE(g_onCreateCalled); + GTEST_LOG_(INFO) << "OnStart_WithCallback_001 end"; +} + +// ==================== OnStop ==================== + +HWTEST_F(ModularObjectExtensionTest, OnStop_NullInstance_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnStop_NullInstance_001 start"; + auto ext = std::make_shared(); + ext->OnStop(); + GTEST_LOG_(INFO) << "OnStop_NullInstance_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnStop_NullOnDestroyFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnStop_NullOnDestroyFunc_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + ext->moeInstance_->onDestroyFunc = nullptr; + ext->OnStop(); + EXPECT_FALSE(g_onDestroyCalled); + GTEST_LOG_(INFO) << "OnStop_NullOnDestroyFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnStop_WithCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnStop_WithCallback_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + ext->moeInstance_->onDestroyFunc = OnDestroyCallback; + ext->OnStop(); + EXPECT_TRUE(g_onDestroyCalled); + GTEST_LOG_(INFO) << "OnStop_WithCallback_001 end"; +} + +// ==================== OnConnect ==================== + +HWTEST_F(ModularObjectExtensionTest, OnConnect_NullInstance_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnect_NullInstance_001 start"; + auto ext = std::make_shared(); + Want want; + auto ret = ext->OnConnect(want); + EXPECT_EQ(ret, nullptr); + GTEST_LOG_(INFO) << "OnConnect_NullInstance_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnConnect_NullOnConnectFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnect_NullOnConnectFunc_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + ext->moeInstance_->onConnectFunc = nullptr; + Want want; + auto ret = ext->OnConnect(want); + EXPECT_EQ(ret, nullptr); + GTEST_LOG_(INFO) << "OnConnect_NullOnConnectFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnConnect_NullStubReturned_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnConnect_NullStubReturned_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + g_connectStubResult = nullptr; + ext->moeInstance_->onConnectFunc = OnConnectCallback; + Want want; + auto ret = ext->OnConnect(want); + EXPECT_EQ(ret, nullptr); + GTEST_LOG_(INFO) << "OnConnect_NullStubReturned_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnDisconnect_NullOnDisconnectFunc_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnDisconnect_NullOnDisconnectFunc_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + ext->moeInstance_->onDisconnectFunc = nullptr; + Want want; + ext->OnDisconnect(want); + EXPECT_FALSE(g_onDisconnectCalled); + GTEST_LOG_(INFO) << "OnDisconnect_NullOnDisconnectFunc_001 end"; +} + +HWTEST_F(ModularObjectExtensionTest, OnDisconnect_WithCallback_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "OnDisconnect_WithCallback_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + ext->Init(record, app, handler, token); + ext->moeInstance_->onDisconnectFunc = OnDisconnectCallback; + Want want; + ext->OnDisconnect(want); + EXPECT_TRUE(g_onDisconnectCalled); + GTEST_LOG_(INFO) << "OnDisconnect_WithCallback_001 end"; +} + +// ==================== CreateAndInitContext ==================== + +HWTEST_F(ModularObjectExtensionTest, CreateAndInitContext_ReturnsNullptr_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CreateAndInitContext_ReturnsNullptr_001 start"; + auto ext = std::make_shared(); + auto record = std::make_shared(); + auto app = std::make_shared(); + auto handler = std::make_shared(); + sptr token; + auto ret = ext->CreateAndInitContext(record, app, handler, token); + EXPECT_EQ(ret, nullptr); + GTEST_LOG_(INFO) << "CreateAndInitContext_ReturnsNullptr_001 end"; +} diff --git a/test/unittest/modular_object_utils_test/BUILD.gn b/test/unittest/modular_object_utils_test/BUILD.gn new file mode 100644 index 0000000000..947266b415 --- /dev/null +++ b/test/unittest/modular_object_utils_test/BUILD.gn @@ -0,0 +1,54 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_unittest("modular_object_utils_test") { + module_out_path = "ability_runtime/ability_runtime/modular_object_utils_test" + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../cfi_blocklist.txt" + } + + sources = [ + "modular_object_utils_test.cpp", + "mock/src/mock_flag.cpp", + "${ability_runtime_services_path}/abilitymgr/src/modular_object_utils.cpp", + ] + + include_dirs = [ + "mock/include", + "${ability_runtime_services_path}/common/include", + ] + + cflags = [ "-Dprivate=public" ] + + deps = [] + + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":modular_object_utils_test" ] +} diff --git a/test/unittest/modular_object_utils_test/mock/include/ability_manager_errors.h b/test/unittest/modular_object_utils_test/mock/include/ability_manager_errors.h new file mode 100644 index 0000000000..5f43cf3f2e --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/ability_manager_errors.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_MANAGER_ERRORS_H +#define MOCK_ABILITY_MANAGER_ERRORS_H + +#include + +using ErrCode = int32_t; + +constexpr int32_t SUBSYS_AAFWK = 4; +constexpr int32_t ABILITY_MODULE_TYPE_SERVICE = 0; + +inline constexpr ErrCode ErrCodeOffset(int32_t subsysId, int32_t moduleId) +{ + return ((subsysId << 20) | (moduleId << 16)); +} + +constexpr ErrCode AAFWK_SERVICE_ERR_OFFSET = ErrCodeOffset(SUBSYS_AAFWK, ABILITY_MODULE_TYPE_SERVICE); + +enum { + RESOLVE_ABILITY_ERR = AAFWK_SERVICE_ERR_OFFSET, + INNER_ERR = AAFWK_SERVICE_ERR_OFFSET + 100, + ERR_CAPABILITY_NOT_SUPPORT = AAFWK_SERVICE_ERR_OFFSET + 125, + ERR_PERMISSION_DENIED = AAFWK_SERVICE_ERR_OFFSET + 6, + ERR_OK = 0, +}; + +enum { + NOT_TOP_ABILITY = 0x500001, +}; + +constexpr ErrCode ERR_MODULAR_OBJECT_DISABLED = 2099412; +constexpr ErrCode ERR_NO_RUNNING_ABILITIES_WITH_UI = 2099413; + +#endif // MOCK_ABILITY_MANAGER_ERRORS_H diff --git a/test/unittest/modular_object_utils_test/mock/include/ability_manager_service.h b/test/unittest/modular_object_utils_test/mock/include/ability_manager_service.h new file mode 100644 index 0000000000..0e512ec21e --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/ability_manager_service.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_MANAGER_SERVICE_H +#define MOCK_ABILITY_MANAGER_SERVICE_H + +#include +#include +#include +#include "mock_flag.h" + +namespace OHOS { +namespace AAFwk { + +// Forward declare +class UIAbilityLifecycleManager; +class MissionListManagerInterface; +class UIExtensionAbilityManager; + +class UIAbilityLifecycleManager { +public: + void GetActiveAbilityList(int32_t uid, std::vector &abilityList) + { + if (MockFlag::hasRunningUIAbility) { + abilityList.push_back("TestAbility"); + } + } +}; + +class MissionListManagerInterface { +public: + void GetActiveAbilityList(int32_t uid, std::vector &abilityList) + { + if (MockFlag::hasRunningUIAbility) { + abilityList.push_back("TestAbility"); + } + } +}; + +class UIExtensionAbilityManager { +public: + void GetActiveUIExtensionListByUid(int32_t uid, std::vector &extensionList) + { + if (MockFlag::hasRunningUIExtension) { + extensionList.push_back("TestExtension"); + } + } +}; + +class AbilityManagerService { + DECLARE_DELAYED_SINGLETON(AbilityManagerService); +public: + std::shared_ptr GetUIAbilityManagerByUserId(int32_t userId) + { + if (MockFlag::uiAbilityMgrNull) { + return nullptr; + } + static auto mgr = std::make_shared(); + return mgr; + } + std::shared_ptr GetMissionListManagerByUserId(int32_t userId) + { + if (MockFlag::missionListMgrNull) { + return nullptr; + } + static auto mgr = std::make_shared(); + return mgr; + } + std::shared_ptr GetUIExtensionAbilityManagerByUserId(int32_t userId) + { + if (MockFlag::uiExtMgrNull) { + return nullptr; + } + static auto mgr = std::make_shared(); + return mgr; + } +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_ABILITY_MANAGER_SERVICE_H diff --git a/test/unittest/modular_object_utils_test/mock/include/ability_record/ability_request.h b/test/unittest/modular_object_utils_test/mock/include/ability_record/ability_request.h new file mode 100644 index 0000000000..82da7179cf --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/ability_record/ability_request.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_REQUEST_H +#define MOCK_ABILITY_REQUEST_H + +#include +#include + +namespace OHOS { +namespace AppExecFwk { +struct ApplicationInfo { + std::string appDistributionType; + int32_t uid = 0; +}; +struct AbilityInfo {}; +} // namespace AppExecFwk + +namespace AAFwk { + +class ElementName { +public: + ElementName() = default; + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &abilityName) + : bundleName_(bundleName), abilityName_(abilityName) {} + ElementName(const std::string &deviceId, const std::string &bundleName, + const std::string &moduleName, const std::string &abilityName) + : bundleName_(bundleName), moduleName_(moduleName), abilityName_(abilityName) {} + std::string GetBundleName() const { return bundleName_; } + std::string GetModuleName() const { return moduleName_; } + std::string GetAbilityName() const { return abilityName_; } + void SetBundleName(const std::string &name) { bundleName_ = name; } + void SetModuleName(const std::string &name) { moduleName_ = name; } + void SetAbilityName(const std::string &name) { abilityName_ = name; } +private: + std::string bundleName_; + std::string moduleName_; + std::string abilityName_; +}; + +class Want { +public: + inline static const std::string PARAM_APP_CLONE_INDEX_KEY = "appCloneIndex"; + ElementName GetElement() const { return element_; } + void SetElement(const ElementName &element) { element_ = element; } + int32_t GetIntParam(const std::string &key, int32_t defaultValue) const + { + if (key == PARAM_APP_CLONE_INDEX_KEY) { + return appCloneIndex_; + } + return defaultValue; + } + void SetAppCloneIndex(int32_t index) { appCloneIndex_ = index; } +private: + ElementName element_; + int32_t appCloneIndex_ = 0; +}; + +struct AbilityRequest { + Want want; + AppExecFwk::ApplicationInfo appInfo; + AppExecFwk::AbilityInfo abilityInfo; + int32_t uid = 0; + int32_t userId = 0; +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_ABILITY_REQUEST_H diff --git a/test/unittest/modular_object_utils_test/mock/include/ability_util.h b/test/unittest/modular_object_utils_test/mock/include/ability_util.h new file mode 100644 index 0000000000..02d9b47d02 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/ability_util.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 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 MOCK_ABILITY_UTIL_H +#define MOCK_ABILITY_UTIL_H + +#include "ipc_skeleton.h" + +#define IN_PROCESS_CALL(theCall) \ + ([&]() { \ + std::string identity = OHOS::IPCSkeleton::ResetCallingIdentity(); \ + auto retVal = theCall; \ + OHOS::IPCSkeleton::SetCallingIdentity(identity); \ + return retVal; \ + }()) + +#define CHECK_POINTER_AND_RETURN(object, value) \ + if (!object) { \ + return value; \ + } + +#endif // MOCK_ABILITY_UTIL_H diff --git a/test/unittest/modular_object_utils_test/mock/include/app_mgr_client.h b/test/unittest/modular_object_utils_test/mock/include/app_mgr_client.h new file mode 100644 index 0000000000..692da4ad41 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/app_mgr_client.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2026 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 MOCK_APP_MGR_CLIENT_H +#define MOCK_APP_MGR_CLIENT_H + +#include "running_process_info.h" +#include "mock_flag.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppMgrClient { + DECLARE_DELAYED_SINGLETON(AppMgrClient); +public: + int32_t GetRunningProcessInfoByPid(const pid_t pid, RunningProcessInfo &info) + { + if (MockFlag::getRunningProcessInfoRet != 0) { + return MockFlag::getRunningProcessInfoRet; + } + info.state_ = static_cast(MockFlag::processState); + info.isPreForeground = MockFlag::isPreForeground; + return 0; + } +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_APP_MGR_CLIENT_H diff --git a/test/unittest/modular_object_utils_test/mock/include/app_utils.h b/test/unittest/modular_object_utils_test/mock/include/app_utils.h new file mode 100644 index 0000000000..04ea54bb22 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/app_utils.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 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 MOCK_APP_UTILS_H +#define MOCK_APP_UTILS_H + +#include "mock_flag.h" + +namespace OHOS { +namespace AAFwk { +class AppUtils { +public: + static AppUtils &GetInstance() + { + static AppUtils instance; + return instance; + } + bool IsSupportModularObjectExtension() + { + return MockFlag::isSupportModularObjectExtension; + } +}; +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_APP_UTILS_H diff --git a/test/unittest/modular_object_utils_test/mock/include/bundle_mgr_helper.h b/test/unittest/modular_object_utils_test/mock/include/bundle_mgr_helper.h new file mode 100644 index 0000000000..5ecd0fcec9 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/bundle_mgr_helper.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026 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 MOCK_BUNDLE_MGR_HELPER_H +#define MOCK_BUNDLE_MGR_HELPER_H + +#include +#include +#include "mock_flag.h" +#include "ability_record/ability_request.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleMgrHelper { + DECLARE_DELAYED_SINGLETON(BundleMgrHelper); +public: + int32_t GetNameAndIndexForUid(int32_t uid, std::string &bundleName, int32_t &appIndex) + { + if (MockFlag::getNameAndIndexRet != 0) { + return MockFlag::getNameAndIndexRet; + } + bundleName = "com.caller.bundle"; + appIndex = 0; + return 0; + } + bool GetApplicationInfoWithAppIndex(const std::string &appName, int32_t appIndex, + int32_t userId, ApplicationInfo &appInfo) + { + if (!MockFlag::getApplicationInfoRet) { + return false; + } + appInfo.appDistributionType = "debug"; + appInfo.uid = 1000; + return true; + } +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_BUNDLE_MGR_HELPER_H diff --git a/test/unittest/modular_object_utils_test/mock/include/ipc_skeleton.h b/test/unittest/modular_object_utils_test/mock/include/ipc_skeleton.h new file mode 100644 index 0000000000..7f590e8d94 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/ipc_skeleton.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 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 MOCK_IPC_SKELETON_H +#define MOCK_IPC_SKELETON_H + +#include +#include +#include "mock_flag.h" + +namespace OHOS { +class IPCSkeleton { +public: + static int32_t GetCallingUid() + { + return MockFlag::callingUid; + } + static pid_t GetCallingPid() + { + return MockFlag::callingPid; + } + static std::string ResetCallingIdentity() + { + return ""; + } + static void SetCallingIdentity(const std::string &identity) + { + (void)identity; + } +}; +} // namespace OHOS + +#endif // MOCK_IPC_SKELETON_H diff --git a/test/unittest/modular_object_utils_test/mock/include/mock_flag.h b/test/unittest/modular_object_utils_test/mock/include/mock_flag.h new file mode 100644 index 0000000000..3160d52666 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/mock_flag.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026 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 MOCK_FLAG_H +#define MOCK_FLAG_H + +#include +#include + +class MockFlag { +public: + // AppUtils + static bool isSupportModularObjectExtension; + + // IPCSkeleton + static int32_t callingUid; + static pid_t callingPid; + + // AppMgrClient + static int32_t getRunningProcessInfoRet; + static int32_t processState; + static bool isPreForeground; + + // system::GetBoolParameter + static bool isDeveloperMode; + + // ModularObjectExtensionRdbStorageMgr + static int32_t queryDataRet; + static bool extensionFound; + static bool extensionDisabled; + + // BundleMgrHelper + static bool bundleMgrHelperNull; + static int32_t getNameAndIndexRet; + static int32_t getOsAccountRet; + static bool getApplicationInfoRet; + + // AbilityManagerService + static bool amsNull; + static bool isSceneBoardEnabled; + static bool hasRunningUIAbility; + static bool hasRunningUIExtension; + + // MissionListManager + static bool missionListMgrNull; + // UIAbilityManager + static bool uiAbilityMgrNull; + // UIExtensionAbilityManager + static bool uiExtMgrNull; +}; + +#endif // MOCK_FLAG_H diff --git a/test/unittest/modular_object_utils_test/mock/include/modular_object_extension_info.h b/test/unittest/modular_object_utils_test/mock/include/modular_object_extension_info.h new file mode 100644 index 0000000000..f17edfef05 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/modular_object_extension_info.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_EXTENSION_INFO_H +#define MOCK_MODULAR_OBJECT_EXTENSION_INFO_H + +#include +#include + +namespace OHOS { +namespace AAFwk { + +enum class MoeLaunchMode { IN_PROCESS = 0, CROSS_PROCESS = 1 }; +enum class MoeThreadMode { BUNDLE = 0, TYPE = 1, INSTANCE = 2 }; +enum class MoeProcessMode { BUNDLE = 0, TYPE = 1, INSTANCE = 2 }; + +struct ModularObjectExtensionInfo { + std::string bundleName; + std::string moduleName; + std::string abilityName; + int32_t appIndex = 0; + MoeLaunchMode launchMode = MoeLaunchMode::IN_PROCESS; + MoeProcessMode processMode = MoeProcessMode::BUNDLE; + MoeThreadMode threadMode = MoeThreadMode::BUNDLE; + bool isDisabled = false; +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_EXTENSION_INFO_H diff --git a/test/unittest/modular_object_utils_test/mock/include/modular_object_rdb_storage_mgr.h b/test/unittest/modular_object_utils_test/mock/include/modular_object_rdb_storage_mgr.h new file mode 100644 index 0000000000..4a32a6de34 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/modular_object_rdb_storage_mgr.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026 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 MOCK_MODULAR_OBJECT_RDB_STORAGE_MGR_H +#define MOCK_MODULAR_OBJECT_RDB_STORAGE_MGR_H + +#include +#include +#include "mock_flag.h" +#include "modular_object_extension_info.h" + +namespace OHOS { +namespace AbilityRuntime { + +class ModularObjectExtensionRdbStorageMgr + : public std::enable_shared_from_this { + DECLARE_DELAYED_SINGLETON(ModularObjectExtensionRdbStorageMgr); +public: + int32_t QueryData(const std::string &key, std::vector &infos) + { + if (MockFlag::queryDataRet != 0) { + return MockFlag::queryDataRet; + } + if (MockFlag::extensionFound) { + AAFwk::ModularObjectExtensionInfo info; + info.bundleName = "com.test.bundle"; + info.abilityName = "TestAbility"; + info.isDisabled = MockFlag::extensionDisabled; + infos.push_back(info); + } + return 0; + } + int32_t InsertOrUpdateData(const std::string &key, + const std::vector &infos, uint32_t versionCode) + { + return 0; + } + int32_t DeleteData(const std::string &key) { return 0; } + bool QueryVersion(const std::string &key, uint32_t &versionCode) { return false; } +}; + +} // namespace AbilityRuntime +} // namespace OHOS + +// Bring into AAFwk namespace for source compatibility +namespace OHOS { +namespace AAFwk { +using AbilityRuntime::ModularObjectExtensionRdbStorageMgr; +} // namespace AAFwk +} // namespace OHOS + +#endif // MOCK_MODULAR_OBJECT_RDB_STORAGE_MGR_H diff --git a/test/unittest/modular_object_utils_test/mock/include/modular_object_utils.h b/test/unittest/modular_object_utils_test/mock/include/modular_object_utils.h new file mode 100644 index 0000000000..88db93ac0e --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/modular_object_utils.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026 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_MODULAR_OBJECT_UTILS_H +#define OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_UTILS_H + +#include +#include + +#include "ability_record/ability_request.h" +#include "modular_object_extension_info.h" + +namespace OHOS { +namespace AAFwk { + +class ModularObjectUtils { +public: + ModularObjectUtils() = delete; + + static int32_t CheckPermission(const AbilityRequest &abilityRequest); + + static int32_t CheckExtensionEnabled(const ModularObjectExtensionInfo &info, + const AbilityRequest &abilityRequest); + static int32_t CheckCallerForeground(); + static int32_t CheckAppDistributionType(const std::string &callerAppDistributionType, + const std::string &targetAppDistributionType); + static bool HasRunningUIAbilityOrExtension(int32_t targetUid, int32_t userId); + static int32_t CheckTargetHasRunningAbility(int32_t targetUid, int32_t userId, + const std::string &targetBundleName); + static int32_t GetTargetExtensionInfoFromDb(const std::string &bundleName, + const std::string &abilityName, int32_t appIndex, int32_t validUserId, + ModularObjectExtensionInfo &targetExtensionInfo); + static int32_t GetCallerAppInfo(AppExecFwk::ApplicationInfo &callerAppInfo); +}; + +} // namespace AAFwk +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_MODULAR_OBJECT_UTILS_H diff --git a/test/unittest/modular_object_utils_test/mock/include/os_account_manager_wrapper.h b/test/unittest/modular_object_utils_test/mock/include/os_account_manager_wrapper.h new file mode 100644 index 0000000000..0edbcceb0d --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/os_account_manager_wrapper.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2026 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 MOCK_OS_ACCOUNT_MANAGER_WRAPPER_H +#define MOCK_OS_ACCOUNT_MANAGER_WRAPPER_H + +#include +#include "mock_flag.h" + +namespace OHOS { +namespace AppExecFwk { + +class OsAccountManagerWrapper { + DECLARE_DELAYED_SINGLETON(OsAccountManagerWrapper); +public: + int32_t GetOsAccountLocalIdFromUid(int32_t uid, int32_t &id) + { + if (MockFlag::getOsAccountRet != 0) { + return MockFlag::getOsAccountRet; + } + id = 100; + return 0; + } +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_OS_ACCOUNT_MANAGER_WRAPPER_H diff --git a/test/unittest/modular_object_utils_test/mock/include/parameters.h b/test/unittest/modular_object_utils_test/mock/include/parameters.h new file mode 100644 index 0000000000..9e1a8280ff --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/parameters.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 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 MOCK_PARAMETERS_H +#define MOCK_PARAMETERS_H + +#include +#include "mock_flag.h" + +namespace OHOS { +namespace system { +inline bool GetBoolParameter(const std::string &key, bool defaultValue) +{ + (void)key; + (void)defaultValue; + return MockFlag::isDeveloperMode; +} +} // namespace system +} // namespace OHOS + +#endif // MOCK_PARAMETERS_H diff --git a/test/unittest/modular_object_utils_test/mock/include/running_process_info.h b/test/unittest/modular_object_utils_test/mock/include/running_process_info.h new file mode 100644 index 0000000000..67bc3fd4ef --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/running_process_info.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026 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 MOCK_RUNNING_PROCESS_INFO_H +#define MOCK_RUNNING_PROCESS_INFO_H + +#include + +namespace OHOS { +namespace AppExecFwk { + +enum class AppProcessState { + APP_STATE_BEGIN = 0, + APP_STATE_READY = 1, + APP_STATE_FOREGROUND = 2, + APP_STATE_BACKGROUND = 4, + APP_STATE_END +}; + +struct RunningProcessInfo { + AppProcessState state_ = AppProcessState::APP_STATE_FOREGROUND; + bool isPreForeground = false; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // MOCK_RUNNING_PROCESS_INFO_H diff --git a/test/unittest/modular_object_utils_test/mock/include/scene_board_judgement.h b/test/unittest/modular_object_utils_test/mock/include/scene_board_judgement.h new file mode 100644 index 0000000000..1e52f74505 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/scene_board_judgement.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 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 MOCK_SCENE_BOARD_JUDGEMENT_H +#define MOCK_SCENE_BOARD_JUDGEMENT_H + +#include "mock_flag.h" + +namespace OHOS { +namespace Rosen { +class SceneBoardJudgement { +public: + static bool IsSceneBoardEnabled() + { + return MockFlag::isSceneBoardEnabled; + } +}; +} // namespace Rosen +} // namespace OHOS + +#endif // MOCK_SCENE_BOARD_JUDGEMENT_H diff --git a/test/unittest/modular_object_utils_test/mock/include/singleton.h b/test/unittest/modular_object_utils_test/mock/include/singleton.h new file mode 100644 index 0000000000..0acb903bd6 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/include/singleton.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026 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 MOCK_SINGLETON_H +#define MOCK_SINGLETON_H + +#include +#include + +template +class DelayedSingleton { +public: + static std::shared_ptr GetInstance() + { + static std::once_flag onceFlag; + static std::shared_ptr instance; + std::call_once(onceFlag, []() { instance = std::make_shared(); }); + return instance; + } +}; + +#define DECLARE_DELAYED_SINGLETON(cls) \ + friend class DelayedSingleton + +#endif // MOCK_SINGLETON_H diff --git a/test/unittest/modular_object_utils_test/mock/src/mock_flag.cpp b/test/unittest/modular_object_utils_test/mock/src/mock_flag.cpp new file mode 100644 index 0000000000..273438fb43 --- /dev/null +++ b/test/unittest/modular_object_utils_test/mock/src/mock_flag.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 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 "mock_flag.h" + +bool MockFlag::isSupportModularObjectExtension = true; +int32_t MockFlag::callingUid = 1000; +pid_t MockFlag::callingPid = 1234; +int32_t MockFlag::getRunningProcessInfoRet = 0; +int32_t MockFlag::processState = 2; // APP_STATE_FOREGROUND +bool MockFlag::isPreForeground = false; +bool MockFlag::isDeveloperMode = false; +int32_t MockFlag::queryDataRet = 0; +bool MockFlag::extensionFound = true; +bool MockFlag::extensionDisabled = false; +bool MockFlag::bundleMgrHelperNull = false; +int32_t MockFlag::getNameAndIndexRet = 0; +int32_t MockFlag::getOsAccountRet = 0; +bool MockFlag::getApplicationInfoRet = true; +bool MockFlag::amsNull = false; +bool MockFlag::isSceneBoardEnabled = true; +bool MockFlag::hasRunningUIAbility = true; +bool MockFlag::hasRunningUIExtension = false; +bool MockFlag::missionListMgrNull = false; +bool MockFlag::uiAbilityMgrNull = false; +bool MockFlag::uiExtMgrNull = false; diff --git a/test/unittest/modular_object_utils_test/modular_object_utils_test.cpp b/test/unittest/modular_object_utils_test/modular_object_utils_test.cpp new file mode 100644 index 0000000000..ef1226c39e --- /dev/null +++ b/test/unittest/modular_object_utils_test/modular_object_utils_test.cpp @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2026 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 "modular_object_utils.h" +#include "ability_manager_errors.h" +#include "mock_flag.h" + +using namespace testing::ext; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; + +namespace { +void ResetFlags() +{ + MockFlag::isSupportModularObjectExtension = true; + MockFlag::callingUid = 1000; + MockFlag::callingPid = 1234; + MockFlag::getRunningProcessInfoRet = 0; + MockFlag::processState = 2; // APP_STATE_FOREGROUND + MockFlag::isPreForeground = false; + MockFlag::isDeveloperMode = false; + MockFlag::queryDataRet = 0; + MockFlag::extensionFound = true; + MockFlag::extensionDisabled = false; + MockFlag::bundleMgrHelperNull = false; + MockFlag::getNameAndIndexRet = 0; + MockFlag::getOsAccountRet = 0; + MockFlag::getApplicationInfoRet = true; + MockFlag::amsNull = false; + MockFlag::isSceneBoardEnabled = true; + MockFlag::hasRunningUIAbility = true; + MockFlag::hasRunningUIExtension = false; + MockFlag::missionListMgrNull = false; + MockFlag::uiAbilityMgrNull = false; + MockFlag::uiExtMgrNull = false; +} +} // namespace + +class ModularObjectUtilsTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() override { ResetFlags(); } + void TearDown() override {} +}; + +// ==================== CheckPermission ==================== + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_001 start"; + // Device not supported + MockFlag::isSupportModularObjectExtension = false; + AbilityRequest request; + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, ERR_CAPABILITY_NOT_SUPPORT); + GTEST_LOG_(INFO) << "CheckPermission_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_002 start"; + // GetTargetExtensionInfoFromDb fails + MockFlag::queryDataRet = -1; + AbilityRequest request; + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, -1); + GTEST_LOG_(INFO) << "CheckPermission_002 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_003 start"; + // Extension not found in db + MockFlag::extensionFound = false; + AbilityRequest request; + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, INNER_ERR); + GTEST_LOG_(INFO) << "CheckPermission_003 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_004 start"; + // Extension disabled and different uid + MockFlag::extensionFound = true; + MockFlag::extensionDisabled = true; + MockFlag::callingUid = 999; // different from request.uid + AbilityRequest request; + request.uid = 100; + request.want.SetElement(ElementName("", "com.test.bundle", "TestAbility")); + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, ERR_MODULAR_OBJECT_DISABLED); + GTEST_LOG_(INFO) << "CheckPermission_004 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_005, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_005 start"; + // Caller not foreground + MockFlag::processState = 4; // APP_STATE_BACKGROUND + AbilityRequest request; + request.uid = 100; + request.want.SetElement(ElementName("", "com.test.bundle", "TestAbility")); + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, NOT_TOP_ABILITY); + GTEST_LOG_(INFO) << "CheckPermission_005 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_006, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_006 start"; + // Caller is preForeground + MockFlag::isPreForeground = true; + AbilityRequest request; + request.uid = 100; + request.want.SetElement(ElementName("", "com.test.bundle", "TestAbility")); + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, NOT_TOP_ABILITY); + GTEST_LOG_(INFO) << "CheckPermission_006 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_007, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_007 start"; + // GetCallerAppInfo fails - BundleMgrHelper GetNameAndIndexForUid fails + MockFlag::getNameAndIndexRet = -1; + AbilityRequest request; + request.uid = 100; + request.want.SetElement(ElementName("", "com.test.bundle", "TestAbility")); + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, INNER_ERR); + GTEST_LOG_(INFO) << "CheckPermission_007 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_008, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_008 start"; + // Distribution type check - caller is "none", not developer mode + MockFlag::isDeveloperMode = false; + AbilityRequest request; + request.uid = 1000; + request.want.SetElement(ElementName("", "com.test.bundle", "TestAbility")); + request.appInfo.appDistributionType = "none"; + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, ERR_PERMISSION_DENIED); + GTEST_LOG_(INFO) << "CheckPermission_008 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_009, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_009 start"; + // Distribution type check - target is "none" + MockFlag::isDeveloperMode = false; + MockFlag::hasRunningUIAbility = false; + AbilityRequest request; + request.uid = 1000; + request.want.SetElement(ElementName("", "com.test.bundle", "TestAbility")); + request.appInfo.appDistributionType = "debug"; + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, ERR_NO_RUNNING_ABILITIES_WITH_UI); + GTEST_LOG_(INFO) << "CheckPermission_009 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckPermission_010, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckPermission_010 start"; + // Target has no running ability + MockFlag::hasRunningUIAbility = false; + MockFlag::hasRunningUIExtension = false; + AbilityRequest request; + request.uid = 1000; + request.want.SetElement(ElementName("", "com.test.bundle", "TestAbility")); + auto ret = ModularObjectUtils::CheckPermission(request); + EXPECT_EQ(ret, ERR_NO_RUNNING_ABILITIES_WITH_UI); + GTEST_LOG_(INFO) << "CheckPermission_010 end"; +} + +// ==================== CheckAppDistributionType ==================== + +HWTEST_F(ModularObjectUtilsTest, CheckAppDistributionType_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckAppDistributionType_001 start"; + // Developer mode - allow + MockFlag::isDeveloperMode = true; + auto ret = ModularObjectUtils::CheckAppDistributionType("none", "none"); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "CheckAppDistributionType_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckAppDistributionType_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckAppDistributionType_002 start"; + // Caller distribution type is "none" + MockFlag::isDeveloperMode = false; + auto ret = ModularObjectUtils::CheckAppDistributionType("none", "debug"); + EXPECT_EQ(ret, ERR_PERMISSION_DENIED); + GTEST_LOG_(INFO) << "CheckAppDistributionType_002 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckAppDistributionType_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckAppDistributionType_003 start"; + // Target distribution type is "none" + MockFlag::isDeveloperMode = false; + auto ret = ModularObjectUtils::CheckAppDistributionType("debug", "none"); + EXPECT_EQ(ret, ERR_PERMISSION_DENIED); + GTEST_LOG_(INFO) << "CheckAppDistributionType_003 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckAppDistributionType_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckAppDistributionType_004 start"; + // Normal - both have valid distribution types + MockFlag::isDeveloperMode = false; + auto ret = ModularObjectUtils::CheckAppDistributionType("debug", "release"); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "CheckAppDistributionType_004 end"; +} + +// ==================== CheckExtensionEnabled ==================== + +HWTEST_F(ModularObjectUtilsTest, CheckExtensionEnabled_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckExtensionEnabled_001 start"; + // Disabled and different uid + MockFlag::callingUid = 999; + ModularObjectExtensionInfo info; + info.isDisabled = true; + info.bundleName = "com.test"; + info.abilityName = "TestAbility"; + AbilityRequest request; + request.uid = 100; + auto ret = ModularObjectUtils::CheckExtensionEnabled(info, request); + EXPECT_EQ(ret, ERR_MODULAR_OBJECT_DISABLED); + GTEST_LOG_(INFO) << "CheckExtensionEnabled_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckExtensionEnabled_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckExtensionEnabled_002 start"; + // Disabled but same uid - should pass + MockFlag::callingUid = 100; + ModularObjectExtensionInfo info; + info.isDisabled = true; + info.bundleName = "com.test"; + info.abilityName = "TestAbility"; + AbilityRequest request; + request.uid = 100; + auto ret = ModularObjectUtils::CheckExtensionEnabled(info, request); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "CheckExtensionEnabled_002 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckExtensionEnabled_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckExtensionEnabled_003 start"; + // Not disabled - should pass regardless of uid + MockFlag::callingUid = 999; + ModularObjectExtensionInfo info; + info.isDisabled = false; + info.bundleName = "com.test"; + info.abilityName = "TestAbility"; + AbilityRequest request; + request.uid = 100; + auto ret = ModularObjectUtils::CheckExtensionEnabled(info, request); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "CheckExtensionEnabled_003 end"; +} + +// ==================== CheckCallerForeground ==================== + +HWTEST_F(ModularObjectUtilsTest, CheckCallerForeground_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckCallerForeground_001 start"; + // GetRunningProcessInfoByPid fails + MockFlag::getRunningProcessInfoRet = -1; + auto ret = ModularObjectUtils::CheckCallerForeground(); + EXPECT_EQ(ret, -1); + GTEST_LOG_(INFO) << "CheckCallerForeground_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckCallerForeground_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckCallerForeground_002 start"; + // Caller not foreground (background state) + MockFlag::processState = 4; // APP_STATE_BACKGROUND + auto ret = ModularObjectUtils::CheckCallerForeground(); + EXPECT_EQ(ret, NOT_TOP_ABILITY); + GTEST_LOG_(INFO) << "CheckCallerForeground_002 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckCallerForeground_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckCallerForeground_003 start"; + // Caller is preForeground + MockFlag::isPreForeground = true; + auto ret = ModularObjectUtils::CheckCallerForeground(); + EXPECT_EQ(ret, NOT_TOP_ABILITY); + GTEST_LOG_(INFO) << "CheckCallerForeground_003 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckCallerForeground_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckCallerForeground_004 start"; + // Caller is foreground + MockFlag::processState = 2; // APP_STATE_FOREGROUND + MockFlag::isPreForeground = false; + auto ret = ModularObjectUtils::CheckCallerForeground(); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "CheckCallerForeground_004 end"; +} + +HWTEST_F(ModularObjectUtilsTest, HasRunningUIAbilityOrExtension_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_001 start"; + // SceneBoard enabled with running UIAbility + MockFlag::isSceneBoardEnabled = true; + MockFlag::hasRunningUIAbility = true; + auto ret = ModularObjectUtils::HasRunningUIAbilityOrExtension(1000, 100); + EXPECT_TRUE(ret); + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, HasRunningUIAbilityOrExtension_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_002 start"; + // SceneBoard enabled, no UIAbility but has UIExtension + MockFlag::isSceneBoardEnabled = true; + MockFlag::hasRunningUIAbility = false; + MockFlag::hasRunningUIExtension = true; + MockFlag::uiExtMgrNull = false; + auto ret = ModularObjectUtils::HasRunningUIAbilityOrExtension(1000, 100); + EXPECT_TRUE(ret); + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_002 end"; +} + +HWTEST_F(ModularObjectUtilsTest, HasRunningUIAbilityOrExtension_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_003 start"; + // No running abilities at all + MockFlag::isSceneBoardEnabled = true; + MockFlag::hasRunningUIAbility = false; + MockFlag::hasRunningUIExtension = false; + MockFlag::uiExtMgrNull = false; + auto ret = ModularObjectUtils::HasRunningUIAbilityOrExtension(1000, 100); + EXPECT_FALSE(ret); + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_003 end"; +} + +HWTEST_F(ModularObjectUtilsTest, HasRunningUIAbilityOrExtension_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_004 start"; + // SceneBoard disabled with running ability via MissionListManager + MockFlag::isSceneBoardEnabled = false; + MockFlag::hasRunningUIAbility = true; + MockFlag::missionListMgrNull = false; + auto ret = ModularObjectUtils::HasRunningUIAbilityOrExtension(1000, 100); + EXPECT_TRUE(ret); + GTEST_LOG_(INFO) << "HasRunningUIAbilityOrExtension_004 end"; +} + +// ==================== CheckTargetHasRunningAbility ==================== + +HWTEST_F(ModularObjectUtilsTest, CheckTargetHasRunningAbility_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckTargetHasRunningAbility_001 start"; + // No running ability + MockFlag::hasRunningUIAbility = false; + MockFlag::hasRunningUIExtension = false; + auto ret = ModularObjectUtils::CheckTargetHasRunningAbility(1000, 100, "com.test"); + EXPECT_EQ(ret, ERR_NO_RUNNING_ABILITIES_WITH_UI); + GTEST_LOG_(INFO) << "CheckTargetHasRunningAbility_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, CheckTargetHasRunningAbility_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CheckTargetHasRunningAbility_002 start"; + // Has running ability + MockFlag::hasRunningUIAbility = true; + auto ret = ModularObjectUtils::CheckTargetHasRunningAbility(1000, 100, "com.test"); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "CheckTargetHasRunningAbility_002 end"; +} + +// ==================== GetTargetExtensionInfoFromDb ==================== + +HWTEST_F(ModularObjectUtilsTest, GetTargetExtensionInfoFromDb_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetTargetExtensionInfoFromDb_001 start"; + // QueryData fails + MockFlag::queryDataRet = -1; + ModularObjectExtensionInfo targetInfo; + auto ret = ModularObjectUtils::GetTargetExtensionInfoFromDb("bundle", "ability", 0, 100, targetInfo); + EXPECT_EQ(ret, -1); + GTEST_LOG_(INFO) << "GetTargetExtensionInfoFromDb_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, GetTargetExtensionInfoFromDb_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetTargetExtensionInfoFromDb_002 start"; + // Extension not found + MockFlag::extensionFound = false; + ModularObjectExtensionInfo targetInfo; + auto ret = ModularObjectUtils::GetTargetExtensionInfoFromDb("bundle", "ability", 0, 100, targetInfo); + EXPECT_EQ(ret, INNER_ERR); + GTEST_LOG_(INFO) << "GetTargetExtensionInfoFromDb_002 end"; +} + +HWTEST_F(ModularObjectUtilsTest, GetTargetExtensionInfoFromDb_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetTargetExtensionInfoFromDb_003 start"; + // Success - extension found + MockFlag::extensionFound = true; + ModularObjectExtensionInfo targetInfo; + auto ret = ModularObjectUtils::GetTargetExtensionInfoFromDb( + "com.test.bundle", "TestAbility", 0, 100, targetInfo); + EXPECT_EQ(ret, ERR_OK); + EXPECT_EQ(targetInfo.bundleName, "com.test.bundle"); + EXPECT_EQ(targetInfo.abilityName, "TestAbility"); + GTEST_LOG_(INFO) << "GetTargetExtensionInfoFromDb_003 end"; +} + +// ==================== GetCallerAppInfo ==================== + +HWTEST_F(ModularObjectUtilsTest, GetCallerAppInfo_001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetCallerAppInfo_001 start"; + // BundleMgrHelper is null - can't easily test since singleton always returns instance + // GetNameAndIndexForUid fails + MockFlag::getNameAndIndexRet = -1; + ApplicationInfo callerAppInfo; + auto ret = ModularObjectUtils::GetCallerAppInfo(callerAppInfo); + EXPECT_EQ(ret, INNER_ERR); + GTEST_LOG_(INFO) << "GetCallerAppInfo_001 end"; +} + +HWTEST_F(ModularObjectUtilsTest, GetCallerAppInfo_002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetCallerAppInfo_002 start"; + // GetOsAccountLocalIdFromUid fails + MockFlag::getOsAccountRet = -1; + ApplicationInfo callerAppInfo; + auto ret = ModularObjectUtils::GetCallerAppInfo(callerAppInfo); + EXPECT_EQ(ret, INNER_ERR); + GTEST_LOG_(INFO) << "GetCallerAppInfo_002 end"; +} + +HWTEST_F(ModularObjectUtilsTest, GetCallerAppInfo_003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetCallerAppInfo_003 start"; + // GetApplicationInfoWithAppIndex fails + MockFlag::getApplicationInfoRet = false; + ApplicationInfo callerAppInfo; + auto ret = ModularObjectUtils::GetCallerAppInfo(callerAppInfo); + EXPECT_EQ(ret, INNER_ERR); + GTEST_LOG_(INFO) << "GetCallerAppInfo_003 end"; +} + +HWTEST_F(ModularObjectUtilsTest, GetCallerAppInfo_004, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "GetCallerAppInfo_004 start"; + // Success + ApplicationInfo callerAppInfo; + auto ret = ModularObjectUtils::GetCallerAppInfo(callerAppInfo); + EXPECT_EQ(ret, ERR_OK); + GTEST_LOG_(INFO) << "GetCallerAppInfo_004 end"; +} diff --git a/test/unittest/ui_extension/extension_record_manager_test/extension_record_manager_test.cpp b/test/unittest/ui_extension/extension_record_manager_test/extension_record_manager_test.cpp index cd5b323046..1e6a995a40 100755 --- a/test/unittest/ui_extension/extension_record_manager_test/extension_record_manager_test.cpp +++ b/test/unittest/ui_extension/extension_record_manager_test/extension_record_manager_test.cpp @@ -245,6 +245,144 @@ HWTEST_F(ExtensionRecordManagerTest, GetActiveUIExtensionList_0100, TestSize.Lev extRecordMgr->GetActiveUIExtensionList("aa", extensionList); } +/** + * @tc.name: GetActiveUIExtensionListByUid_0100 + * @tc.desc: Empty extensionRecords_, should return ERR_OK with empty list. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRecordManagerTest, GetActiveUIExtensionListByUid_0100, TestSize.Level1) +{ + auto extRecordMgr = std::make_shared(0); + ASSERT_NE(extRecordMgr, nullptr); + + std::vector extensionList; + auto result = extRecordMgr->GetActiveUIExtensionListByUid(1000, extensionList); + EXPECT_EQ(result, ERR_OK); + EXPECT_EQ(extensionList.size(), 0); +} + +/** + * @tc.name: GetActiveUIExtensionListByUid_0200 + * @tc.desc: uid match, should add moduleName:name to list. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRecordManagerTest, GetActiveUIExtensionListByUid_0200, TestSize.Level1) +{ + auto extRecordMgr = std::make_shared(0); + ASSERT_NE(extRecordMgr, nullptr); + + AAFwk::AbilityRequest abilityRequest; + abilityRequest.appInfo.bundleName = "com.example.unittest"; + abilityRequest.abilityInfo.name = "MainAbility"; + abilityRequest.abilityInfo.moduleName = "entry"; + abilityRequest.abilityInfo.type = AppExecFwk::AbilityType::EXTENSION; + auto abilityRecord = AAFwk::BaseExtensionRecord::CreateBaseExtensionRecord(abilityRequest); + ASSERT_NE(abilityRecord, nullptr); + int32_t testUid = 2000; + abilityRecord->SetUid(testUid); + auto extRecord = std::make_shared(abilityRecord); + extRecordMgr->AddExtensionRecord(10, extRecord); + + std::vector extensionList; + auto result = extRecordMgr->GetActiveUIExtensionListByUid(testUid, extensionList); + EXPECT_EQ(result, ERR_OK); + EXPECT_EQ(extensionList.size(), 1); + EXPECT_EQ(extensionList[0], std::string("entry") + SEPARATOR + "MainAbility"); +} + +/** + * @tc.name: GetActiveUIExtensionListByUid_0300 + * @tc.desc: uid not match, should return empty list. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRecordManagerTest, GetActiveUIExtensionListByUid_0300, TestSize.Level1) +{ + auto extRecordMgr = std::make_shared(0); + ASSERT_NE(extRecordMgr, nullptr); + + AAFwk::AbilityRequest abilityRequest; + abilityRequest.appInfo.bundleName = "com.example.unittest"; + abilityRequest.abilityInfo.name = "MainAbility"; + abilityRequest.abilityInfo.moduleName = "entry"; + abilityRequest.abilityInfo.type = AppExecFwk::AbilityType::EXTENSION; + auto abilityRecord = AAFwk::BaseExtensionRecord::CreateBaseExtensionRecord(abilityRequest); + ASSERT_NE(abilityRecord, nullptr); + abilityRecord->SetUid(2000); + auto extRecord = std::make_shared(abilityRecord); + extRecordMgr->AddExtensionRecord(10, extRecord); + + std::vector extensionList; + auto result = extRecordMgr->GetActiveUIExtensionListByUid(9999, extensionList); + EXPECT_EQ(result, ERR_OK); + EXPECT_EQ(extensionList.size(), 0); +} + +/** + * @tc.name: GetActiveUIExtensionListByUid_0400 + * @tc.desc: it.second is nullptr, should skip. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRecordManagerTest, GetActiveUIExtensionListByUid_0400, TestSize.Level1) +{ + auto extRecordMgr = std::make_shared(0); + ASSERT_NE(extRecordMgr, nullptr); + + AAFwk::AbilityRequest abilityRequest; + abilityRequest.appInfo.bundleName = "com.example.unittest"; + abilityRequest.abilityInfo.name = "MainAbility"; + abilityRequest.abilityInfo.moduleName = "entry"; + abilityRequest.abilityInfo.type = AppExecFwk::AbilityType::EXTENSION; + auto abilityRecord = AAFwk::BaseExtensionRecord::CreateBaseExtensionRecord(abilityRequest); + ASSERT_NE(abilityRecord, nullptr); + int32_t testUid = 2000; + abilityRecord->SetUid(testUid); + auto extRecord = std::make_shared(abilityRecord); + extRecordMgr->AddExtensionRecord(10, extRecord); + + extRecordMgr->extensionRecords_[11] = nullptr; + + std::vector extensionList; + auto result = extRecordMgr->GetActiveUIExtensionListByUid(testUid, extensionList); + EXPECT_EQ(result, ERR_OK); + EXPECT_EQ(extensionList.size(), 1); +} + +/** + * @tc.name: GetActiveUIExtensionListByUid_0500 + * @tc.desc: it.second->abilityRecord_ is nullptr, should skip. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRecordManagerTest, GetActiveUIExtensionListByUid_0500, TestSize.Level1) +{ + auto extRecordMgr = std::make_shared(0); + ASSERT_NE(extRecordMgr, nullptr); + + AAFwk::AbilityRequest abilityRequest; + abilityRequest.appInfo.bundleName = "com.example.unittest"; + abilityRequest.abilityInfo.name = "MainAbility"; + abilityRequest.abilityInfo.moduleName = "entry"; + abilityRequest.abilityInfo.type = AppExecFwk::AbilityType::EXTENSION; + auto abilityRecord = AAFwk::BaseExtensionRecord::CreateBaseExtensionRecord(abilityRequest); + ASSERT_NE(abilityRecord, nullptr); + int32_t testUid = 2000; + abilityRecord->SetUid(testUid); + auto extRecord = std::make_shared(abilityRecord); + extRecordMgr->AddExtensionRecord(10, extRecord); + + auto extRecordNullAbility = std::make_shared(nullptr); + extRecordMgr->extensionRecords_[11] = extRecordNullAbility; + + std::vector extensionList; + auto result = extRecordMgr->GetActiveUIExtensionListByUid(testUid, extensionList); + EXPECT_EQ(result, ERR_OK); + EXPECT_EQ(extensionList.size(), 1); +} + /** * @tc.name: GetAbilityRecordBySessionInfo_0100 * @tc.desc: GetAbilityRecordBySessionInfo From 72cf26dfe78d40a535ff4c4201b7ce9db21fb51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=BB=E5=9B=BD=E5=86=9B?= Date: Tue, 21 Apr 2026 17:49:41 +0800 Subject: [PATCH 3/9] change contextType to isContextOf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Agent Signed-off-by: 任国军 --- frameworks/ets/ani/ani_common/src/ets_context_utils.cpp | 2 +- frameworks/ets/ets/application/Context.ets | 6 +++--- .../js/napi/app/application_context/application_context.js | 2 +- frameworks/js/napi/app/context/context.js | 2 +- .../js_ability_context_test/js_ability_context_test.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frameworks/ets/ani/ani_common/src/ets_context_utils.cpp b/frameworks/ets/ani/ani_common/src/ets_context_utils.cpp index a723671da8..badf38a1c3 100644 --- a/frameworks/ets/ani/ani_common/src/ets_context_utils.cpp +++ b/frameworks/ets/ani/ani_common/src/ets_context_utils.cpp @@ -295,7 +295,7 @@ void BindNativeFunction(ani_env *aniEnv) ani_native_function {"nativeCreateSystemHspModuleResourceManager", "C{std.core.String}C{std.core.String}" ":C{@ohos.resourceManager.resourceManager.ResourceManager}", reinterpret_cast(ContextUtil::NativeCreateSystemHspModuleResourceManager)}, - ani_native_function {"nativeContextType", + ani_native_function {"nativeIsContextOf", "C{@ohos.app.ability.contextConstant.contextConstant.ContextType}:z", reinterpret_cast(ContextUtil::ContextType)}, }; diff --git a/frameworks/ets/ets/application/Context.ets b/frameworks/ets/ets/application/Context.ets index 8dabe717de..483dade18f 100644 --- a/frameworks/ets/ets/application/Context.ets +++ b/frameworks/ets/ets/application/Context.ets @@ -86,7 +86,7 @@ export default class Context extends BaseContext { destroyRegister.unregister(unregisterToken); } - public native nativeContextType(contextType: contextConstant.ContextType): boolean; + public native nativeIsContextOf(contextType: contextConstant.ContextType): boolean; public native getApplicationContextSync(): ApplicationContext; public native createModuleResourceManagerSync(bundleName: string, moduleName: string): resmgr.ResourceManager; @@ -144,8 +144,8 @@ export default class Context extends BaseContext { }); } - contextType(contextType: contextConstant.ContextType): boolean { - return this.nativeContextType(contextType); + isContextOf(contextType: contextConstant.ContextType): boolean { + return this.nativeIsContextOf(contextType); } createDisplayContext(displayId: long): Context { diff --git a/frameworks/js/napi/app/application_context/application_context.js b/frameworks/js/napi/app/application_context/application_context.js index fd17735cf0..ba10f2af6d 100644 --- a/frameworks/js/napi/app/application_context/application_context.js +++ b/frameworks/js/napi/app/application_context/application_context.js @@ -226,7 +226,7 @@ class ApplicationContext { this.__context_impl__.eventHub = eventHub; } - contextType(contextType) { + isContextOf(contextType) { if (typeof (contextType) !== 'number') { return false; } diff --git a/frameworks/js/napi/app/context/context.js b/frameworks/js/napi/app/context/context.js index c8a0a51bc0..5e02321bc2 100644 --- a/frameworks/js/napi/app/context/context.js +++ b/frameworks/js/napi/app/context/context.js @@ -230,7 +230,7 @@ class Context { this.__context_impl__.eventHub = eventHub; } - contextType(contextType) { + isContextOf(contextType) { if (typeof (contextType) !== 'number') { return false; } diff --git a/test/unittest/js_ability_context_test/js_ability_context_test.cpp b/test/unittest/js_ability_context_test/js_ability_context_test.cpp index 15c8339715..7befb3fc84 100644 --- a/test/unittest/js_ability_context_test/js_ability_context_test.cpp +++ b/test/unittest/js_ability_context_test/js_ability_context_test.cpp @@ -509,7 +509,7 @@ void CreateContextTypeTestEnv(napi_env env, const char* typeStr, napi_value &con void CallContextTypeAndCheck(napi_env env, napi_value contextObj, napi_value contextTypeArg, bool expected) { napi_value funcValue = nullptr; - napi_create_function(env, "contextType", NAPI_AUTO_LENGTH, ContextTypeFunc, nullptr, &funcValue); + napi_create_function(env, "isContextOf", NAPI_AUTO_LENGTH, ContextTypeFunc, nullptr, &funcValue); napi_value result = nullptr; napi_call_function(env, contextObj, funcValue, 1, &contextTypeArg, &result); bool boolResult = false; From 227532f7a7b4c49f8f6ed06c1c8d8e9bf76ecea7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Apr 2026 15:29:30 +0800 Subject: [PATCH 4/9] add client Co-Authored-By:Agent Signed-off-by: unknown --- .../interfaces/cli_tool/BUILD.gn | 1 + .../interfaces/cli_tool/ICliToolManager.idl | 7 + .../cli_tool/include/cli_tool_mgr_client.h | 29 ++ .../interfaces/cli_tool/include/tool_info.h | 18 +- .../cli_tool/include/tool_summary.h | 43 +++ .../cli_tool/src/cli_tool_mgr_client.cpp | 44 +++ .../interfaces/cli_tool/src/tool_info.cpp | 24 -- .../interfaces/cli_tool/src/tool_summary.cpp | 66 ++++ .../climgr/include/cli_tool_manager_service.h | 8 +- .../climgr/src/cli_tool_data_manager.cpp | 4 +- .../climgr/src/cli_tool_manager_service.cpp | 12 +- test/unittest/cli_tool_mgr/BUILD.gn | 1 + .../cli_tool_mgr_client_test.cpp | 73 +++++ .../cli_tool_mgr/tool_summary_test/BUILD.gn | 45 +++ .../tool_summary_test/tool_summary_test.cpp | 289 ++++++++++++++++++ 15 files changed, 612 insertions(+), 52 deletions(-) create mode 100644 cli_tool_framework/interfaces/cli_tool/include/tool_summary.h create mode 100644 cli_tool_framework/interfaces/cli_tool/src/tool_summary.cpp create mode 100644 test/unittest/cli_tool_mgr/tool_summary_test/BUILD.gn create mode 100644 test/unittest/cli_tool_mgr/tool_summary_test/tool_summary_test.cpp diff --git a/cli_tool_framework/interfaces/cli_tool/BUILD.gn b/cli_tool_framework/interfaces/cli_tool/BUILD.gn index 7324d3a37b..2252a10079 100644 --- a/cli_tool_framework/interfaces/cli_tool/BUILD.gn +++ b/cli_tool_framework/interfaces/cli_tool/BUILD.gn @@ -51,6 +51,7 @@ ohos_shared_library("cli_tool_client") { sources = [ "src/cli_tool_mgr_client.cpp", "src/tool_info.cpp", + "src/tool_summary.cpp", ] sources += filter_include(output_values, [ "*.cpp" ]) defines = [ "AMS_LOG_TAG = \"CliToolManager\"" ] diff --git a/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl b/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl index 7130e612f7..91e8c62891 100644 --- a/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl +++ b/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl @@ -13,5 +13,12 @@ * limitations under the License. */ +sequenceable ToolInfo..OHOS.CliTool.ToolInfo; +sequenceable OHOS.CliTool.ToolSummary; + interface OHOS.CliTool.ICliToolManager { + void GetAllToolSummaries([out] ToolSummary[] summaries); + void GetToolInfoByName([in] String name, [out] ToolInfo tool); + void GetAllToolInfos([out] ToolInfo[] tools); + void RegisterTool([in] ToolInfo tool); } diff --git a/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h b/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h index bcdeb77925..084e214af9 100644 --- a/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h +++ b/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h @@ -41,6 +41,35 @@ public: */ ~CliToolMGRClient() = default; + /** + * @brief Get all tool summaries (lightweight for listing) + * @param summaries Output vector of ToolSummary + * @return ErrCode ERR_OK on success + */ + ErrCode GetAllToolSummaries(std::vector &summaries); + + /** + * @brief Get tool information by name + * @param name Tool name + * @param tool Output ToolInfo + * @return ErrCode ERR_OK on success + */ + ErrCode GetToolInfoByName(const std::string &name, ToolInfo &tool); + + /** + * @brief Get all tool infos + * @param tools Output vector of ToolInfo + * @return ErrCode ERR_OK on success + */ + ErrCode GetAllToolInfos(std::vector &tools); + + /** + * @brief Register a CLI tool + * @param tool ToolInfo to register + * @return ErrCode ERR_OK on success + */ + ErrCode RegisterTool(const ToolInfo &tool); + private: CliToolMGRClient() = default; DISALLOW_COPY_AND_MOVE(CliToolMGRClient); diff --git a/cli_tool_framework/interfaces/cli_tool/include/tool_info.h b/cli_tool_framework/interfaces/cli_tool/include/tool_info.h index 630c5e7097..6cfad5dce1 100644 --- a/cli_tool_framework/interfaces/cli_tool/include/tool_info.h +++ b/cli_tool_framework/interfaces/cli_tool/include/tool_info.h @@ -16,6 +16,8 @@ #ifndef OHOS_ABILITY_RUNTIME_TOOL_INFO_H #define OHOS_ABILITY_RUNTIME_TOOL_INFO_H +#include "tool_summary.h" + #include #include #include @@ -55,22 +57,6 @@ public: } }; -/** - * @brief Tool summary information (lightweight for listing) - */ -class ToolSummary : public Parcelable { -public: - std::string name; - std::string version; - std::string description; - - ToolSummary() = default; - ~ToolSummary() = default; - - bool Marshalling(Parcel &parcel) const override; - static ToolSummary *Unmarshalling(Parcel &parcel); -}; - /** * @brief Tool information structure (full version) */ diff --git a/cli_tool_framework/interfaces/cli_tool/include/tool_summary.h b/cli_tool_framework/interfaces/cli_tool/include/tool_summary.h new file mode 100644 index 0000000000..4730583834 --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/include/tool_summary.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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_TOOL_SUMMARY_H +#define OHOS_ABILITY_RUNTIME_TOOL_SUMMARY_H + +#include +#include +#include + +namespace OHOS { +namespace CliTool { +/** + * @brief Tool summary information (lightweight for listing) + */ +class ToolSummary : public Parcelable { +public: + std::string name; + std::string version; + std::string description; + + ToolSummary() = default; + ~ToolSummary() = default; + + bool Marshalling(Parcel &parcel) const override; + static ToolSummary *Unmarshalling(Parcel &parcel); +}; +} // namespace CliTool +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_TOOL_SUMMARY_H diff --git a/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp b/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp index 4d6a511f7b..c85d2c3b99 100644 --- a/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp +++ b/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp @@ -102,5 +102,49 @@ void CliToolMGRClient::ResetProxy(const wptr& remote) proxy_ = nullptr; } } + +ErrCode CliToolMGRClient::GetAllToolSummaries(std::vector &summaries) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + auto proxy = GetCliToolManager(); + if (proxy == nullptr) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "proxy is null"); + return AAFwk::GET_CLI_TOOL_MGR_SERVICE_FAILED; + } + return proxy->GetAllToolSummaries(summaries); +} + +ErrCode CliToolMGRClient::GetToolInfoByName(const std::string &name, ToolInfo &tool) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + auto proxy = GetCliToolManager(); + if (proxy == nullptr) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "proxy is null"); + return AAFwk::GET_CLI_TOOL_MGR_SERVICE_FAILED; + } + return proxy->GetToolInfoByName(name, tool); +} + +ErrCode CliToolMGRClient::GetAllToolInfos(std::vector &tools) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + auto proxy = GetCliToolManager(); + if (proxy == nullptr) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "proxy is null"); + return AAFwk::GET_CLI_TOOL_MGR_SERVICE_FAILED; + } + return proxy->GetAllToolInfos(tools); +} + +ErrCode CliToolMGRClient::RegisterTool(const ToolInfo &tool) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + auto proxy = GetCliToolManager(); + if (proxy == nullptr) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "proxy is null"); + return AAFwk::GET_CLI_TOOL_MGR_SERVICE_FAILED; + } + return proxy->RegisterTool(tool); +} } // namespace CliTool } // namespace OHOS diff --git a/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp b/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp index 48ed61fe74..bc303801cf 100644 --- a/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp +++ b/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp @@ -17,30 +17,6 @@ namespace OHOS { namespace CliTool { -// ToolSummary implementation -bool ToolSummary::Marshalling(Parcel &parcel) const -{ - return parcel.WriteString(name) && - parcel.WriteString(version) && - parcel.WriteString(description); -} - -ToolSummary *ToolSummary::Unmarshalling(Parcel &parcel) -{ - auto *summary = new (std::nothrow) ToolSummary(); - if (summary == nullptr) { - return nullptr; - } - - if (!parcel.ReadString(summary->name) || - !parcel.ReadString(summary->version) || - !parcel.ReadString(summary->description)) { - delete summary; - return nullptr; - } - - return summary; -} // ToolInfo implementation bool ToolInfo::Marshalling(Parcel &parcel) const diff --git a/cli_tool_framework/interfaces/cli_tool/src/tool_summary.cpp b/cli_tool_framework/interfaces/cli_tool/src/tool_summary.cpp new file mode 100644 index 0000000000..b51c9e93b8 --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/src/tool_summary.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2026 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 "tool_summary.h" + +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace CliTool { +bool ToolSummary::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(name)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Write name failed"); + return false; + } + if (!parcel.WriteString(version)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Write version failed"); + return false; + } + if (!parcel.WriteString(description)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Write description failed"); + return false; + } + return true; +} + +ToolSummary *ToolSummary::Unmarshalling(Parcel &parcel) +{ + auto *summary = new (std::nothrow) ToolSummary(); + if (summary == nullptr) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to allocate ToolSummary"); + return nullptr; + } + + if (!parcel.ReadString(summary->name)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Read name failed"); + delete summary; + return nullptr; + } + if (!parcel.ReadString(summary->version)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Read version failed"); + delete summary; + return nullptr; + } + if (!parcel.ReadString(summary->description)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Read description failed"); + delete summary; + return nullptr; + } + + return summary; +} +} // namespace CliTool +} // namespace OHOS diff --git a/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h b/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h index a87ce099d6..9ec0baef79 100644 --- a/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h +++ b/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h @@ -38,22 +38,22 @@ public: /** * @brief Query all available tools */ - int32_t QueryTools(std::vector &tools); + int32_t GetAllToolInfos(std::vector &tools) override; /** * @brief Query tool summaries (lightweight for listing) */ - int32_t QueryToolSummaries(std::vector &summaries); + int32_t GetAllToolSummaries(std::vector &summaries) override; /** * @brief Get tool information by name */ - int32_t GetToolInfoByName(const std::string &name, ToolInfo &tool); + int32_t GetToolInfoByName(const std::string &name, ToolInfo &tool) override; /** * @brief Register a CLI tool */ - int32_t RegisterCliTool(const ToolInfo &tool); + int32_t RegisterTool(const ToolInfo &tool) override; protected: void OnStart() override; diff --git a/cli_tool_framework/services/climgr/src/cli_tool_data_manager.cpp b/cli_tool_framework/services/climgr/src/cli_tool_data_manager.cpp index a4b7e3bc51..a0cb0d2e71 100644 --- a/cli_tool_framework/services/climgr/src/cli_tool_data_manager.cpp +++ b/cli_tool_framework/services/climgr/src/cli_tool_data_manager.cpp @@ -35,9 +35,9 @@ constexpr int32_t CHECK_INTERVAL = 100000; // 100ms constexpr int32_t MAX_TIMES = 5; // 5 * 100ms = 500ms constexpr const char* DEFAULT_REGISTRY_PATH = "/system/bin/cli_tool/cli_tool.json"; -constexpr const char* KV_STORE_APP_ID = "cli_tools_storage"; +constexpr const char* KV_STORE_APP_ID = "cli_tools_db"; constexpr const char* KV_STORE_STORE_ID = "cli_tools_store"; -constexpr const char* CLI_TOOLS_STORAGE_DIR = "/data/service/el1/public/database/ability_manager_service"; +constexpr const char* CLI_TOOLS_STORAGE_DIR = "/data/service/el1/public/database/cli_tool"; const DistributedKv::AppId APP_ID { KV_STORE_APP_ID }; const DistributedKv::StoreId STORE_ID { KV_STORE_STORE_ID }; diff --git a/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp b/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp index be52c2d4c0..e591219648 100644 --- a/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp +++ b/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp @@ -62,15 +62,15 @@ void CliToolManagerService::OnStop() { } -int32_t CliToolManagerService::QueryTools(std::vector &tools) +int32_t CliToolManagerService::GetAllToolInfos(std::vector &tools) { - TAG_LOGI(AAFwkTag::CLI_TOOL, "QueryTools called"); + TAG_LOGI(AAFwkTag::CLI_TOOL, "GetAllToolInfos called"); return CliToolDataManager::GetInstance().GetAllTools(tools); } -int32_t CliToolManagerService::QueryToolSummaries(std::vector &summaries) +int32_t CliToolManagerService::GetAllToolSummaries(std::vector &summaries) { - TAG_LOGI(AAFwkTag::CLI_TOOL, "QueryToolSummaries called"); + TAG_LOGI(AAFwkTag::CLI_TOOL, "GetAllToolSummaries called"); return CliToolDataManager::GetInstance().QueryToolSummaries(summaries); } @@ -80,9 +80,9 @@ int32_t CliToolManagerService::GetToolInfoByName(const std::string &name, ToolIn return CliToolDataManager::GetInstance().GetToolByName(name, tool); } -int32_t CliToolManagerService::RegisterCliTool(const ToolInfo &tool) +int32_t CliToolManagerService::RegisterTool(const ToolInfo &tool) { - TAG_LOGI(AAFwkTag::CLI_TOOL, "RegisterCliTool called, tool name='%{public}s'", tool.name.c_str()); + TAG_LOGI(AAFwkTag::CLI_TOOL, "RegisterTool called, tool name='%{public}s'", tool.name.c_str()); return CliToolDataManager::GetInstance().RegisterTool(tool); } } // namespace CliTool diff --git a/test/unittest/cli_tool_mgr/BUILD.gn b/test/unittest/cli_tool_mgr/BUILD.gn index 46309f78e2..50de4c632f 100644 --- a/test/unittest/cli_tool_mgr/BUILD.gn +++ b/test/unittest/cli_tool_mgr/BUILD.gn @@ -20,6 +20,7 @@ group("unittest") { "cli_tool_mgr_client_test:cli_tool_mgr_client_test", "cli_tool_mgr_service_test:cli_tool_mgr_service_test", "cli_tool_data_manager_test:cli_tool_data_manager_test", + "tool_summary_test:tool_summary_test", ] } diff --git a/test/unittest/cli_tool_mgr/cli_tool_mgr_client_test/cli_tool_mgr_client_test.cpp b/test/unittest/cli_tool_mgr/cli_tool_mgr_client_test/cli_tool_mgr_client_test.cpp index a572c3487d..f28d17b6fc 100644 --- a/test/unittest/cli_tool_mgr/cli_tool_mgr_client_test/cli_tool_mgr_client_test.cpp +++ b/test/unittest/cli_tool_mgr/cli_tool_mgr_client_test/cli_tool_mgr_client_test.cpp @@ -90,5 +90,78 @@ HWTEST_F(CliToolMGRClientTest, ResetProxy_0100, TestSize.Level1) GTEST_LOG_(INFO) << "CliToolMGRClient_ResetProxy_0100 end"; } + +/** + * @tc.name: CliToolMGRClient_GetAllToolSummaries_0100 + * @tc.desc: Test GetAllToolSummaries returns error when proxy is null + * @tc.type: FUNC + */ +HWTEST_F(CliToolMGRClientTest, GetAllToolSummaries_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CliToolMGRClient_GetAllToolSummaries_0100 start"; + + auto& client = CliToolMGRClient::GetInstance(); + std::vector summaries; + ErrCode ret = client.GetAllToolSummaries(summaries); + + EXPECT_NE(ret, -1); + + GTEST_LOG_(INFO) << "CliToolMGRClient_GetAllToolSummaries_0100 end"; +} + +/** + * @tc.name: CliToolMGRClient_GetToolInfoByName_0100 + * @tc.desc: Test GetToolInfoByName returns error when proxy is null + * @tc.type: FUNC + */ +HWTEST_F(CliToolMGRClientTest, GetToolInfoByName_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CliToolMGRClient_GetToolInfoByName_0100 start"; + + auto& client = CliToolMGRClient::GetInstance(); + ToolInfo tool; + ErrCode ret = client.GetToolInfoByName("test_tool", tool); + + EXPECT_NE(ret, -1); + + GTEST_LOG_(INFO) << "CliToolMGRClient_GetToolInfoByName_0100 end"; +} + +/** + * @tc.name: CliToolMGRClient_GetAllToolInfos_0100 + * @tc.desc: Test GetAllToolInfos returns error when proxy is null + * @tc.type: FUNC + */ +HWTEST_F(CliToolMGRClientTest, GetAllToolInfos_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CliToolMGRClient_GetAllToolInfos_0100 start"; + + auto& client = CliToolMGRClient::GetInstance(); + std::vector tools; + ErrCode ret = client.GetAllToolInfos(tools); + + EXPECT_NE(ret, -1); + + GTEST_LOG_(INFO) << "CliToolMGRClient_GetAllToolInfos_0100 end"; +} + +/** + * @tc.name: CliToolMGRClient_RegisterTool_0100 + * @tc.desc: Test RegisterTool returns error when proxy is null + * @tc.type: FUNC + */ +HWTEST_F(CliToolMGRClientTest, RegisterTool_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CliToolMGRClient_RegisterTool_0100 start"; + + auto& client = CliToolMGRClient::GetInstance(); + ToolInfo tool; + tool.name = "test_tool"; + ErrCode ret = client.RegisterTool(tool); + + EXPECT_NE(ret, -1); + + GTEST_LOG_(INFO) << "CliToolMGRClient_RegisterTool_0100 end"; +} } // namespace CliTool } // namespace OHOS diff --git a/test/unittest/cli_tool_mgr/tool_summary_test/BUILD.gn b/test/unittest/cli_tool_mgr/tool_summary_test/BUILD.gn new file mode 100644 index 0000000000..63a14d1207 --- /dev/null +++ b/test/unittest/cli_tool_mgr/tool_summary_test/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright (c) 2026 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/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +module_output_path = "ability_runtime/ability_runtime/clitool" + +ohos_unittest("tool_summary_test") { + module_out_path = module_output_path + + include_dirs = [ "${cli_tool_framework_path}/interfaces/cli_tool/include" ] + + sources = [ "tool_summary_test.cpp" ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-BINDER_IPC_32BIT" ] + } + + deps = [ "${cli_tool_framework_path}/interfaces/cli_tool:cli_tool_client" ] + + external_deps = [ + "c_utils:utils", + "googletest:gmock_main", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":tool_summary_test" ] +} diff --git a/test/unittest/cli_tool_mgr/tool_summary_test/tool_summary_test.cpp b/test/unittest/cli_tool_mgr/tool_summary_test/tool_summary_test.cpp new file mode 100644 index 0000000000..2978b386af --- /dev/null +++ b/test/unittest/cli_tool_mgr/tool_summary_test/tool_summary_test.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2026 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 +#include + +#include "tool_summary.h" + +using namespace testing::ext; + +namespace OHOS { +namespace CliTool { + +class MockParcel : public Parcel { +public: + MockParcel() = default; + ~MockParcel() = default; +}; + +class ToolSummaryTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void ToolSummaryTest::SetUpTestCase(void) {} +void ToolSummaryTest::TearDownTestCase(void) {} +void ToolSummaryTest::SetUp() {} +void ToolSummaryTest::TearDown() {} + +/** + * @tc.name: ToolSummary_Marshalling_0100 + * @tc.desc: Test Marshalling success + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Marshalling_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_0100 start"; + + ToolSummary summary; + summary.name = "test_tool"; + summary.version = "1.0.0"; + summary.description = "test description"; + + Parcel parcel; + bool ret = summary.Marshalling(parcel); + + EXPECT_TRUE(ret); + + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_0100 end"; +} + +/** + * @tc.name: ToolSummary_Marshalling_0200 + * @tc.desc: Test Marshalling with empty strings + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Marshalling_0200, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_0200 start"; + + ToolSummary summary; + summary.name = ""; + summary.version = ""; + summary.description = ""; + + Parcel parcel; + bool ret = summary.Marshalling(parcel); + + EXPECT_TRUE(ret); + + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_0200 end"; +} + +/** + * @tc.name: ToolSummary_Unmarshalling_0100 + * @tc.desc: Test Unmarshalling success + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Unmarshalling_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Unmarshalling_0100 start"; + + ToolSummary summary; + summary.name = "test_tool"; + summary.version = "1.0.0"; + summary.description = "test description"; + + Parcel parcel; + ASSERT_TRUE(summary.Marshalling(parcel)); + + parcel.RewindRead(0); + ToolSummary *result = ToolSummary::Unmarshalling(parcel); + + ASSERT_NE(result, nullptr); + EXPECT_EQ(result->name, "test_tool"); + EXPECT_EQ(result->version, "1.0.0"); + EXPECT_EQ(result->description, "test description"); + + delete result; + + GTEST_LOG_(INFO) << "ToolSummary_Unmarshalling_0100 end"; +} + +/** + * @tc.name: ToolSummary_Unmarshalling_0200 + * @tc.desc: Test Unmarshalling with empty strings + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Unmarshalling_0200, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Unmarshalling_0200 start"; + + ToolSummary summary; + summary.name = ""; + summary.version = ""; + summary.description = ""; + + Parcel parcel; + ASSERT_TRUE(summary.Marshalling(parcel)); + + parcel.RewindRead(0); + ToolSummary *result = ToolSummary::Unmarshalling(parcel); + + ASSERT_NE(result, nullptr); + EXPECT_EQ(result->name, ""); + EXPECT_EQ(result->version, ""); + EXPECT_EQ(result->description, ""); + + delete result; + + GTEST_LOG_(INFO) << "ToolSummary_Unmarshalling_0200 end"; +} + +/** + * @tc.name: ToolSummary_Unmarshalling_0300 + * @tc.desc: Test Unmarshalling fail when parcel read fails + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Unmarshalling_0300, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Unmarshalling_0300 start"; + + Parcel parcel; + // Empty parcel, read will fail + ToolSummary *result = ToolSummary::Unmarshalling(parcel); + + EXPECT_EQ(result, nullptr); + + GTEST_LOG_(INFO) << "ToolSummary_Unmarshalling_0300 end"; +} + +/** + * @tc.name: ToolSummary_Marshalling_Unmarshalling_RoundTrip_0100 + * @tc.desc: Test Marshalling and Unmarshalling round trip + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Marshalling_Unmarshalling_RoundTrip_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0100 start"; + + ToolSummary original; + original.name = "my_tool"; + original.version = "2.0.0"; + original.description = "A test tool for CLI"; + + Parcel parcel; + ASSERT_TRUE(original.Marshalling(parcel)); + + parcel.RewindRead(0); + ToolSummary *restored = ToolSummary::Unmarshalling(parcel); + + ASSERT_NE(restored, nullptr); + EXPECT_EQ(restored->name, original.name); + EXPECT_EQ(restored->version, original.version); + EXPECT_EQ(restored->description, original.description); + + delete restored; + + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0100 end"; +} + +/** + * @tc.name: ToolSummary_Marshalling_Unmarshalling_RoundTrip_0200 + * @tc.desc: Test Marshalling and Unmarshalling with special characters + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Marshalling_Unmarshalling_RoundTrip_0200, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0200 start"; + + ToolSummary original; + original.name = "tool_with_special_chars_!@#$%"; + original.version = "1.0.0-beta+build.123"; + original.description = "Description with\nnew line\tand tab"; + + Parcel parcel; + ASSERT_TRUE(original.Marshalling(parcel)); + + parcel.RewindRead(0); + ToolSummary *restored = ToolSummary::Unmarshalling(parcel); + + ASSERT_NE(restored, nullptr); + EXPECT_EQ(restored->name, original.name); + EXPECT_EQ(restored->version, original.version); + EXPECT_EQ(restored->description, original.description); + + delete restored; + + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0200 end"; +} + +/** + * @tc.name: ToolSummary_Marshalling_Unmarshalling_RoundTrip_0300 + * @tc.desc: Test Marshalling and Unmarshalling with unicode characters + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Marshalling_Unmarshalling_RoundTrip_0300, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0300 start"; + + ToolSummary original; + original.name = "工具名称"; + original.version = "1.0.0"; + original.description = "这是一个测试工具描述"; + + Parcel parcel; + ASSERT_TRUE(original.Marshalling(parcel)); + + parcel.RewindRead(0); + ToolSummary *restored = ToolSummary::Unmarshalling(parcel); + + ASSERT_NE(restored, nullptr); + EXPECT_EQ(restored->name, original.name); + EXPECT_EQ(restored->version, original.version); + EXPECT_EQ(restored->description, original.description); + + delete restored; + + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0300 end"; +} + +/** + * @tc.name: ToolSummary_Marshalling_Unmarshalling_RoundTrip_0400 + * @tc.desc: Test Marshalling and Unmarshalling with long strings + * @tc.type: FUNC + */ +HWTEST_F(ToolSummaryTest, Marshalling_Unmarshalling_RoundTrip_0400, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0400 start"; + + ToolSummary original; + original.name = std::string(1000, 'a'); + original.version = "1.0.0"; + original.description = std::string(2000, 'd'); + + Parcel parcel; + ASSERT_TRUE(original.Marshalling(parcel)); + + parcel.RewindRead(0); + ToolSummary *restored = ToolSummary::Unmarshalling(parcel); + + ASSERT_NE(restored, nullptr); + EXPECT_EQ(restored->name, original.name); + EXPECT_EQ(restored->version, original.version); + EXPECT_EQ(restored->description, original.description); + + delete restored; + + GTEST_LOG_(INFO) << "ToolSummary_Marshalling_Unmarshalling_RoundTrip_0400 end"; +} + +} // namespace CliTool +} // namespace OHOS From 86901067ee771631a71631b7770b6af233541956 Mon Sep 17 00:00:00 2001 From: "DESKTOP-UGVMD4B\\DawnComing" Date: Sat, 18 Apr 2026 17:34:51 +0800 Subject: [PATCH 5/9] =?UTF-8?q?SA=E6=9D=83=E9=99=90=E6=95=B4=E6=94=B9?= =?UTF-8?q?=EF=BC=8C=E4=B8=8B=E7=BA=BF=E7=99=BD=E5=90=8D=E5=8D=95=20Signed?= =?UTF-8?q?-off-by:=20lidongrui=20=20Co-Authored-By?= =?UTF-8?q?:=20lidongrui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/common/include/support_system_ability_permission.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/common/include/support_system_ability_permission.h b/services/common/include/support_system_ability_permission.h index dcfed99729..24e206ad10 100755 --- a/services/common/include/support_system_ability_permission.h +++ b/services/common/include/support_system_ability_permission.h @@ -26,7 +26,7 @@ namespace SupportSystemAbilityPermission { constexpr std::array SUPPORTED_UIDS{1002, 1003, 1004, 1007, 1010, 1013, 1014, 1016, 1017, 1019, 1021, 1022, 1023, 1024, 1027, 1028, 1029, 1032, 1036, 1037, 1043, 1047, 1048, 1065, 1077, 1080, 1088, 1089, 1097, 1098, 1100, 1101, 1102, 1103, 1112, 1113, - 1114, 1115, 1201, 1202, 1250, 2000, 2001, 3001, 3006, 3007, 3009, 3010, 3011, 3012, 3013, 3019, 3020, + 1114, 1115, 1201, 1202, 1250, 2001, 3001, 3006, 3007, 3009, 3010, 3011, 3012, 3013, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3047, 3048, 3049, 3053, 3056, 3058, 3059, 3060, 3061, 3062, 3064, 3065, 3068, 3070, 3071, 3072, 3073, 3074, 3075, 3077, From d35035068dade4d75501f928d9dc3f308a1a9536 Mon Sep 17 00:00:00 2001 From: yangxuguang-huawei Date: Tue, 21 Apr 2026 21:51:49 +0800 Subject: [PATCH 6/9] bugfix: add system-app check for register/update/delete AgentCard Co-Authored-By: Agent Signed-off-by: yangxuguang-huawei --- .../agentmgr/src/agent_manager_service.cpp | 12 +++++++ .../agent_manager_service_test.cpp | 35 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/agent_runtime_framework/services/agentmgr/src/agent_manager_service.cpp b/agent_runtime_framework/services/agentmgr/src/agent_manager_service.cpp index e4cb038fc4..dfe651049e 100644 --- a/agent_runtime_framework/services/agentmgr/src/agent_manager_service.cpp +++ b/agent_runtime_framework/services/agentmgr/src/agent_manager_service.cpp @@ -263,6 +263,10 @@ int32_t AgentManagerService::GetCallerAgentCardByAgentId(const std::string &agen int32_t AgentManagerService::RegisterAgentCard(const AgentCard &card) { + if (!AAFwk::PermissionVerification::GetInstance()->JudgeCallerIsAllowedToUseSystemAPI()) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "caller no system-app, can not use system-api"); + return AAFwk::ERR_NOT_SYSTEM_APP; + } if (!AAFwk::PermissionVerification::GetInstance()->VerifyCallingPermission( AAFwk::PermissionConstants::PERMISSION_MODIFY_AGENT_CARD)) { TAG_LOGE(AAFwkTag::SER_ROUTER, "Permission verification failed"); @@ -273,6 +277,10 @@ int32_t AgentManagerService::RegisterAgentCard(const AgentCard &card) int32_t AgentManagerService::UpdateAgentCard(const AgentCard &card) { + if (!AAFwk::PermissionVerification::GetInstance()->JudgeCallerIsAllowedToUseSystemAPI()) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "caller no system-app, can not use system-api"); + return AAFwk::ERR_NOT_SYSTEM_APP; + } if (!AAFwk::PermissionVerification::GetInstance()->VerifyCallingPermission( AAFwk::PermissionConstants::PERMISSION_MODIFY_AGENT_CARD)) { TAG_LOGE(AAFwkTag::SER_ROUTER, "Permission verification failed"); @@ -283,6 +291,10 @@ int32_t AgentManagerService::UpdateAgentCard(const AgentCard &card) int32_t AgentManagerService::DeleteAgentCard(const std::string &bundleName, const std::string &agentId) { + if (!AAFwk::PermissionVerification::GetInstance()->JudgeCallerIsAllowedToUseSystemAPI()) { + TAG_LOGE(AAFwkTag::SER_ROUTER, "caller no system-app, can not use system-api"); + return AAFwk::ERR_NOT_SYSTEM_APP; + } if (!AAFwk::PermissionVerification::GetInstance()->VerifyCallingPermission( AAFwk::PermissionConstants::PERMISSION_MODIFY_AGENT_CARD)) { TAG_LOGE(AAFwkTag::SER_ROUTER, "Permission verification failed"); diff --git a/test/unittest/agent_runtime_framework/agent_manager_service_test/agent_manager_service_test.cpp b/test/unittest/agent_runtime_framework/agent_manager_service_test/agent_manager_service_test.cpp index 0bc42af5c5..0ddd5d5dec 100644 --- a/test/unittest/agent_runtime_framework/agent_manager_service_test/agent_manager_service_test.cpp +++ b/test/unittest/agent_runtime_framework/agent_manager_service_test/agent_manager_service_test.cpp @@ -600,6 +600,18 @@ HWTEST_F(AgentManagerServiceTest, GetCallerAgentCardByAgentId_005, TestSize.Leve MyFlag::retGetAgentCardByAgentId = ERR_OK; } +/** + * @tc.name : UpdateAgentCard_004 + * @tc.number: UpdateAgentCard_004 + * @tc.desc : Test UpdateAgentCard when caller is not allowed to use system API +*/ +HWTEST_F(AgentManagerServiceTest, UpdateAgentCard_004, TestSize.Level1) +{ + MyFlag::retJudgeCallerIsAllowedToUseSystemAPI = false; + AgentCard card; + EXPECT_EQ(AgentManagerService::GetInstance()->UpdateAgentCard(card), ERR_NOT_SYSTEM_APP); +} + /** * @tc.name : UpdateAgentCard_001 * @tc.number: UpdateAgentCard_001 @@ -613,6 +625,18 @@ HWTEST_F(AgentManagerServiceTest, UpdateAgentCard_001, TestSize.Level1) MyFlag::retVerifyModifyAgentCardPermission = true; } +/** + * @tc.name : RegisterAgentCard_004 + * @tc.number: RegisterAgentCard_004 + * @tc.desc : Test RegisterAgentCard when caller is not allowed to use system API +*/ +HWTEST_F(AgentManagerServiceTest, RegisterAgentCard_004, TestSize.Level1) +{ + MyFlag::retJudgeCallerIsAllowedToUseSystemAPI = false; + AgentCard card; + EXPECT_EQ(AgentManagerService::GetInstance()->RegisterAgentCard(card), ERR_NOT_SYSTEM_APP); +} + /** * @tc.name : RegisterAgentCard_001 * @tc.number: RegisterAgentCard_001 @@ -676,6 +700,17 @@ HWTEST_F(AgentManagerServiceTest, UpdateAgentCard_003, TestSize.Level1) EXPECT_EQ(AgentManagerService::GetInstance()->UpdateAgentCard(card), ERR_OK); } +/** + * @tc.name : DeleteAgentCard_004 + * @tc.number: DeleteAgentCard_004 + * @tc.desc : Test DeleteAgentCard when caller is not allowed to use system API +*/ +HWTEST_F(AgentManagerServiceTest, DeleteAgentCard_004, TestSize.Level1) +{ + MyFlag::retJudgeCallerIsAllowedToUseSystemAPI = false; + EXPECT_EQ(AgentManagerService::GetInstance()->DeleteAgentCard("bundle", "agentId"), ERR_NOT_SYSTEM_APP); +} + /** * @tc.name : DeleteAgentCard_001 * @tc.number: DeleteAgentCard_001 From 2965306d2945c29f24c5c34db1b65214ed0fd5fd Mon Sep 17 00:00:00 2001 From: liuzongze Date: Tue, 21 Apr 2026 21:52:29 +0800 Subject: [PATCH 7/9] =?UTF-8?q?so=E5=AD=90=E7=9B=AE=E5=BD=95fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Agent Signed-off-by: liuzongze Change-Id: Idd5d9b012bcda8bb5937dfa5cae1ffc5626ce35c --- frameworks/native/appkit/app/native_lib_util.cpp | 10 ++++++++++ frameworks/native/runtime/ets_native_lib_util.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/frameworks/native/appkit/app/native_lib_util.cpp b/frameworks/native/appkit/app/native_lib_util.cpp index 4b49b22224..39d878705e 100644 --- a/frameworks/native/appkit/app/native_lib_util.cpp +++ b/frameworks/native/appkit/app/native_lib_util.cpp @@ -49,6 +49,11 @@ void GetHapSoPath(const HapModuleInfo &hapInfo, AppLibPathMap &appLibPaths, bool TAG_LOGD( AAFwkTag::APPKIT, "appLibPathKey: %{private}s, lib path: %{private}s", appLibPathKey.c_str(), libPath.c_str()); appLibPaths[appLibPathKey].emplace_back(libPath); + for (const auto &dir : hapInfo.librarySupportDirectory) { + std::string supportLibPath = libPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths[appLibPathKey].emplace_back(supportLibPath); + } } void GetHspNativeLibPath(const BaseSharedBundleInfo &hspInfo, AppLibPathMap &appLibPaths, bool isPreInstallApp) @@ -109,6 +114,11 @@ void GetPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNativ TAG_LOGD(AAFwkTag::APPKIT, "appLibPathKey: %{public}s, patch lib path: %{private}s", appLibPathKey.c_str(), patchLibPath.c_str()); appLibPaths[appLibPathKey].emplace_back(patchLibPath); + for (const auto &dir : hapInfo.librarySupportDirectory) { + std::string supportLibPath = patchLibPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths[appLibPathKey].emplace_back(supportLibPath); + } } void GetLibrarySupportDirectory( diff --git a/frameworks/native/runtime/ets_native_lib_util.cpp b/frameworks/native/runtime/ets_native_lib_util.cpp index a44b38817d..a043fa09d2 100644 --- a/frameworks/native/runtime/ets_native_lib_util.cpp +++ b/frameworks/native/runtime/ets_native_lib_util.cpp @@ -53,6 +53,11 @@ void GetEtsHapSoPath(const HapModuleInfo &hapInfo, AppLibPathMap &appLibPaths, b TAG_LOGD( AAFwkTag::APPKIT, "appLibPathKey: %{private}s, lib path: %{private}s", appLibPathKey.c_str(), libPath.c_str()); appLibPaths[appLibPathKey].emplace_back(libPath); + for (const auto &dir : hapInfo.librarySupportDirectory) { + std::string supportLibPath = libPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths[appLibPathKey].emplace_back(supportLibPath); + } std::string appLibAbcPathKey = APP_ABC_LIB_PATH_KEY_PREFIX + hapInfo.moduleName + APP_ABC_LIB_PATH_KEY_SUFFIX; abcPathsToBundleModuleNameMap[appLibAbcPathKey] = appLibPathKey; @@ -123,6 +128,11 @@ void GetEtsPatchNativeLibPath(const HapModuleInfo &hapInfo, std::string &patchNa TAG_LOGD(AAFwkTag::APPKIT, "appLibPathKey: %{public}s, patch lib path: %{private}s", appLibPathKey.c_str(), patchLibPath.c_str()); appLibPaths[appLibPathKey].emplace_back(patchLibPath); + for (const auto &dir : hapInfo.librarySupportDirectory) { + std::string supportLibPath = patchLibPath + "/" + dir; + TAG_LOGD(AAFwkTag::APPKIT, "supportLibPath: %{public}s", supportLibPath.c_str()); + appLibPaths[appLibPathKey].emplace_back(supportLibPath); + } std::string appLibAbcPathKey = APP_ABC_LIB_PATH_KEY_PREFIX + hapInfo.moduleName + APP_ABC_LIB_PATH_KEY_SUFFIX; abcPathsToBundleModuleNameMap[appLibAbcPathKey] = appLibPathKey; } From c0af7f98270cc586a594c64932d4f712a718e882 Mon Sep 17 00:00:00 2001 From: wendel Date: Tue, 21 Apr 2026 22:24:01 +0800 Subject: [PATCH 8/9] add exec Signed-off-by: wendel Co-Authored-By: Agent Change-Id: I24e1950f58e3c5092b8dfa632c23502911f006de --- bundle.json | 5 +- cli_tool_framework/frameworks/BUILD.gn | 21 ++ .../js/napi/cli_tool_manager/BUILD.gn | 53 ++++ .../cli_tool_manager/include/js_cli_manager.h | 82 ++++++ .../include/js_cli_manager_utils.h | 68 +++++ .../src/cli_tool_manager_module.cpp | 29 +++ .../cli_tool_manager/src/js_cli_manager.cpp | 137 ++++++++++ .../src/js_cli_manager_utils.cpp | 239 ++++++++++++++++++ .../interfaces/cli_tool/BUILD.gn | 3 + .../interfaces/cli_tool/ICliToolManager.idl | 4 + .../cli_tool/include/cli_session_info.h | 46 ++++ .../cli_tool/include/cli_tool_mgr_client.h | 19 +- .../cli_tool/include/exec_options.h | 43 ++++ .../interfaces/cli_tool/include/exec_result.h | 42 +++ .../interfaces/cli_tool/include/tool_info.h | 58 +---- .../cli_tool/src/cli_session_info.cpp | 87 +++++++ .../cli_tool/src/cli_tool_mgr_client.cpp | 14 + .../interfaces/cli_tool/src/exec_options.cpp | 88 +++++++ .../interfaces/cli_tool/src/exec_result.cpp | 73 ++++++ .../interfaces/cli_tool/src/tool_info.cpp | 99 -------- cli_tool_framework/services/climgr/BUILD.gn | 2 +- .../climgr/include/cli_tool_manager_service.h | 10 + .../climgr/src/cli_tool_manager_service.cpp | 11 + 23 files changed, 1074 insertions(+), 159 deletions(-) create mode 100644 cli_tool_framework/frameworks/BUILD.gn create mode 100644 cli_tool_framework/frameworks/js/napi/cli_tool_manager/BUILD.gn create mode 100644 cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager.h create mode 100644 cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager_utils.h create mode 100644 cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/cli_tool_manager_module.cpp create mode 100644 cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp create mode 100644 cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager_utils.cpp create mode 100644 cli_tool_framework/interfaces/cli_tool/include/cli_session_info.h create mode 100644 cli_tool_framework/interfaces/cli_tool/include/exec_options.h create mode 100644 cli_tool_framework/interfaces/cli_tool/include/exec_result.h create mode 100644 cli_tool_framework/interfaces/cli_tool/src/cli_session_info.cpp create mode 100644 cli_tool_framework/interfaces/cli_tool/src/exec_options.cpp create mode 100644 cli_tool_framework/interfaces/cli_tool/src/exec_result.cpp diff --git a/bundle.json b/bundle.json index 4cc477140e..ac538bff1e 100644 --- a/bundle.json +++ b/bundle.json @@ -127,10 +127,11 @@ "sub_component": [ "//foundation/ability/ability_runtime/agent_runtime_framework/interfaces/inner_api:agent_fwk", "//foundation/ability/ability_runtime/agent_runtime_framework/services:agent_services_target", - "//foundation/ability/ability_runtime/cli_tool_framework/interfaces/cli_tool:cli_tool_client", - "//foundation/ability/ability_runtime/cli_tool_framework/services/climgr:climgr", "//foundation/ability/ability_runtime/cli_tool_framework/etc/profile:aimgr_cfg", "//foundation/ability/ability_runtime/cli_tool_framework/etc/profile:aimgr_trust", + "//foundation/ability/ability_runtime/cli_tool_framework/frameworks:cli_tool_framework_packages", + "//foundation/ability/ability_runtime/cli_tool_framework/interfaces/cli_tool:cli_tool_client", + "//foundation/ability/ability_runtime/cli_tool_framework/services/climgr:climgr", "//foundation/ability/ability_runtime/services:ams_target", "//foundation/ability/ability_runtime/services/sa_profile:ams_sa_profile", "//foundation/ability/ability_runtime/services/quickfixmgr:quick_fix.cfg", diff --git a/cli_tool_framework/frameworks/BUILD.gn b/cli_tool_framework/frameworks/BUILD.gn new file mode 100644 index 0000000000..94800930ed --- /dev/null +++ b/cli_tool_framework/frameworks/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +group("cli_tool_framework_packages") { + deps = [ + "${cli_tool_framework_path}/frameworks/js/napi/cli_tool_manager:clitoolmanager_napi", + ] +} diff --git a/cli_tool_framework/frameworks/js/napi/cli_tool_manager/BUILD.gn b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/BUILD.gn new file mode 100644 index 0000000000..ff2e3ae4cf --- /dev/null +++ b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/BUILD.gn @@ -0,0 +1,53 @@ +# Copyright (c) 2026 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/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("clitoolmanager_napi") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "include", + "${ability_runtime_path}/interfaces/kits/native/ability/ability_runtime", + "${cli_tool_framework_path}/interfaces/cli_tool/include", + ] + + sources = [ + "src/cli_tool_manager_module.cpp", + "src/js_cli_manager.cpp", + "src/js_cli_manager_utils.cpp", + ] + + deps = [ + "${ability_runtime_innerkits_path}/error_utils:ability_runtime_error_util", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_napi_path}/inner/napi_common:napi_common", + "${cli_tool_framework_path}/interfaces/cli_tool:cli_tool_client", + ] + + external_deps = [ + "ability_base:base", + "c_utils:utils", + "hilog:libhilog", + "napi:ace_napi", + ] + + relative_install_dir = "module/app/cli_tool" + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager.h b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager.h new file mode 100644 index 0000000000..6ee5691ee3 --- /dev/null +++ b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2026 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_CLI_TOOL_JS_CLI_MANAGER_H +#define OHOS_CLI_TOOL_JS_CLI_MANAGER_H + +#include +#include +#include + +#include "native_engine/native_engine.h" +#include "refbase.h" + +namespace OHOS { +namespace CliTool { + +/** + * @class JSCliManager + * @brief JS API wrapper for CLI tool management functionality. + * + * Provides native methods for executing CLI tools. + */ +class JSCliManager final { +public: + JSCliManager() {} + ~JSCliManager() {} + + /** + * @brief Finalizer for the JSCliManager object. + * + * @param env The N-API environment. + * @param data The pointer to the JSCliManager instance. + * @param hint The hint data. + */ + static void Finalizer(napi_env env, void *data, void *hint); + + /** + * @brief Native method for executing a CLI tool. + * + * @param env The N-API environment. + * @param info The N-API callback info. + * @return Returns the N-API value. + */ + static napi_value ExecTool(napi_env env, napi_callback_info info); + +private: + /** + * @brief Implementation for executing a CLI tool. + * + * @param env The N-API environment. + * @param argc The argument count. + * @param argv The argument values. + * @return Returns the N-API value. + */ + napi_value OnExecTool(napi_env env, size_t argc, napi_value *argv); +}; + +/** + * @brief Initialize the JSCliManager module. + * + * @param env The N-API environment. + * @param exportObj The export object. + * @return Returns the N-API value. + */ +napi_value JSCliManagerInit(napi_env env, napi_value exportObj); + +} // namespace CliTool +} // namespace OHOS + +#endif // OHOS_CLI_TOOL_JS_CLI_MANAGER_H diff --git a/cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager_utils.h b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager_utils.h new file mode 100644 index 0000000000..3f59f62eb3 --- /dev/null +++ b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager_utils.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026 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_CLI_TOOL_JS_CLI_MANAGER_UTILS_H +#define OHOS_CLI_TOOL_JS_CLI_MANAGER_UTILS_H + +#include +#include + +#include "cli_session_info.h" +#include "exec_options.h" +#include "exec_result.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace CliTool { + +/** + * @brief Unwrap a string map from JavaScript object. + * @param env The N-API environment. + * @param obj The JavaScript object. + * @param values Output key-value pairs. + * @return Returns true on success, false otherwise. + */ +bool UnwrapStringMap(napi_env env, napi_value obj, + std::map &values); + +/** + * @brief Unwrap ExecOptions from JavaScript object. + * @param env The N-API environment. + * @param obj The JavaScript object. + * @param options Output ExecOptions. + * @return Returns true on success, false otherwise. + */ +bool UnwrapExecOptions(napi_env env, napi_value obj, ExecOptions &options); + +/** + * @brief Create JavaScript CliSessionInfo object. + * @param env The N-API environment. + * @param session The CliSessionInfo structure. + * @return Returns the JavaScript object. + */ +napi_value CreateJsCliSessionInfo(napi_env env, const CliSessionInfo &session); + +/** + * @brief Create JavaScript error from native error code. + * @param env The N-API environment. + * @param errCode The native error code. + * @return Returns the JavaScript error object. + */ +napi_value CreateCliJsErrorByNativeErr(napi_env env, int32_t errCode); + +} // namespace CliTool +} // namespace OHOS + +#endif // OHOS_CLI_TOOL_JS_CLI_MANAGER_UTILS_H diff --git a/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/cli_tool_manager_module.cpp b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/cli_tool_manager_module.cpp new file mode 100644 index 0000000000..184bf3a105 --- /dev/null +++ b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/cli_tool_manager_module.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2026 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 "native_engine/native_engine.h" +#include "js_cli_manager.h" + +static napi_module _module = { + .nm_version = 0, + .nm_filename = "app/cli_tool/cli_tool_manager_napi.so/cli_tool_manager.js", + .nm_register_func = OHOS::CliTool::JSCliManagerInit, + .nm_modname = "app.cliTool.cliToolManager", +}; + +extern "C" __attribute__((constructor)) void NAPI_app_cliTool_cliToolManager_AutoRegister(void) +{ + napi_module_register(&_module); +} diff --git a/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp new file mode 100644 index 0000000000..0372927437 --- /dev/null +++ b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2026 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 "js_cli_manager.h" + +#include +#include +#include + +#include "hilog_tag_wrapper.h" +#include "js_cli_manager_utils.h" +#include "js_error_utils.h" +#include "js_runtime_utils.h" +#include "napi/native_api.h" +#include "napi_common_util.h" +#include "cli_tool_mgr_client.h" + +using namespace OHOS::AbilityRuntime; + +namespace OHOS { +namespace CliTool { +namespace { +constexpr int32_t INDEX_ZERO = 0; +constexpr int32_t INDEX_ONE = 1; +constexpr int32_t INDEX_TWO = 2; +constexpr int32_t INDEX_THREE = 3; +} // namespace + +void JSCliManager::Finalizer(napi_env env, void *data, void *hint) +{ + TAG_LOGD(AAFwkTag::CLI_TOOL, "JSCliManager::Finalizer is called"); + std::unique_ptr(static_cast(data)); +} + +napi_value JSCliManager::ExecTool(napi_env env, napi_callback_info info) +{ + GET_CB_INFO_AND_CALL(env, info, JSCliManager, OnExecTool); +} + +napi_value JSCliManager::OnExecTool(napi_env env, size_t argc, napi_value *argv) +{ + TAG_LOGD(AAFwkTag::CLI_TOOL, "JSCliManager::OnExecTool called"); + HandleEscape handleEscape(env); + if (argc < INDEX_THREE) { + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + + std::string name; + if (!AppExecFwk::UnwrapStringFromJS2(env, argv[INDEX_ZERO], name) || name.empty()) { + ThrowInvalidParamError(env, "Tool name is required"); + return CreateJsUndefined(env); + } + + std::map args; + if (!UnwrapStringMap(env, argv[INDEX_ONE], args)) { + ThrowInvalidParamError(env, "Tool args is required"); + return CreateJsUndefined(env); + } + + std::string challenge; + if (!AppExecFwk::UnwrapStringFromJS2(env, argv[INDEX_TWO], challenge)) { + ThrowInvalidParamError(env, "Tool challenge is required"); + return CreateJsUndefined(env); + } + + ExecOptions options; + if (argc > INDEX_THREE && argv[INDEX_THREE] != nullptr) { + if (!UnwrapExecOptions(env, argv[INDEX_THREE], options)) { + ThrowInvalidParamError(env, "Tool options is required"); + return CreateJsUndefined(env); + } + } + + auto innerErrCode = std::make_shared(ERR_OK); + auto session = std::make_shared(); + + NapiAsyncTask::ExecuteCallback execute = [innerErrCode, name, args, challenge, options, session]() { + *innerErrCode = CliToolMGRClient::GetInstance().ExecTool(name, args, challenge, options, *session); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrCode, session]( + napi_env env, NapiAsyncTask &task, int32_t status) { + HandleScope handleScope(env); + if (*innerErrCode != ERR_OK) { + task.Reject(env, CreateCliJsErrorByNativeErr(env, *innerErrCode)); + return; + } + + napi_value jsSession = CreateJsCliSessionInfo(env, *session); + if (jsSession == nullptr) { + task.Reject(env, CreateJsUndefined(env)); + return; + } + + task.ResolveWithNoError(env, jsSession); + }; + + napi_value asyncResult = nullptr; + NapiAsyncTask::Schedule("JsCliManager::OnExecTool", env, + CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &asyncResult)); + return handleEscape.Escape(asyncResult); +} + +napi_value JSCliManagerInit(napi_env env, napi_value exportObj) +{ + TAG_LOGD(AAFwkTag::CLI_TOOL, "Init JSCliManager"); + + if (env == nullptr || exportObj == nullptr) { + TAG_LOGW(AAFwkTag::CLI_TOOL, "Null env or exportObj"); + return nullptr; + } + + std::unique_ptr jsCliManager = std::make_unique(); + napi_wrap(env, exportObj, jsCliManager.release(), JSCliManager::Finalizer, nullptr, nullptr); + + const char *moduleName = "JsCliManager"; + BindNativeFunction(env, exportObj, "execTool", moduleName, JSCliManager::ExecTool); + + TAG_LOGD(AAFwkTag::CLI_TOOL, "JSCliManagerInit end"); + return CreateJsUndefined(env); +} + +} // namespace CliTool +} // namespace OHOS diff --git a/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager_utils.cpp b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager_utils.cpp new file mode 100644 index 0000000000..c6d0b678fe --- /dev/null +++ b/cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager_utils.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2026 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 "js_cli_manager_utils.h" + +#include + +#include "hilog_tag_wrapper.h" +#include "js_error_utils.h" +#include "js_runtime_utils.h" +#include "napi/native_api.h" +#include "napi_common_util.h" +#include "ability_runtime_error_util.h" + +using namespace OHOS::AbilityRuntime; + +namespace OHOS { +namespace CliTool { +namespace { +constexpr int32_t TIME_OUT = 30 * 1000; +} +bool UnwrapStringMap(napi_env env, napi_value obj, + std::map &values) +{ + if (obj == nullptr) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Input object is null"); + return false; + } + + napi_valuetype valueType = napi_undefined; + napi_status status = napi_typeof(env, obj, &valueType); + if (status != napi_ok || valueType != napi_object) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Input is not an object"); + return false; + } + + napi_value propertyNames = nullptr; + if (napi_get_property_names(env, obj, &propertyNames) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to get property names"); + return false; + } + uint32_t propertyCount = 0; + if (napi_get_array_length(env, propertyNames, &propertyCount) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to get array length"); + return false; + } + + values.clear(); + for (uint32_t i = 0; i < propertyCount; i++) { + napi_value key = nullptr; + if (napi_get_element(env, propertyNames, i, &key) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to get element"); + return false; + } + + std::string keyStr; + if (!AppExecFwk::UnwrapStringFromJS2(env, key, keyStr)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to unwrap key"); + return false; + } + + napi_value value = nullptr; + if (napi_get_named_property(env, obj, keyStr.c_str(), &value) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to get value"); + return false; + } + + std::string valueStr; + if (!AppExecFwk::UnwrapStringFromJS2(env, value, valueStr)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to unwrap value"); + return false; + } + + values.emplace(std::make_pair(keyStr, valueStr)); + } + + return true; +} + +bool UnwrapExecOptions(napi_env env, napi_value obj, ExecOptions &options) +{ + if (obj == nullptr) { + // Use default options + options.background = false; + options.yieldMs = 0; + options.timeout = TIME_OUT; + options.workingDir = ""; + return true; + } + + napi_valuetype valueType = napi_undefined; + napi_status status = napi_typeof(env, obj, &valueType); + if (status != napi_ok || valueType != napi_object) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Input is not an object"); + return false; + } + + // Extract background (optional) + napi_value backgroundProp = nullptr; + if (napi_get_named_property(env, obj, "background", &backgroundProp) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "invalid background property"); + return false; + } + if (!AppExecFwk::UnwrapBoolFromJS2(env, backgroundProp, options.background)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "unwrap background failed"); + return false; + } + + // Extract yieldMs (optional) + napi_value yieldMsProp = nullptr; + if (napi_get_named_property(env, obj, "yieldMs", &yieldMsProp) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "invalid yieldMs property"); + return false; + } + if (!AppExecFwk::UnwrapInt32FromJS2(env, yieldMsProp, options.yieldMs)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "unwrap yieldMs failed"); + return false; + } + + // Extract timeout (optional) + napi_value timeoutProp = nullptr; + if (napi_get_named_property(env, obj, "timeout", &timeoutProp) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "invalid timeout property"); + return false; + } + if (!AppExecFwk::UnwrapInt32FromJS2(env, timeoutProp, options.timeout)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "unwrap timeout failed"); + return false; + } + + // Extract workingDir (optional) + napi_value workingDirProp = nullptr; + if (napi_get_named_property(env, obj, "workingDir", &workingDirProp) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "invalid workingDir property"); + return false; + } + if (!AppExecFwk::UnwrapStringFromJS2(env, workingDirProp, options.workingDir)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "unwrap workingDir failed"); + return false; + } + + // Extract env (optional) + napi_value envProp = nullptr; + if (napi_get_named_property(env, obj, "env", &envProp) != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "invalid env property"); + return false; + } + if (!UnwrapStringMap(env, envProp, options.env)) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "unwrap env failed"); + return false; + } + + return true; +} + +napi_value CreateJsCliSessionInfo(napi_env env, const CliSessionInfo &session) +{ + napi_value jsObj = nullptr; + napi_status status = napi_create_object(env, &jsObj); + if (status != napi_ok) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "Failed to create JS object"); + return nullptr; + } + + // Set sessionId + napi_value jsSessionId = AppExecFwk::WrapStringToJS(env, session.sessionId); + napi_set_named_property(env, jsObj, "sessionId", jsSessionId); + + // Set toolName + napi_value jsToolName = AppExecFwk::WrapStringToJS(env, session.toolName); + napi_set_named_property(env, jsObj, "toolName", jsToolName); + + // Set status + napi_value jsStatus = AppExecFwk::WrapStringToJS(env, session.status); + napi_set_named_property(env, jsObj, "status", jsStatus); + + // Set startTime + napi_value jsStartTime = AppExecFwk::WrapInt64ToJS(env, session.startTime); + napi_set_named_property(env, jsObj, "startTime", jsStartTime); + + // Set endTime + napi_value jsEndTime = AppExecFwk::WrapInt64ToJS(env, session.endTime); + napi_set_named_property(env, jsObj, "endTime", jsEndTime); + + // Set result if present + if (session.result != nullptr) { + napi_value jsResult = nullptr; + status = napi_create_object(env, &jsResult); + if (status == napi_ok) { + // Set exitCode + napi_value jsExitCode = AppExecFwk::WrapInt32ToJS(env, session.result->exitCode); + napi_set_named_property(env, jsResult, "exitCode", jsExitCode); + + // Set outputText + napi_value jsOutputText = AppExecFwk::WrapStringToJS(env, session.result->outputText); + napi_set_named_property(env, jsResult, "outputText", jsOutputText); + + // Set errorText + napi_value jsErrorText = AppExecFwk::WrapStringToJS(env, session.result->errorText); + napi_set_named_property(env, jsResult, "errorText", jsErrorText); + + // Set signalNumber + napi_value jsSignalNumber = AppExecFwk::WrapInt32ToJS(env, session.result->signalNumber); + napi_set_named_property(env, jsResult, "signalNumber", jsSignalNumber); + + // Set timedOut + napi_value jsTimedOut = AppExecFwk::WrapBoolToJS(env, session.result->timedOut); + napi_set_named_property(env, jsResult, "timedOut", jsTimedOut); + + // Set executionTime + napi_value jsExecutionTime = AppExecFwk::WrapInt64ToJS(env, session.result->executionTime); + napi_set_named_property(env, jsResult, "executionTime", jsExecutionTime); + + napi_set_named_property(env, jsObj, "result", jsResult); + } + } + + return jsObj; +} + +napi_value CreateCliJsErrorByNativeErr(napi_env env, int32_t errCode) +{ + return CreateJsErrorByNativeErr(env, errCode); +} + +} // namespace CliTool +} // namespace OHOS diff --git a/cli_tool_framework/interfaces/cli_tool/BUILD.gn b/cli_tool_framework/interfaces/cli_tool/BUILD.gn index 2252a10079..267f475008 100644 --- a/cli_tool_framework/interfaces/cli_tool/BUILD.gn +++ b/cli_tool_framework/interfaces/cli_tool/BUILD.gn @@ -49,7 +49,10 @@ ohos_shared_library("cli_tool_client") { output_values = get_target_outputs(":cli_tool_manager_interface") sources = [ + "src/cli_session_info.cpp", "src/cli_tool_mgr_client.cpp", + "src/exec_options.cpp", + "src/exec_result.cpp", "src/tool_info.cpp", "src/tool_summary.cpp", ] diff --git a/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl b/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl index 91e8c62891..4449058984 100644 --- a/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl +++ b/cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl @@ -15,10 +15,14 @@ sequenceable ToolInfo..OHOS.CliTool.ToolInfo; sequenceable OHOS.CliTool.ToolSummary; +sequenceable ExecOptions..OHOS.CliTool.ExecOptions; +sequenceable CliSessionInfo..OHOS.CliTool.CliSessionInfo; interface OHOS.CliTool.ICliToolManager { void GetAllToolSummaries([out] ToolSummary[] summaries); void GetToolInfoByName([in] String name, [out] ToolInfo tool); void GetAllToolInfos([out] ToolInfo[] tools); void RegisterTool([in] ToolInfo tool); + void ExecTool([in] String cliName, [in] OrderedMap args, + [in] String challenge, [in] ExecOptions options, [out] CliSessionInfo session); } diff --git a/cli_tool_framework/interfaces/cli_tool/include/cli_session_info.h b/cli_tool_framework/interfaces/cli_tool/include/cli_session_info.h new file mode 100644 index 0000000000..ff72235b9e --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/include/cli_session_info.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2026 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_CLI_SESSION_INFO_H +#define OHOS_ABILITY_RUNTIME_CLI_SESSION_INFO_H + +#include + +#include "exec_result.h" +#include "parcel.h" + +namespace OHOS { +namespace CliTool { +/** + * @struct CliSessionInfo + * @brief Information about a CLI tool execution session. + */ +class CliSessionInfo : public Parcelable { +public: + std::string sessionId; + std::string toolName; + std::string status; // "running", "completed", "failed" + int64_t startTime; + int64_t endTime; + std::shared_ptr result; // optional, only when status="completed" + + CliSessionInfo() = default; + + bool Marshalling(Parcel &parcel) const; + static CliSessionInfo *Unmarshalling(Parcel &parcel); +}; +} // namespace CliTool +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_CLI_SESSION_INFO_H diff --git a/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h b/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h index 084e214af9..d5503ce563 100644 --- a/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h +++ b/cli_tool_framework/interfaces/cli_tool/include/cli_tool_mgr_client.h @@ -18,6 +18,8 @@ #include +#include "cli_session_info.h" +#include "exec_options.h" #include "icli_tool_manager.h" namespace OHOS { @@ -70,6 +72,21 @@ public: */ ErrCode RegisterTool(const ToolInfo &tool); + /** + * @brief Execute a CLI tool with key-value pairs (convenience method). + * @param name The CLI tool name. + * @param args The tool arguments as key-value pairs. + * @param challenge Optional challenge string. + * @param options Execution options. + * @param session Output session information. + * @return Returns ERR_OK on success, error code otherwise. + */ + int32_t ExecTool(const std::string &name, + const std::map &args, + const std::string &challenge, + const ExecOptions &options, + CliSessionInfo &session); + private: CliToolMGRClient() = default; DISALLOW_COPY_AND_MOVE(CliToolMGRClient); @@ -82,7 +99,7 @@ private: private: DISALLOW_COPY_AND_MOVE(CliSaDeathRecipient); }; - + sptr GetCliToolManager(); ErrCode Connect(); /** diff --git a/cli_tool_framework/interfaces/cli_tool/include/exec_options.h b/cli_tool_framework/interfaces/cli_tool/include/exec_options.h new file mode 100644 index 0000000000..b8e12d4624 --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/include/exec_options.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026 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_EXEC_OPTIONS_H +#define OHOS_ABILITY_RUNTIME_EXEC_OPTIONS_H + +#include +#include + +#include "parcel.h" + +namespace OHOS { +namespace CliTool { +/** + * @struct ExecOptions + * @brief Options for executing CLI tools. + */ +class ExecOptions : public Parcelable { +public: + bool background; + int32_t yieldMs; + int32_t timeout; + std::map env; + std::string workingDir; + + bool Marshalling(Parcel &parcel) const; + static ExecOptions *Unmarshalling(Parcel &parcel); +}; +} // namespace CliTool +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_EXEC_OPTIONS_H diff --git a/cli_tool_framework/interfaces/cli_tool/include/exec_result.h b/cli_tool_framework/interfaces/cli_tool/include/exec_result.h new file mode 100644 index 0000000000..d238dfbcb7 --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/include/exec_result.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2026 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_EXEC_RESULT_H +#define OHOS_ABILITY_RUNTIME_EXEC_RESULT_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace CliTool { +/** + * @brief Tool execution result + */ +class ExecResult : public Parcelable { +public: + int32_t exitCode; + std::string outputText; + std::string errorText; + int32_t signalNumber; + bool timedOut; + int64_t executionTime; + + bool Marshalling(Parcel &parcel) const; + static ExecResult *Unmarshalling(Parcel &parcel); +}; +} // namespace CliTool +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_EXEC_RESULT_H diff --git a/cli_tool_framework/interfaces/cli_tool/include/tool_info.h b/cli_tool_framework/interfaces/cli_tool/include/tool_info.h index 6cfad5dce1..a4f1e3e609 100644 --- a/cli_tool_framework/interfaces/cli_tool/include/tool_info.h +++ b/cli_tool_framework/interfaces/cli_tool/include/tool_info.h @@ -26,6 +26,8 @@ #include #include +#include "exec_result.h" + namespace OHOS { namespace CliTool { /** @@ -85,62 +87,6 @@ public: static ToolInfo *Unmarshalling(Parcel &parcel); }; -/** - * @brief Tool execution options - */ -class ExecOptions : public Parcelable { -public: - bool background = false; // true: async, false: sync with yieldMs timeout - int32_t yieldMs = 30000; // foreground wait timeout (only when background=false) - int32_t timeout = 0; // total execution timeout (0 = use tool default) - std::map env; - std::string workingDir; - - ExecOptions() = default; - ~ExecOptions() = default; - - bool Marshalling(Parcel &parcel) const override; - static ExecOptions *Unmarshalling(Parcel &parcel); -}; - -/** - * @brief Tool execution result - */ -class ExecResult : public Parcelable { -public: - int32_t exitCode = 0; - std::string outputText; - std::string errorText; - int32_t signalNumber = 0; - bool timedOut = false; - int64_t executionTime = 0; - - ExecResult() = default; - ~ExecResult() = default; - - bool Marshalling(Parcel &parcel) const override; - static ExecResult *Unmarshalling(Parcel &parcel); -}; - -/** - * @brief Session information - */ -class SessionInfo : public Parcelable { -public: - std::string sessionId; - std::string toolName; - std::string status; // "running", "completed", "failed" - int64_t startTime = 0; - int64_t endTime = 0; - std::shared_ptr result; // optional, only when status="completed" - - SessionInfo() = default; - ~SessionInfo() = default; - - bool Marshalling(Parcel &parcel) const override; - static SessionInfo *Unmarshalling(Parcel &parcel); -}; - /** * @brief Tool event (for async mode) */ diff --git a/cli_tool_framework/interfaces/cli_tool/src/cli_session_info.cpp b/cli_tool_framework/interfaces/cli_tool/src/cli_session_info.cpp new file mode 100644 index 0000000000..77b987ec8c --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/src/cli_session_info.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026 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 "cli_session_info.h" + +namespace OHOS { +namespace CliTool { +bool CliSessionInfo::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(sessionId)) { + return false; + } + if (!parcel.WriteString(toolName)) { + return false; + } + if (!parcel.WriteString(status)) { + return false; + } + if (!parcel.WriteInt64(startTime)) { + return false; + } + if (!parcel.WriteInt64(endTime)) { + return false; + } + // Write result presence flag + bool hasResult = (result != nullptr); + if (!parcel.WriteBool(hasResult)) { + return false; + } + if (hasResult && !result->Marshalling(parcel)) { + return false; + } + return true; +} + +CliSessionInfo *CliSessionInfo::Unmarshalling(Parcel &parcel) +{ + auto *info = new (std::nothrow) CliSessionInfo(); + if (info && !parcel.ReadString(info->sessionId)) { + delete info; + return nullptr; + } + if (!parcel.ReadString(info->toolName)) { + delete info; + return nullptr; + } + if (!parcel.ReadString(info->status)) { + delete info; + return nullptr; + } + if (!parcel.ReadInt64(info->startTime)) { + delete info; + return nullptr; + } + if (!parcel.ReadInt64(info->endTime)) { + delete info; + return nullptr; + } + bool hasResult = false; + if (!parcel.ReadBool(hasResult)) { + delete info; + return nullptr; + } + if (hasResult) { + ExecResult *resultPtr = ExecResult::Unmarshalling(parcel); + if (resultPtr == nullptr) { + delete info; + return nullptr; + } + info->result = std::shared_ptr(resultPtr); + } + return info; +} +} // namespace CliTool +} // namespace OHOS \ No newline at end of file diff --git a/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp b/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp index ca2b2fbdc9..afdbfcf21f 100644 --- a/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp +++ b/cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp @@ -84,6 +84,20 @@ void CliToolMGRClient::CliSaDeathRecipient::OnRemoteDied(const wptr &args, + const std::string &challenge, + const ExecOptions &options, + CliSessionInfo &session) +{ + auto proxy = GetCliToolManager(); + if (proxy == nullptr) { + TAG_LOGE(AAFwkTag::CLI_TOOL, "connect failed"); + return AAFwk::GET_CLI_TOOL_MGR_SERVICE_FAILED; + } + return proxy->ExecTool(name, args, challenge, options, session); +} + void CliToolMGRClient::ResetProxy(const wptr& remote) { std::lock_guard lock(mutex_); diff --git a/cli_tool_framework/interfaces/cli_tool/src/exec_options.cpp b/cli_tool_framework/interfaces/cli_tool/src/exec_options.cpp new file mode 100644 index 0000000000..726b89ccbd --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/src/exec_options.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2026 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 "exec_options.h" + +namespace OHOS { +namespace CliTool { +bool ExecOptions::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteBool(background)) { + return false; + } + if (!parcel.WriteInt32(yieldMs)) { + return false; + } + if (!parcel.WriteInt32(timeout)) { + return false; + } + if (!parcel.WriteUint32(static_cast(env.size()))) { + return false; + } + for (const auto &[key, value] : env) { + if (!parcel.WriteString(key)) { + return false; + } + if (!parcel.WriteString(value)) { + return false; + } + } + if (!parcel.WriteString(workingDir)) { + return false; + } + return true; +} + +ExecOptions *ExecOptions::Unmarshalling(Parcel &parcel) +{ + auto *options = new (std::nothrow) ExecOptions(); + if (options && !parcel.ReadBool(options->background)) { + delete options; + return nullptr; + } + if (!parcel.ReadInt32(options->yieldMs)) { + delete options; + return nullptr; + } + if (!parcel.ReadInt32(options->timeout)) { + delete options; + return nullptr; + } + uint32_t envSize = 0; + if (!parcel.ReadUint32(envSize)) { + delete options; + return nullptr; + } + for (uint32_t i = 0; i < envSize; i++) { + std::string key; + std::string value; + if (!parcel.ReadString(key)) { + delete options; + return nullptr; + } + if (!parcel.ReadString(value)) { + delete options; + return nullptr; + } + options->env[key] = value; + } + if (!parcel.ReadString(options->workingDir)) { + delete options; + return nullptr; + } + return options; +} +} // namespace CliTool +} // namespace OHOS \ No newline at end of file diff --git a/cli_tool_framework/interfaces/cli_tool/src/exec_result.cpp b/cli_tool_framework/interfaces/cli_tool/src/exec_result.cpp new file mode 100644 index 0000000000..e0035b7fa5 --- /dev/null +++ b/cli_tool_framework/interfaces/cli_tool/src/exec_result.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2026 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 "exec_result.h" + +namespace OHOS { +namespace CliTool { +bool ExecResult::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteInt32(exitCode)) { + return false; + } + if (!parcel.WriteString(outputText)) { + return false; + } + if (!parcel.WriteString(errorText)) { + return false; + } + if (!parcel.WriteInt32(signalNumber)) { + return false; + } + if (!parcel.WriteBool(timedOut)) { + return false; + } + if (!parcel.WriteInt64(executionTime)) { + return false; + } + return true; +} + +ExecResult *ExecResult::Unmarshalling(Parcel &parcel) +{ + auto *result = new (std::nothrow) ExecResult(); + if (result && !parcel.ReadInt32(result->exitCode)) { + delete result; + return nullptr; + } + if (!parcel.ReadString(result->outputText)) { + delete result; + return nullptr; + } + if (!parcel.ReadString(result->errorText)) { + delete result; + return nullptr; + } + if (!parcel.ReadInt32(result->signalNumber)) { + delete result; + return nullptr; + } + if (!parcel.ReadBool(result->timedOut)) { + delete result; + return nullptr; + } + if (!parcel.ReadInt64(result->executionTime)) { + delete result; + return nullptr; + } + return result; +} +} // namespace CliTool +} // namespace OHOS \ No newline at end of file diff --git a/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp b/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp index bc303801cf..e5f85ca07f 100644 --- a/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp +++ b/cli_tool_framework/interfaces/cli_tool/src/tool_info.cpp @@ -67,105 +67,6 @@ ToolInfo *ToolInfo::Unmarshalling(Parcel &parcel) return tool; } -// ExecOptions implementation -bool ExecOptions::Marshalling(Parcel &parcel) const -{ - return parcel.WriteBool(background) && - parcel.WriteInt32(yieldMs) && - parcel.WriteInt32(timeout) && - parcel.WriteString(workingDir); -} - -ExecOptions *ExecOptions::Unmarshalling(Parcel &parcel) -{ - auto *options = new (std::nothrow) ExecOptions(); - if (options == nullptr) { - return nullptr; - } - - if (!parcel.ReadBool(options->background) || - !parcel.ReadInt32(options->yieldMs) || - !parcel.ReadInt32(options->timeout) || - !parcel.ReadString(options->workingDir)) { - delete options; - return nullptr; - } - - return options; -} - -// ExecResult implementation -bool ExecResult::Marshalling(Parcel &parcel) const -{ - return parcel.WriteInt32(exitCode) && - parcel.WriteString(outputText) && - parcel.WriteString(errorText) && - parcel.WriteInt32(signalNumber) && - parcel.WriteBool(timedOut) && - parcel.WriteInt64(executionTime); -} - -ExecResult *ExecResult::Unmarshalling(Parcel &parcel) -{ - auto *result = new (std::nothrow) ExecResult(); - if (result == nullptr) { - return nullptr; - } - - if (!parcel.ReadInt32(result->exitCode) || - !parcel.ReadString(result->outputText) || - !parcel.ReadString(result->errorText) || - !parcel.ReadInt32(result->signalNumber) || - !parcel.ReadBool(result->timedOut) || - !parcel.ReadInt64(result->executionTime)) { - delete result; - return nullptr; - } - - return result; -} - -// SessionInfo implementation -bool SessionInfo::Marshalling(Parcel &parcel) const -{ - return parcel.WriteString(sessionId) && - parcel.WriteString(toolName) && - parcel.WriteString(status) && - parcel.WriteInt64(startTime) && - parcel.WriteInt64(endTime) && - parcel.WriteBool(result != nullptr) && - (result == nullptr || parcel.WriteParcelable(result.get())); -} - -SessionInfo *SessionInfo::Unmarshalling(Parcel &parcel) -{ - auto *session = new (std::nothrow) SessionInfo(); - if (session == nullptr) { - return nullptr; - } - - bool hasResult = false; - if (!parcel.ReadString(session->sessionId) || - !parcel.ReadString(session->toolName) || - !parcel.ReadString(session->status) || - !parcel.ReadInt64(session->startTime) || - !parcel.ReadInt64(session->endTime) || - !parcel.ReadBool(hasResult)) { - delete session; - return nullptr; - } - - if (hasResult) { - session->result.reset(ExecResult::Unmarshalling(parcel)); - if (session->result == nullptr) { - delete session; - return nullptr; - } - } - - return session; -} - // ToolEvent implementation bool ToolEvent::Marshalling(Parcel &parcel) const { diff --git a/cli_tool_framework/services/climgr/BUILD.gn b/cli_tool_framework/services/climgr/BUILD.gn index 762a1afc94..b677eb9bc3 100644 --- a/cli_tool_framework/services/climgr/BUILD.gn +++ b/cli_tool_framework/services/climgr/BUILD.gn @@ -47,7 +47,7 @@ ohos_shared_library("climgr") { external_deps = [ "c_utils:utils", "hilog:libhilog", - "ipc:ipc_core", + "ipc:ipc_single", "json:nlohmann_json_static", "kv_store:distributeddata_inner", "safwk:system_ability_fwk", diff --git a/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h b/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h index dd5934a35b..2fbed41ffa 100644 --- a/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h +++ b/cli_tool_framework/services/climgr/include/cli_tool_manager_service.h @@ -52,6 +52,16 @@ public: */ int32_t RegisterTool(const ToolInfo &tool) override; + /** + * @brief Execute a CLI tool. + * Implements the ICliToolManager interface method. + */ + int32_t ExecTool(const std::string &cliName, + const std::map &args, + const std::string &challenge, + const ExecOptions &options, + CliSessionInfo &session) override; + protected: void OnStart() override; void OnStop() override; diff --git a/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp b/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp index e591219648..03b40ae997 100644 --- a/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp +++ b/cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp @@ -60,6 +60,7 @@ void CliToolManagerService::OnStart() void CliToolManagerService::OnStop() { + TAG_LOGI(AAFwkTag::CLI_TOOL, "climgr stop"); } int32_t CliToolManagerService::GetAllToolInfos(std::vector &tools) @@ -85,5 +86,15 @@ int32_t CliToolManagerService::RegisterTool(const ToolInfo &tool) TAG_LOGI(AAFwkTag::CLI_TOOL, "RegisterTool called, tool name='%{public}s'", tool.name.c_str()); return CliToolDataManager::GetInstance().RegisterTool(tool); } + +int32_t CliToolManagerService::ExecTool(const std::string &cliName, + const std::map &args, + const std::string &challenge, + const ExecOptions &options, + CliSessionInfo &session) +{ + TAG_LOGI(AAFwkTag::CLI_TOOL, "ExecTool called: %{public}s", cliName.c_str()); + return 0; +} } // namespace CliTool } // namespace OHOS From 9e5974f174e08484cdf8e88c0cd8fe87d2258c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E8=8F=B2=E5=A2=A8?= Date: Tue, 21 Apr 2026 14:58:19 +0800 Subject: [PATCH 9/9] =?UTF-8?q?AMS=E9=80=80=E5=87=BA=E5=8E=9F=E5=9B=A0?= =?UTF-8?q?=E6=95=B4=E6=94=B9=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 朱菲墨 Co-Authored-By: Agent --- .../include/appmgr/app_mgr_client.h | 12 ++ .../include/appmgr/app_mgr_interface.h | 12 ++ .../appmgr/app_mgr_ipc_interface_code.h | 3 +- .../include/appmgr/app_mgr_proxy.h | 12 ++ .../app_manager/include/appmgr/app_mgr_stub.h | 1 + .../include/appmgr/running_process_info.h | 1 + .../app_manager/src/appmgr/app_mgr_client.cpp | 14 ++ .../app_manager/src/appmgr/app_mgr_proxy.cpp | 24 +++ .../app_manager/src/appmgr/app_mgr_stub.cpp | 23 +++ .../src/appmgr/running_process_info.cpp | 4 + .../include/ability_manager_service.h | 4 +- .../include/app_exit_reason_helper.h | 18 +-- services/abilitymgr/include/app_scheduler.h | 12 ++ .../src/ability_manager_service.cpp | 51 +++--- .../abilitymgr/src/app_exit_reason_helper.cpp | 146 ++++++------------ services/abilitymgr/src/app_scheduler.cpp | 7 + .../ui_ability_lifecycle_manager.cpp | 4 +- services/appmgr/include/app_mgr_service.h | 13 ++ .../appmgr/include/app_mgr_service_inner.h | 13 +- services/appmgr/include/app_running_record.h | 7 + services/appmgr/src/app_mgr_service.cpp | 13 ++ services/appmgr/src/app_mgr_service_inner.cpp | 22 ++- services/appmgr/src/app_running_manager.cpp | 5 +- services/appmgr/src/app_running_record.cpp | 8 + .../include/mock_app_mgr_service.h | 2 + .../include/mock_app_mgr_service.h | 2 + .../mock/include/mock_app_mgr_service.h | 2 + .../ability_manager_service_ninth_test.cpp | 14 +- .../mock/src/mock_app_scheduler.cpp | 6 + .../mock/include/mock_app_mgr_service.h | 2 + .../app_exit_reason_helper_fourth_test.cpp | 4 +- .../mock/src/mock_app_running_record.cpp | 5 + .../mock/src/mock_app_running_record.cpp | 5 + .../include/mock_app_mgr_service.h | 2 + .../mock_iapp_mgr.h | 6 + .../mock/include/mock_app_mgr_service.h | 2 + 36 files changed, 318 insertions(+), 163 deletions(-) diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_client.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_client.h index dae476d7f9..0f0a942bd4 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_client.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_client.h @@ -294,6 +294,18 @@ public: */ virtual AppMgrResultCode GetProcessRunningInfosByUserId(std::vector &info, int32_t userId); + /** + * GetProcessRunningInfosByAccessTokenId, call GetProcessRunningInfosByAccessTokenId() + * through proxy project. Obtains information about application processes that are + * running on the device by accessTokenId. + * + * @param accessTokenId, accessTokenId. + * @param info, Running process information list. + * @return ERR_OK ,return back success,others fail. + */ + virtual AppMgrResultCode GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info); + /** * GetProcessRunningInformation, call GetProcessRunningInformation() through proxy project. * Obtains information about current application processes which is running on the device. diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h index 75fd03ef2c..4698d24bea 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_interface.h @@ -280,6 +280,18 @@ public: */ virtual int GetProcessRunningInfosByUserId(std::vector &info, int32_t userId) = 0; + /** + * GetProcessRunningInfosByAccessTokenId, call GetProcessRunningInfosByAccessTokenId() + * through proxy project. Obtains information about application processes + * that are running on the device by accessTokenId. + * + * @param accessTokenId, accessTokenId. + * @param info, Running process information list. + * @return ERR_OK ,return back success,others fail. + */ + virtual int32_t GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info) = 0; + /** * GetProcessRunningInformation, call GetProcessRunningInformation() through proxy project. * Obtains information about current application process which is running on the device. diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h index 5a565bd9b9..46352dba9c 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_ipc_interface_code.h @@ -154,7 +154,8 @@ enum class AppMgrInterfaceCode { UNREGISTER_IMAGE_PROCESS_STATE_OBSERVER = 129, GET_ALL_ABILITY_INFOS = 130, DUMP_MEM_PROCESS = 131, - UPDATE_FREEZE_EXCLUDED_PID = 132 + UPDATE_FREEZE_EXCLUDED_PID = 132, + GET_PROCESS_RUNNING_INFOS_BY_ACCESS_TOKEN_ID = 133 }; } // AppExecFwk } // OHOS diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h index d3d8b89681..0f647ff1c3 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_proxy.h @@ -218,6 +218,18 @@ public: */ virtual int32_t GetProcessRunningInfosByUserId(std::vector &info, int32_t userId) override; + /** + * GetProcessRunningInfosByAccessTokenId, call GetProcessRunningInfosByAccessTokenId() + * through proxy project. Obtains information about application processes + * that are running on the device by accessTokenId. + * + * @param accessTokenId, accessTokenId. + * @param info, Running process information list. + * @return ERR_OK ,return back success,others fail. + */ + virtual int32_t GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info) override; + /** * GetProcessRunningInformation, call GetProcessRunningInformation() through proxy project. * Obtains information about current application process which is running on the device. diff --git a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h index b34dacbfda..a259b41c53 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h +++ b/interfaces/inner_api/app_manager/include/appmgr/app_mgr_stub.h @@ -76,6 +76,7 @@ private: int32_t HandleGetAllRunningProcesses(MessageParcel &data, MessageParcel &reply); int32_t HandleGetRunningProcessesByBundleType(MessageParcel &data, MessageParcel &reply); int32_t HandleGetProcessRunningInfosByUserId(MessageParcel &data, MessageParcel &reply); + int32_t HandleGetProcessRunningInfosByAccessTokenId(MessageParcel &data, MessageParcel &reply); int32_t HandleGetProcessRunningInformation(MessageParcel &data, MessageParcel &reply); int32_t HandleGetAllRenderProcesses(MessageParcel &data, MessageParcel &reply); int32_t HandlePreloadModuleFinished(MessageParcel &data, MessageParcel &reply); diff --git a/interfaces/inner_api/app_manager/include/appmgr/running_process_info.h b/interfaces/inner_api/app_manager/include/appmgr/running_process_info.h index 85c918ef23..e7017864dc 100644 --- a/interfaces/inner_api/app_manager/include/appmgr/running_process_info.h +++ b/interfaces/inner_api/app_manager/include/appmgr/running_process_info.h @@ -65,6 +65,7 @@ struct RunningProcessInfo : public Parcelable { bool isPreload = false; std::int32_t pid_; std::int32_t uid_; + std::uint32_t accessTokenId_ = 0; std::int32_t bundleType = 0; std::int32_t appCloneIndex = -1; std::int32_t rssValue = 0; diff --git a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_client.cpp b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_client.cpp index 93d0559c69..7dd357d777 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_client.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_client.cpp @@ -531,6 +531,20 @@ AppMgrResultCode AppMgrClient::GetProcessRunningInfosByUserId(std::vector &info) +{ + sptr service = iface_cast(mgrHolder_->GetRemoteObject()); + if (service != nullptr) { + int32_t result = service->GetProcessRunningInfosByAccessTokenId(accessTokenId, info); + if (result == ERR_OK) { + return AppMgrResultCode::RESULT_OK; + } + return AppMgrResultCode::ERROR_SERVICE_NOT_READY; + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + AppMgrResultCode AppMgrClient::GetProcessRunningInformation(AppExecFwk::RunningProcessInfo &info) { sptr service = iface_cast(mgrHolder_->GetRemoteObject()); diff --git a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp index 194b051d1f..5109cd8fa2 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_proxy.cpp @@ -448,6 +448,30 @@ int32_t AppMgrProxy::GetProcessRunningInfosByUserId(std::vector &info) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!WriteInterfaceToken(data)) { + return ERR_FLATTEN_OBJECT; + } + PARCEL_UTIL_WRITE_RET_INT(data, Uint32, accessTokenId); + + if (!SendTransactCmd(AppMgrInterfaceCode::GET_PROCESS_RUNNING_INFOS_BY_ACCESS_TOKEN_ID, data, reply)) { + return ERR_NULL_OBJECT; + } + auto error = GetParcelableInfos(reply, info); + if (error != NO_ERROR) { + TAG_LOGE(AAFwkTag::APPMGR, "GetParcelableInfos fail, error: %{public}d", error); + return error; + } + int result = reply.ReadInt32(); + return result; +} + int32_t AppMgrProxy::GetProcessRunningInformation(RunningProcessInfo &info) { MessageParcel data; diff --git a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp index 96a829b7ca..f6762792c8 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/app_mgr_stub.cpp @@ -43,6 +43,7 @@ namespace AppExecFwk { constexpr int32_t CYCLE_LIMIT = 1000; constexpr int32_t MAX_PROCESS_STATE_COUNT = 1000; constexpr int32_t MAX_BACKGROUND_APP_COUNT = 1000; +constexpr int32_t MAX_PROCESS_INFO_COUNT = 1024; AppMgrStub::AppMgrStub() {} @@ -129,6 +130,8 @@ int32_t AppMgrStub::OnRemoteRequestInnerFirst(uint32_t code, MessageParcel &data return HandleNotifyProcMemoryLevel(data, reply); case static_cast(AppMgrInterfaceCode::APP_GET_RUNNING_PROCESSES_BY_USER_ID): return HandleGetProcessRunningInfosByUserId(data, reply); + case static_cast(AppMgrInterfaceCode::GET_PROCESS_RUNNING_INFOS_BY_ACCESS_TOKEN_ID): + return HandleGetProcessRunningInfosByAccessTokenId(data, reply); case static_cast(AppMgrInterfaceCode::APP_ADD_ABILITY_STAGE_INFO_DONE): return HandleAddAbilityStageDone(data, reply); case static_cast(AppMgrInterfaceCode::STARTUP_RESIDENT_PROCESS): @@ -722,6 +725,26 @@ int32_t AppMgrStub::HandleGetProcessRunningInfosByUserId(MessageParcel &data, Me return NO_ERROR; } +int32_t AppMgrStub::HandleGetProcessRunningInfosByAccessTokenId(MessageParcel &data, MessageParcel &reply) +{ + HITRACE_METER(HITRACE_TAG_APP); + uint32_t accessTokenId = data.ReadUint32(); + std::vector info; + auto result = GetProcessRunningInfosByAccessTokenId(accessTokenId, info); + int32_t writeSize = std::min(static_cast(info.size()), MAX_PROCESS_INFO_COUNT); + reply.WriteInt32(writeSize); + for (int32_t i = 0; i < writeSize; ++i) { + if (!reply.WriteParcelable(&info[i])) { + return ERR_INVALID_VALUE; + } + } + if (!reply.WriteInt32(result)) { + return ERR_INVALID_VALUE; + } + TAG_LOGD(AAFwkTag::APPMGR, "AppMgrStub::HandleGetProcessRunningInfosByAccessTokenId end"); + return NO_ERROR; +} + int32_t AppMgrStub::HandleGetAllRenderProcesses(MessageParcel &data, MessageParcel &reply) { HITRACE_METER(HITRACE_TAG_APP); diff --git a/interfaces/inner_api/app_manager/src/appmgr/running_process_info.cpp b/interfaces/inner_api/app_manager/src/appmgr/running_process_info.cpp index 7f00c17685..fa3e2bcc18 100644 --- a/interfaces/inner_api/app_manager/src/appmgr/running_process_info.cpp +++ b/interfaces/inner_api/app_manager/src/appmgr/running_process_info.cpp @@ -38,6 +38,9 @@ bool RunningProcessInfo::ReadFromParcel(Parcel &parcel) int32_t uidData; READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, uidData); uid_ = static_cast(uidData); + uint32_t accessTokenIdData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, accessTokenIdData); + accessTokenId_ = accessTokenIdData; int32_t stateData; READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, stateData); state_ = static_cast(stateData); @@ -98,6 +101,7 @@ bool RunningProcessInfo::Marshalling(Parcel &parcel) const WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(processName_)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(pid_)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(uid_)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, accessTokenId_); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(state_)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isContinuousTask); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isKeepAlive); diff --git a/services/abilitymgr/include/ability_manager_service.h b/services/abilitymgr/include/ability_manager_service.h index 5ca60cbc82..6cd8a03ddc 100644 --- a/services/abilitymgr/include/ability_manager_service.h +++ b/services/abilitymgr/include/ability_manager_service.h @@ -1536,6 +1536,8 @@ public: virtual int GetProcessRunningInfos(std::vector &info) override; virtual int GetAllIntentExemptionInfo(std::vector &info) override; int GetProcessRunningInfosByUserId(std::vector &info, int32_t userId); + int GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info); void GetAbilityRunningInfo(std::vector &info, std::shared_ptr abilityRecord); void GetExtensionRunningInfo(std::shared_ptr &abilityRecord, const int32_t userId, std::vector &info); @@ -3516,7 +3518,7 @@ private: bool IsAllowAttachOrDetachAppDebug(AppExecFwk::ApplicationInfo &appInfo); bool IsExitReasonValid(const ExitReasonCompability &reason); - void RecordRecoveryExitReason(bool isAppRecovery, int32_t callerPid, int32_t callerUid); + void RecordAppRestartExitReason(bool isAppRecovery, int32_t callerPid, int32_t callerUid); void SetAppDeathRecipient(const sptr& abilityToken); void HandleAppDiedForRecovery(const sptr& remote, const AbilityInfo& abilityInfo, int32_t pid, int32_t uid, int32_t userId); diff --git a/services/abilitymgr/include/app_exit_reason_helper.h b/services/abilitymgr/include/app_exit_reason_helper.h index 5feddf3254..943bc0fd63 100644 --- a/services/abilitymgr/include/app_exit_reason_helper.h +++ b/services/abilitymgr/include/app_exit_reason_helper.h @@ -35,15 +35,6 @@ struct RecordExitReasonParams { bool fromKillWithReason = false; }; -struct AppReasonInfo { - int32_t userId = -1; - std::string bundleName = ""; - int32_t appIndex = -1; - - AppReasonInfo() = default; - AppReasonInfo(int32_t userId, const std::string &bundleName, int32_t appIndex) - : userId(userId), bundleName(bundleName), appIndex(appIndex) {} -}; class AppExitReasonHelper { public: explicit AppExitReasonHelper(std::shared_ptr subManagersHelper); @@ -65,13 +56,10 @@ public: int32_t AddBundleExitReason(const std::string &bundleName, int32_t userId, int32_t appIndex, const ExitReasonCompability &exitReason); int32_t RecordAppWithReason(int32_t pid, int32_t uid, const ExitReasonCompability &exitReason); - void RecordAppsWithReasonByUserId(int32_t userId, const ExitReasonCompability &exitReason, + void RecordAppsWithReasonByProcessInfoList(const ExitReasonCompability &exitReason, const std::vector &processInfoList); void RecordInvalidKillId(int32_t pid, const ExitReasonCompability ¶ms, const std::string &bundleName = "", int32_t userId = 0); - int32_t RecordAppWithReasonByAccessTokenId(int32_t userId, uint32_t accessTokenId, - const ExitReasonCompability &exitReasonCompability, - const std::vector &processInfoList); private: int32_t RecordProcessExitReason(const int32_t pid, const std::string bundleName, const int32_t uid, @@ -83,11 +71,11 @@ private: bool IsExitReasonValid(const ExitReason &exitReason); int32_t GetActiveAbilityListWithPid(int32_t uid, std::vector &abilityList, int32_t pid); void GetRunningProcessInfo(int32_t pid, int32_t userId, const std::string &bundleName, - AppExecFwk::RunningProcessInfo &processInfo); + AppExecFwk::RunningProcessInfo &processInfo, int32_t appIndex = DEFAULT_INVAL_VALUE); int32_t AddProcessExitReason(const RecordExitReasonParams ¶ms); std::vector GetRunningProcessInfos(int32_t userId, const std::string &bundleName); - int32_t RecordAppWithReasonInner(const AppReasonInfo &appInfo, const ExitReasonCompability &exitReasonCompability, + int32_t RecordAppWithReasonInner(const ExitReasonCompability &exitReasonCompability, const AppExecFwk::RunningProcessInfo &processInfo); std::shared_ptr subManagersHelper_; diff --git a/services/abilitymgr/include/app_scheduler.h b/services/abilitymgr/include/app_scheduler.h index 64373172eb..4778dfd63a 100644 --- a/services/abilitymgr/include/app_scheduler.h +++ b/services/abilitymgr/include/app_scheduler.h @@ -522,6 +522,18 @@ public: * @return ERR_OK ,return back success,others fail. */ int GetProcessRunningInfosByUserId(std::vector &info, int32_t userId); + + /** + * GetProcessRunningInfosByAccessTokenId, call GetProcessRunningInfosByAccessTokenId() through proxy project. + * Obtains information about application processes that are running on the device by accessTokenId. + * + * @param accessTokenId, accessTokenId in Application record. + * @param info, Running process info. + * @return ERR_OK ,return back success,others fail. + */ + int32_t GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info); + std::string ConvertAppState(const AppState &state); /** diff --git a/services/abilitymgr/src/ability_manager_service.cpp b/services/abilitymgr/src/ability_manager_service.cpp index fb46d88480..c1848bec9d 100644 --- a/services/abilitymgr/src/ability_manager_service.cpp +++ b/services/abilitymgr/src/ability_manager_service.cpp @@ -235,6 +235,7 @@ constexpr size_t INDEX_ONE = 1; constexpr size_t INDEX_TWO = 2; constexpr size_t ARGC_THREE = 3; constexpr size_t INDEX_FOUR = 4; +constexpr int32_t DEFAULT_KILL_ID = -1; constexpr static char WANT_PARAMS_VIEW_DATA_KEY[] = "ohos.ability.params.viewData"; constexpr const char* WANT_PARAMS_HOST_WINDOW_ID_KEY = "ohos.extra.param.key.hostwindowid"; @@ -3592,7 +3593,7 @@ int32_t AbilityManagerService::RecordAppWithReasonByUserId(int32_t userId, HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); CHECK_POINTER_AND_RETURN(appExitReasonHelper_, ERR_NULL_APP_EXIT_REASON_HELPER); if (IPCSkeleton::GetCallingPid() != getprocpid()) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "%{public}s: calling pid is not local process", __func__); + TAG_LOGE(AAFwkTag::ABILITYMGR, "calling pid is not local process"); return CHECK_PERMISSION_FAILED; } if (!IsExitReasonValid(exitReasonCompability)) { @@ -3612,7 +3613,7 @@ int32_t AbilityManagerService::RecordAppWithReasonByUserId(int32_t userId, return ERR_OK; } - appExitReasonHelper_->RecordAppsWithReasonByUserId(userId, exitReasonCompability, processInfoList); + appExitReasonHelper_->RecordAppsWithReasonByProcessInfoList(exitReasonCompability, processInfoList); return ERR_OK; } @@ -3625,28 +3626,20 @@ int32_t AbilityManagerService::RecordAppWithReasonByAccessTokenId(uint32_t acces TAG_LOGE(AAFwkTag::ABILITYMGR, "exit reason is invalid"); return ERR_INVALID_VALUE; } - Security::AccessToken::HapTokenInfo hapInfo; - int32_t ret = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(accessTokenId, hapInfo); - if (ret != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "GetHapTokenInfo failed: %{public}d", ret); - return ret; - } - int32_t userId = hapInfo.userID; std::vector processInfoList; - ret = IN_PROCESS_CALL(GetProcessRunningInfosByUserId(processInfoList, userId)); + int32_t ret = IN_PROCESS_CALL(GetProcessRunningInfosByAccessTokenId(accessTokenId, processInfoList)); if (ret != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "GetProcessRunningInfosByUserId failed: %{public}d", ret); + TAG_LOGE(AAFwkTag::ABILITYMGR, "GetProcessRunningInfosByAccessTokenId failed: %{public}d", ret); return ret; } if (processInfoList.empty()) { - TAG_LOGW(AAFwkTag::ABILITYMGR, "no process info for userId: %{public}d", userId); + TAG_LOGW(AAFwkTag::ABILITYMGR, "no process info for accessTokenId: %{public}d", accessTokenId); return ERR_OK; } - appExitReasonHelper_->RecordAppWithReasonByAccessTokenId(userId, accessTokenId, exitReasonCompability, - processInfoList); + appExitReasonHelper_->RecordAppsWithReasonByProcessInfoList(exitReasonCompability, processInfoList); return ERR_OK; } @@ -8705,8 +8698,9 @@ bool AbilityManagerService::CheckPermissionForKillCollaborator() int AbilityManagerService::KillProcess(const std::string &bundleName, bool clearPageStack, int32_t appIndex, const std::string& reason) { - TAG_LOGI(AAFwkTag::ABILITYMGR, "Kill process, bundleName: %{public}s, clearPageStack: %{public}d", - bundleName.c_str(), clearPageStack); + TAG_LOGI(AAFwkTag::ABILITYMGR, "Kill process, bundleName: %{public}s, clearPageStack: %{public}d" + "callingUid: %{public}d, callingPid: %{public}d", bundleName.c_str(), clearPageStack, + IPCSkeleton::GetCallingUid(), IPCSkeleton::GetCallingPid()); // check permission first auto isAllowKillProcessForCollaborator = CheckPermissionForKillCollaborator(); if (!isAllowKillProcessForCollaborator && @@ -10406,6 +10400,12 @@ int AbilityManagerService::GetProcessRunningInfosByUserId( return DelayedSingleton::GetInstance()->GetProcessRunningInfosByUserId(info, userId); } +int AbilityManagerService::GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info) +{ + return DelayedSingleton::GetInstance()->GetProcessRunningInfosByAccessTokenId(accessTokenId, info); +} + void AbilityManagerService::ClearUserData(int32_t userId) { TAG_LOGD(AAFwkTag::ABILITYMGR, "%{public}s", __func__); @@ -13541,7 +13541,12 @@ int32_t AbilityManagerService::KillProcessWithReasonInner(int32_t pid, const Exi return ERR_KILL_APP_WHILE_STARTING; } CHECK_POINTER_AND_RETURN(appExitReasonHelper_, ERR_NULL_OBJECT); - auto ret = IN_PROCESS_CALL(appExitReasonHelper_->RecordProcessExitReason(pid, reason, true)); + ExitReason modifiedReason(reason.reason, reason.subReason, reason.exitMsg); + modifiedReason.killId = (reason.killId == DEFAULT_KILL_ID) ? + HiviewDFX::ProcessKillReason::KillEventId::REASON_KILL_APPLICATION : reason.killId; + modifiedReason.shouldKillForeground = reason.shouldKillForeground; + modifiedReason.shouldSkipKillInStartup = reason.shouldSkipKillInStartup; + auto ret = IN_PROCESS_CALL(appExitReasonHelper_->RecordProcessExitReason(pid, modifiedReason, true)); if (ret != ERR_OK) { TAG_LOGW(AAFwkTag::ABILITYMGR, "RecordAppExitReason failed, ret:%{public}d", ret); } @@ -14911,19 +14916,14 @@ int32_t AbilityManagerService::GetUIExtensionSessionInfo(const sptr subM int32_t AppExitReasonHelper::RecordAppWithReason(int32_t pid, int32_t uid, const ExitReasonCompability &exitReason) { std::string bundleName; - int32_t appIndex = 0; - auto ret = IN_PROCESS_CALL(AbilityUtil::GetBundleManagerHelper()->GetNameAndIndexForUid(uid, bundleName, appIndex)); - if (ret != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "GetNameAndIndexForUid failed, ret: %{public}d", ret); - return ret; + int32_t userId = DEFAULT_INVAL_VALUE; + int32_t appIndex = DEFAULT_INVAL_VALUE; + if (pid == NO_PID) { + auto ret = IN_PROCESS_CALL(AbilityUtil::GetBundleManagerHelper()->GetNameAndIndexForUid( + uid, bundleName, appIndex)); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "GetNameAndIndexForUid failed, ret: %{public}d", ret); + return ret; + } + int32_t getOsAccountRet = DelayedSingleton::GetInstance()-> + GetOsAccountLocalIdFromUid(uid, userId); + if (getOsAccountRet != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "get GetOsAccountLocalIdFromUid failed. ret: %{public}d", getOsAccountRet); + return getOsAccountRet; + } } AppExecFwk::RunningProcessInfo processInfo; - int32_t userId = -1; - int32_t getOsAccountRet = DelayedSingleton::GetInstance()-> - GetOsAccountLocalIdFromUid(uid, userId); - if (getOsAccountRet != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "get GetOsAccountLocalIdFromUid failed. ret: %{public}d", getOsAccountRet); - return getOsAccountRet; - } - GetRunningProcessInfo(pid, userId, bundleName, processInfo); - TAG_LOGD(AAFwkTag::ABILITYMGR, "RecordAppWithReason inPid: %{public}d, processPid: %{public}d", + + GetRunningProcessInfo(pid, userId, bundleName, processInfo, appIndex); + TAG_LOGD(AAFwkTag::ABILITYMGR, "RecordAppWithReason inputPid: %{public}d, processPid: %{public}d", pid, processInfo.pid_); - AppReasonInfo appInfo(userId, bundleName, appIndex); - return RecordAppWithReasonInner(appInfo, exitReason, processInfo); + return RecordAppWithReasonInner(exitReason, processInfo); } -int32_t AppExitReasonHelper::RecordAppWithReasonInner(const AppReasonInfo &appInfo, - const ExitReasonCompability &exitReasonCompability, const AppExecFwk::RunningProcessInfo &processInfo) +int32_t AppExitReasonHelper::RecordAppWithReasonInner(const ExitReasonCompability &exitReasonCompability, + const AppExecFwk::RunningProcessInfo &processInfo) { - if (processInfo.pid_ <= 0 && processInfo.uid_ <= 0) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "processInfo is invalid"); + if (processInfo.pid_ <= 0 || processInfo.uid_ <= 0 || processInfo.bundleNames.empty()) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "processInfo is invalid, pid: %{public}d, uid: %{public}d, " + "bundleNames empty: %{public}d", processInfo.pid_, processInfo.uid_, processInfo.bundleNames.empty()); return ERR_INVALID_VALUE; } + std::string bundleName = processInfo.bundleNames.front(); ExitReason exitReason(exitReasonCompability.reason, exitReasonCompability.subReason, exitReasonCompability.exitMsg); exitReason.killId = exitReasonCompability.killId; int32_t extensionResultCode = RecordProcessExtensionExitReason( - processInfo.pid_, appInfo.bundleName, exitReason, processInfo, false); + processInfo.pid_, bundleName, exitReason, processInfo, false); if (extensionResultCode != ERR_OK) { TAG_LOGI(AAFwkTag::ABILITYMGR, "not record extension reason: %{public}d", extensionResultCode); } @@ -93,97 +98,33 @@ int32_t AppExitReasonHelper::RecordAppWithReasonInner(const AppReasonInfo &appIn TAG_LOGE(AAFwkTag::ABILITYMGR, "abilityLists empty"); return ERR_GET_ACTIVE_ABILITY_LIST_EMPTY; } - uint32_t accessTokenId = Security::AccessToken::AccessTokenKit::GetHapTokenID(appInfo.userId, appInfo.bundleName, - appInfo.appIndex); + + uint32_t accessTokenId = processInfo.accessTokenId_; TAG_LOGD(AAFwkTag::ABILITYMGR, - "userId: %{public}d, bundleName: %{public}s, accessTokenId: %{public}u", - appInfo.userId, appInfo.bundleName.c_str(), accessTokenId); + "bundleName: %{public}s, accessTokenId: %{public}u", bundleName.c_str(), accessTokenId); return DelayedSingleton::GetInstance()->SetAppExitReason( - appInfo.bundleName, accessTokenId, abilityList, exitReason, processInfo, false); + bundleName, accessTokenId, abilityList, exitReason, processInfo, false); } -void AppExitReasonHelper::RecordAppsWithReasonByUserId(int32_t userId, const ExitReasonCompability &exitReason, +void AppExitReasonHelper::RecordAppsWithReasonByProcessInfoList(const ExitReasonCompability &exitReason, const std::vector &processInfoList) { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); - TAG_LOGD(AAFwkTag::ABILITYMGR, "userId: %{public}d, processInfo count: %{public}zu", - userId, processInfoList.size()); - - int32_t appIndex; - int32_t uid; - int32_t pid; int32_t innerResult = ERR_OK; - std::string bundleName; for (const auto &processInfo : processInfoList) { - if (processInfo.pid_ <= 0 && processInfo.uid_ <= 0) { - continue; - } - uid = processInfo.uid_; - pid = processInfo.pid_; - TAG_LOGD(AAFwkTag::ABILITYMGR, "RecordAppsWithReasonByUserId uid: %{public}d, pid: %{public}d", uid, pid); - auto ret = IN_PROCESS_CALL(AbilityUtil::GetBundleManagerHelper()->GetNameAndIndexForUid( - uid, bundleName, appIndex)); - if (ret != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "GetNameAndIndexForUid failed, ret: %{public}d", ret); - continue; - } - - AppReasonInfo appInfo(userId, bundleName, appIndex); - innerResult = RecordAppWithReasonInner(appInfo, exitReason, processInfo); + TAG_LOGD(AAFwkTag::ABILITYMGR, "RecordAppsWithReasonByProcessInfoList uid: %{public}d, pid: %{public}d", + processInfo.uid_, processInfo.pid_); + + innerResult = RecordAppWithReasonInner(exitReason, processInfo); if (innerResult != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "RecordAppWithReasonInner failed for uid:%{public}d, userId:%{public}d," - " ret: %{public}d", - uid, userId, innerResult); + TAG_LOGE(AAFwkTag::ABILITYMGR, "RecordAppWithReasonInner failed for uid:%{public}d, ret: %{public}d", + processInfo.uid_, innerResult); continue; } } } -int32_t AppExitReasonHelper::RecordAppWithReasonByAccessTokenId(int32_t userId, uint32_t accessTokenId, - const ExitReasonCompability &exitReasonCompability, - const std::vector &processInfoList) -{ - std::string bundleName; - int32_t appIndex; - int32_t uid; - int32_t pid; - int32_t innerResult = ERR_OK; - for (const auto &processInfo : processInfoList) { - if (processInfo.pid_ <= 0 && processInfo.uid_ <= 0) { - continue; - } - uid = processInfo.uid_; - pid = processInfo.pid_; - TAG_LOGD(AAFwkTag::ABILITYMGR, "RecordAppWithReasonByAccessTokenId uid: %{public}d, pid: %{public}d", uid, pid); - innerResult = IN_PROCESS_CALL(AbilityUtil::GetBundleManagerHelper()->GetNameAndIndexForUid( - uid, bundleName, appIndex)); - if (innerResult != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "GetNameAndIndexForUid failed, ret: %{public}d", innerResult); - continue; - } - - uint32_t currentAccessTokenId = Security::AccessToken::AccessTokenKit::GetHapTokenID(uid, bundleName, appIndex); - TAG_LOGD(AAFwkTag::ABILITYMGR, "process uid: %{public}d, calculated accessTokenId: %{public}u, " - "expected accessTokenId: %{public}u", uid, currentAccessTokenId, accessTokenId); - - if (currentAccessTokenId != accessTokenId) { - TAG_LOGD(AAFwkTag::ABILITYMGR, "accessTokenId mismatch, skip process"); - continue; - } - - AppReasonInfo appInfo(userId, bundleName, appIndex); - innerResult = RecordAppWithReasonInner(appInfo, exitReasonCompability, processInfo); - if (innerResult != ERR_OK) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "RecordAppWithReasonInner failed for uid:%{public}d, userId:%{public}d, " - "ret: %{public}d", uid, userId, innerResult); - continue; - } - } - - return innerResult; -} - int32_t AppExitReasonHelper::RecordAppExitReason(const ExitReason &exitReason) { if (!IsExitReasonValid(exitReason)) { @@ -318,7 +259,7 @@ int32_t AppExitReasonHelper::RecordAppExitReason(const std::string &bundleName, "userId: %{public}d, bundleName: %{public}s, appIndex: %{public}d", userId, bundleName.c_str(), appIndex); uint32_t accessTokenId = Security::AccessToken::AccessTokenKit::GetHapTokenID(userId, bundleName, appIndex); AppExecFwk::RunningProcessInfo processInfo; - GetRunningProcessInfo(NO_PID, userId, bundleName, processInfo); + GetRunningProcessInfo(NO_PID, userId, bundleName, processInfo, appIndex); int32_t pid = processInfo.pid_ == DEFAULT_PROCESS_RUNNING_INFO_PID ? NO_PID : processInfo.pid_; return RecordProcessExitReason(pid, bundleName, uid, accessTokenId, exitReason, processInfo, false); } @@ -433,7 +374,7 @@ int32_t AppExitReasonHelper::AddAppExitReason(const std::string &bundleName, int "userId: %{public}d, bundleName: %{public}s, appIndex: %{public}d", userId, bundleName.c_str(), appIndex); uint32_t accessTokenId = Security::AccessToken::AccessTokenKit::GetHapTokenID(userId, bundleName, appIndex); AppExecFwk::RunningProcessInfo processInfo; - GetRunningProcessInfo(pid, userId, bundleName, processInfo); + GetRunningProcessInfo(pid, userId, bundleName, processInfo, appIndex); RecordExitReasonParams params; params.pid = pid; params.uid = uid; @@ -602,7 +543,7 @@ int32_t AppExitReasonHelper::RecordUIAbilityExitReason(const pid_t pid, const st } void AppExitReasonHelper::GetRunningProcessInfo(int32_t pid, int32_t userId, const std::string &bundleName, - AppExecFwk::RunningProcessInfo &processInfo) + AppExecFwk::RunningProcessInfo &processInfo, int32_t appIndex) { if (pid != NO_PID) { DelayedSingleton::GetInstance()->GetRunningProcessInfoByPid(static_cast(pid), @@ -612,6 +553,13 @@ void AppExitReasonHelper::GetRunningProcessInfo(int32_t pid, int32_t userId, con std::vector infoList = GetRunningProcessInfos(userId, bundleName); if (infoList.size() == 1) { processInfo = infoList.front(); + } else if (infoList.size() > 1 && appIndex != DEFAULT_INVAL_VALUE) { + for (const auto &info : infoList) { + if (info.appCloneIndex == appIndex) { + processInfo = info; + return; + } + } } } diff --git a/services/abilitymgr/src/app_scheduler.cpp b/services/abilitymgr/src/app_scheduler.cpp index 31b29090a2..492e80f2cc 100644 --- a/services/abilitymgr/src/app_scheduler.cpp +++ b/services/abilitymgr/src/app_scheduler.cpp @@ -510,6 +510,13 @@ int AppScheduler::GetProcessRunningInfosByUserId(std::vector(appMgrClient_->GetProcessRunningInfosByUserId(info, userId)); } +int AppScheduler::GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info) +{ + CHECK_POINTER_AND_RETURN(appMgrClient_, INNER_ERR); + return static_cast(appMgrClient_->GetProcessRunningInfosByAccessTokenId(accessTokenId, info)); +} + std::string AppScheduler::ConvertAppState(const AppState &state) { return StateUtils::AppStateToStrMap(state); diff --git a/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp b/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp index d0c310d9e0..ecf80b78ef 100644 --- a/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp +++ b/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp @@ -961,7 +961,7 @@ void UIAbilityLifecycleManager::HandleAbilitiesRequestDone(int32_t requestId, in abilitiesRequestMap_.erase(it); auto callerRecord = Token::GetAbilityRecordByToken(abilitiesRequest->callerToken); if (callerRecord == nullptr) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "startUIAbilities callerRecord not exist."); + TAG_LOGW(AAFwkTag::ABILITYMGR, "startUIAbilities callerRecord not exist."); return; } callerRecord->NotifyAbilitiesRequestDone(abilitiesRequest->requestKey, @@ -983,7 +983,7 @@ void UIAbilityLifecycleManager::HandleAbilitiesRequestDone(int32_t requestId, in abilitiesRequestMap_.erase(it); auto callerRecord = Token::GetAbilityRecordByToken(abilitiesRequest->callerToken); if (callerRecord == nullptr) { - TAG_LOGE(AAFwkTag::ABILITYMGR, "startUIAbilities callerRecord not exist."); + TAG_LOGW(AAFwkTag::ABILITYMGR, "startUIAbilities callerRecord not exist."); return; } callerRecord->NotifyAbilitiesRequestDone(abilitiesRequest->requestKey, ret); diff --git a/services/appmgr/include/app_mgr_service.h b/services/appmgr/include/app_mgr_service.h index 69e33ee2d6..f50b170bb1 100644 --- a/services/appmgr/include/app_mgr_service.h +++ b/services/appmgr/include/app_mgr_service.h @@ -239,6 +239,19 @@ public: */ virtual int32_t GetProcessRunningInfosByUserId(std::vector &info, int32_t userId) override; + /** + * GetProcessRunningInfosByAccessTokenId, call GetProcessRunningInfosByAccessTokenId() + * through proxy project. Obtains information about application processes + * that are running on the device by accessTokenId. + * + * @param accessTokenId, accessTokenId. + * @param info, Running process information list. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info) override; + /** * GetProcessRunningInformation, call GetProcessRunningInformation() through proxy project. * Obtains information about current application process which is running on the device. diff --git a/services/appmgr/include/app_mgr_service_inner.h b/services/appmgr/include/app_mgr_service_inner.h index e51058ff31..8118eae748 100644 --- a/services/appmgr/include/app_mgr_service_inner.h +++ b/services/appmgr/include/app_mgr_service_inner.h @@ -561,6 +561,18 @@ public: */ virtual int32_t GetProcessRunningInfosByUserId(std::vector &info, int32_t userId); + /** + * GetProcessRunningInfosByAccessTokenId, Obtains information about application processes + * that are running on the device by accessTokenId. + * + * @param accessTokenId, accessTokenId. + * @param info, Running process information list. + * + * @return ERR_OK ,return back success,others fail. + */ + virtual int32_t GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info); + /** * GetProcessRunningInformation, Obtains information about current application process * which is running on the device. @@ -1084,7 +1096,6 @@ public: int32_t NotifyAppMgrRecordExitReasonCompability( int32_t pid, int32_t killId, const std::string &killMsg, const std::string &innerMsg); #ifdef APP_MGR_KILL_REASON_TAG - void RecordAppWithReason(int32_t pid, int32_t uid, int32_t killId); void RecordAppWithReasonByUserId(int32_t userId, int32_t killId); #endif diff --git a/services/appmgr/include/app_running_record.h b/services/appmgr/include/app_running_record.h index 6f976f1141..3e3146d015 100644 --- a/services/appmgr/include/app_running_record.h +++ b/services/appmgr/include/app_running_record.h @@ -231,6 +231,13 @@ public: */ int32_t GetUid() const; + /** + * @brief Obtains the application accessTokenId. + * + * @return Returns the application accessTokenId. + */ + uint32_t GetAccessTokenId() const; + /** * @brief Setting the application uid. * diff --git a/services/appmgr/src/app_mgr_service.cpp b/services/appmgr/src/app_mgr_service.cpp index b8ab618dfc..b1ccf386c2 100644 --- a/services/appmgr/src/app_mgr_service.cpp +++ b/services/appmgr/src/app_mgr_service.cpp @@ -604,6 +604,19 @@ int32_t AppMgrService::GetProcessRunningInfosByUserId(std::vectorGetProcessRunningInfosByUserId(info, userId); } +int32_t AppMgrService::GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector &info) +{ + if (!IsReady()) { + return ERR_INVALID_OPERATION; + } + if (IPCSkeleton::GetCallingPid() != getprocpid()) { + TAG_LOGE(AAFwkTag::APPMGR, "calling pid is not local process"); + return ERR_PERMISSION_DENIED; + } + return appMgrServiceInner_->GetProcessRunningInfosByAccessTokenId(accessTokenId, info); +} + int32_t AppMgrService::GetProcessRunningInformation(RunningProcessInfo &info) { if (!IsReady()) { diff --git a/services/appmgr/src/app_mgr_service_inner.cpp b/services/appmgr/src/app_mgr_service_inner.cpp index ba07a89a7d..d8202adefb 100644 --- a/services/appmgr/src/app_mgr_service_inner.cpp +++ b/services/appmgr/src/app_mgr_service_inner.cpp @@ -3952,6 +3952,21 @@ int32_t AppMgrServiceInner::GetProcessRunningInfosByUserId(std::vector &info) +{ + for (const auto &item : appRunningManager_->GetAppRunningRecordMap()) { + const auto &appRecord = item.second; + if (!appRecord || !appRecord->GetSpawned()) { + continue; + } + if (appRecord->GetAccessTokenId() == accessTokenId) { + GetRunningProcesses(appRecord, info); + } + } + return ERR_OK; +} + int32_t AppMgrServiceInner::GetProcessRunningInformation(RunningProcessInfo &info) { if (!appRunningManager_) { @@ -4153,6 +4168,7 @@ void AppMgrServiceInner::GetRunningProcess(const std::shared_ptrGetProcessName(); info.pid_ = appRecord->GetPid(); info.uid_ = appRecord->GetUid(); + info.accessTokenId_ = appRecord->GetAccessTokenId(); info.state_ = static_cast(appRecord->GetState()); info.isContinuousTask = appRecord->IsContinuousTask(); info.isKeepAlive = appRecord->IsKeepAliveApp(); @@ -9062,12 +9078,6 @@ void AppMgrServiceInner::RecordAppfreezeKillReason(int32_t pid, const FaultData AbilityManagerClient::GetInstance()->KillAppWithReason(pid, exitReason); } -void AppMgrServiceInner::RecordAppWithReason(int32_t pid, int32_t uid, int32_t killId) -{ - AAFwk::ExitReasonCompability exitReasonCompability(killId); - AbilityManagerClient::GetInstance()->RecordAppWithReason(pid, uid, exitReasonCompability); -} - void AppMgrServiceInner::RecordAppWithReasonByUserId(int32_t userId, int32_t killId) { AAFwk::ExitReasonCompability exitReasonCompability(killId); diff --git a/services/appmgr/src/app_running_manager.cpp b/services/appmgr/src/app_running_manager.cpp index 093a58fb9e..6614e1e8e5 100644 --- a/services/appmgr/src/app_running_manager.cpp +++ b/services/appmgr/src/app_running_manager.cpp @@ -761,10 +761,6 @@ std::shared_ptr AppRunningManager::OnRemoteDied(const wptrGetProcessName().c_str(), priorityObject->GetPid()); if (appMgrServiceInner != nullptr) { -#ifdef APP_MGR_KILL_REASON_TAG - appMgrServiceInner->RecordAppWithReason(priorityObject->GetPid(), appRecord->GetUid(), - HiviewDFX::ProcessKillReason::KillEventId::REASON_ON_REMOTE_DIED); -#endif appMgrServiceInner->KillProcessByPid(priorityObject->GetPid(), "OnRemoteDied"); } AbilityRuntime::FreezeUtil::GetInstance().DeleteAppLifecycleEvent(priorityObject->GetPid()); @@ -1108,6 +1104,7 @@ int32_t AppRunningManager::AssignRunningProcessInfoByAppRecord( info.processName_ = appRecord->GetProcessName(); info.pid_ = appRecord->GetPid(); info.uid_ = appRecord->GetUid(); + info.accessTokenId_ = appRecord->GetAccessTokenId(); info.bundleNames.emplace_back(appRecord->GetBundleName()); info.state_ = static_cast(appRecord->GetState()); info.isContinuousTask = appRecord->IsContinuousTask(); diff --git a/services/appmgr/src/app_running_record.cpp b/services/appmgr/src/app_running_record.cpp index 8e5d463fb1..74ebe2d03c 100644 --- a/services/appmgr/src/app_running_record.cpp +++ b/services/appmgr/src/app_running_record.cpp @@ -208,6 +208,14 @@ int32_t AppRunningRecord::GetUid() const return mainUid_; } +uint32_t AppRunningRecord::GetAccessTokenId() const +{ + if (appInfo_ != nullptr) { + return appInfo_->accessTokenId; + } + return 0; +} + void AppRunningRecord::SetUid(const int32_t uid) { mainUid_ = uid; diff --git a/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h b/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h index d4401a0931..b559dcf645 100644 --- a/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h +++ b/test/mock/frameworks_kits_appkit_test/include/mock_app_mgr_service.h @@ -45,6 +45,8 @@ public: MOCK_METHOD1(NotifyProcMemoryLevel, int32_t(const std::map &procLevelMap)); MOCK_METHOD2(DumpHeapMemory, int(const int32_t pid, OHOS::AppExecFwk::MallocInfo &mallocInfo)); MOCK_METHOD2(GetProcessRunningInfosByUserId, int(std::vector& info, int32_t userId)); + MOCK_METHOD2(GetProcessRunningInfosByAccessTokenId, int32_t(uint32_t accessTokenId, + std::vector& info)); MOCK_METHOD4(StartUserTestProcess, int(const AAFwk::Want& want, const sptr& observer, const BundleInfo& bundleInfo, int32_t userId)); MOCK_METHOD3(FinishUserTest, int(const std::string& msg, const int64_t& resultCode, diff --git a/test/mock/services_appmgr_test/include/mock_app_mgr_service.h b/test/mock/services_appmgr_test/include/mock_app_mgr_service.h index 43ec2e5f83..85784c38c2 100644 --- a/test/mock/services_appmgr_test/include/mock_app_mgr_service.h +++ b/test/mock/services_appmgr_test/include/mock_app_mgr_service.h @@ -53,6 +53,8 @@ public: MOCK_METHOD2(GetRunningProcessesByBundleType, int(const BundleType bundleType, std::vector& info)); MOCK_METHOD2(GetProcessRunningInfosByUserId, int(std::vector& info, int32_t userId)); + MOCK_METHOD2(GetProcessRunningInfosByAccessTokenId, int32_t(uint32_t accessTokenId, + std::vector& info)); MOCK_METHOD1(GetAllRenderProcesses, int(std::vector& info)); MOCK_METHOD1(GetAllChildrenProcesses, int(std::vector&)); MOCK_METHOD0(GetAmsMgr, sptr()); diff --git a/test/unittest/ability_manager_service_eighth_test/mock/include/mock_app_mgr_service.h b/test/unittest/ability_manager_service_eighth_test/mock/include/mock_app_mgr_service.h index ad15bb024a..130e298480 100644 --- a/test/unittest/ability_manager_service_eighth_test/mock/include/mock_app_mgr_service.h +++ b/test/unittest/ability_manager_service_eighth_test/mock/include/mock_app_mgr_service.h @@ -51,6 +51,8 @@ public: MOCK_METHOD2(GetRunningProcessesByBundleType, int(const BundleType bundleType, std::vector& info)); MOCK_METHOD2(GetProcessRunningInfosByUserId, int(std::vector& info, int32_t userId)); + MOCK_METHOD2(GetProcessRunningInfosByAccessTokenId, int32_t(uint32_t accessTokenId, + std::vector& info)); MOCK_METHOD1(GetAllRenderProcesses, int(std::vector& info)); MOCK_METHOD1(GetAllChildrenProcesses, int(std::vector&)); MOCK_METHOD0(GetAmsMgr, sptr()); diff --git a/test/unittest/ability_manager_service_ninth_test/ability_manager_service_ninth_test.cpp b/test/unittest/ability_manager_service_ninth_test/ability_manager_service_ninth_test.cpp index daceb34452..439ec5c2bd 100644 --- a/test/unittest/ability_manager_service_ninth_test/ability_manager_service_ninth_test.cpp +++ b/test/unittest/ability_manager_service_ninth_test/ability_manager_service_ninth_test.cpp @@ -510,22 +510,22 @@ HWTEST_F(AbilityManagerServiceNinthTest, ExecuteIntentWithServiceMatch_002, Test /* * Feature: AbilityManagerService - * Function: RecordRecoveryExitReason + * Function: RecordAppRestartExitReason * SubFunction: NA - * FunctionPoints: AbilityManagerService RecordRecoveryExitReason + * FunctionPoints: AbilityManagerService RecordAppRestartExitReason */ -HWTEST_F(AbilityManagerServiceNinthTest, RecordRecoveryExitReason_001, TestSize.Level1) +HWTEST_F(AbilityManagerServiceNinthTest, RecordAppRestartExitReason_001, TestSize.Level1) { - TAG_LOGI(AAFwkTag::TEST, "AbilityManagerServiceSixthTest RecordRecoveryExitReason_001 start"); + TAG_LOGI(AAFwkTag::TEST, "AbilityManagerServiceSixthTest RecordAppRestartExitReason_001 start"); auto abilityMs_ = std::make_shared(); EXPECT_NE(abilityMs_, nullptr); bool isAppRecovery = false; int32_t callerPid = getpid(); int32_t callerUid = getuid(); - abilityMs_->RecordRecoveryExitReason(isAppRecovery, callerPid, callerUid); + abilityMs_->RecordAppRestartExitReason(isAppRecovery, callerPid, callerUid); isAppRecovery = true; - abilityMs_->RecordRecoveryExitReason(isAppRecovery, callerPid, callerUid); - TAG_LOGI(AAFwkTag::TEST, "AbilityManagerServiceSixthTest RecordRecoveryExitReason_001 end"); + abilityMs_->RecordAppRestartExitReason(isAppRecovery, callerPid, callerUid); + TAG_LOGI(AAFwkTag::TEST, "AbilityManagerServiceSixthTest RecordAppRestartExitReason_001 end"); } } // namespace AAFwk } // namespace OHOS diff --git a/test/unittest/ability_manager_service_thirteenth_test/mock/src/mock_app_scheduler.cpp b/test/unittest/ability_manager_service_thirteenth_test/mock/src/mock_app_scheduler.cpp index 7ded08bb3f..386d635c2b 100644 --- a/test/unittest/ability_manager_service_thirteenth_test/mock/src/mock_app_scheduler.cpp +++ b/test/unittest/ability_manager_service_thirteenth_test/mock/src/mock_app_scheduler.cpp @@ -338,6 +338,12 @@ int AppScheduler::GetProcessRunningInfosByUserId(std::vector &info) +{ + return 0; +} + std::string AppScheduler::ConvertAppState(const AppState &state) { return "INVALIDSTATE"; diff --git a/test/unittest/ability_permission_util_second_test/mock/include/mock_app_mgr_service.h b/test/unittest/ability_permission_util_second_test/mock/include/mock_app_mgr_service.h index 1df8426870..0db55110d1 100644 --- a/test/unittest/ability_permission_util_second_test/mock/include/mock_app_mgr_service.h +++ b/test/unittest/ability_permission_util_second_test/mock/include/mock_app_mgr_service.h @@ -52,6 +52,8 @@ public: MOCK_METHOD2(GetRunningProcessesByBundleType, int(const BundleType bundleType, std::vector& info)); MOCK_METHOD2(GetProcessRunningInfosByUserId, int(std::vector& info, int32_t userId)); + MOCK_METHOD2(GetProcessRunningInfosByAccessTokenId, int32_t(uint32_t accessTokenId, + std::vector& info)); MOCK_METHOD1(GetAllRenderProcesses, int(std::vector& info)); MOCK_METHOD1(GetAllChildrenProcesses, int(std::vector&)); MOCK_METHOD0(GetAmsMgr, sptr()); diff --git a/test/unittest/app_exit_reason_helper_fourth_test/app_exit_reason_helper_fourth_test.cpp b/test/unittest/app_exit_reason_helper_fourth_test/app_exit_reason_helper_fourth_test.cpp index b7cd2d68c8..870e45eff8 100644 --- a/test/unittest/app_exit_reason_helper_fourth_test/app_exit_reason_helper_fourth_test.cpp +++ b/test/unittest/app_exit_reason_helper_fourth_test/app_exit_reason_helper_fourth_test.cpp @@ -357,7 +357,7 @@ HWTEST_F(AppExitReasonHelperTest, RecordAppWithReason_0100, TestSize.Level1) int32_t pid = 1; int32_t uid = 1; int32_t result = appExitReasonHelper->RecordAppWithReason(pid, uid, exitReason); - EXPECT_EQ(result, MOCK_ERROR); + EXPECT_EQ(result, ERR_INVALID_VALUE); AbilityUtil::GetBundleManagerHelper()->getNameAndIndexForUid_ = true; MyStatus::GetInstance().getOsAccountRet_ = MOCK_ERROR; @@ -366,7 +366,7 @@ HWTEST_F(AppExitReasonHelperTest, RecordAppWithReason_0100, TestSize.Level1) EXPECT_NE(subManagersHelper, nullptr); appExitReasonHelper->subManagersHelper_ = subManagersHelper; result = appExitReasonHelper->RecordAppWithReason(pid, uid, exitReason); - EXPECT_EQ(result, MOCK_ERROR); + EXPECT_EQ(result, ERR_INVALID_VALUE); MyStatus::GetInstance().getOsAccountRet_ = 0; auto currentUIAbilityManager = std::make_shared(0); EXPECT_NE(currentUIAbilityManager, nullptr); diff --git a/test/unittest/app_mgr_service_inner_ninth_test/mock/src/mock_app_running_record.cpp b/test/unittest/app_mgr_service_inner_ninth_test/mock/src/mock_app_running_record.cpp index 20ced6f65a..308cd42a0f 100644 --- a/test/unittest/app_mgr_service_inner_ninth_test/mock/src/mock_app_running_record.cpp +++ b/test/unittest/app_mgr_service_inner_ninth_test/mock/src/mock_app_running_record.cpp @@ -1178,6 +1178,11 @@ void AppRunningRecord::SetAssignTokenId(int32_t assignTokenId) assignTokenId_ = assignTokenId; } +uint32_t AppRunningRecord::GetAccessTokenId() const +{ + return 0; +} + void AppRunningRecord::SetRestartAppFlag(bool isRestartApp) { isRestartApp_ = isRestartApp; diff --git a/test/unittest/cache_process_manager_second_test/mock/src/mock_app_running_record.cpp b/test/unittest/cache_process_manager_second_test/mock/src/mock_app_running_record.cpp index 3167466878..84dd1a32ce 100644 --- a/test/unittest/cache_process_manager_second_test/mock/src/mock_app_running_record.cpp +++ b/test/unittest/cache_process_manager_second_test/mock/src/mock_app_running_record.cpp @@ -140,6 +140,11 @@ void AppRunningRecord::SetUid(const int32_t uid) mainUid_ = uid; } +uint32_t AppRunningRecord::GetAccessTokenId() const +{ + return 0; +} + void AppRunningRecord::SetPreloadAttachTimeoutStartTime(const std::chrono::system_clock::time_point &time) { preloadAttachTimeoutStartTime_ = time; diff --git a/test/unittest/multi_app_utils_test/include/mock_app_mgr_service.h b/test/unittest/multi_app_utils_test/include/mock_app_mgr_service.h index 9de0d562e7..0db7155443 100644 --- a/test/unittest/multi_app_utils_test/include/mock_app_mgr_service.h +++ b/test/unittest/multi_app_utils_test/include/mock_app_mgr_service.h @@ -52,6 +52,8 @@ public: MOCK_METHOD2(GetRunningProcessesByBundleType, int(const BundleType bundleType, std::vector& info)); MOCK_METHOD2(GetProcessRunningInfosByUserId, int(std::vector& info, int32_t userId)); + MOCK_METHOD2(GetProcessRunningInfosByAccessTokenId, int32_t(uint32_t accessTokenId, + std::vector& info)); MOCK_METHOD1(GetAllRenderProcesses, int(std::vector& info)); MOCK_METHOD1(GetAllChildrenProcesses, int(std::vector&)); MOCK_METHOD0(GetAmsMgr, sptr()); diff --git a/test/unittest/multi_instance_utils_second_test/mock_iapp_mgr.h b/test/unittest/multi_instance_utils_second_test/mock_iapp_mgr.h index d5697efe96..8512525dbd 100644 --- a/test/unittest/multi_instance_utils_second_test/mock_iapp_mgr.h +++ b/test/unittest/multi_instance_utils_second_test/mock_iapp_mgr.h @@ -131,6 +131,12 @@ public: return 0; } + virtual int32_t GetProcessRunningInfosByAccessTokenId(uint32_t accessTokenId, + std::vector& info) + { + return 0; + } + virtual int32_t GetProcessRunningInformation(RunningProcessInfo& info) { return 0; diff --git a/test/unittest/ui_ability_lifecycle_manager_third_test/mock/include/mock_app_mgr_service.h b/test/unittest/ui_ability_lifecycle_manager_third_test/mock/include/mock_app_mgr_service.h index b865c9a898..f04a81b9b9 100644 --- a/test/unittest/ui_ability_lifecycle_manager_third_test/mock/include/mock_app_mgr_service.h +++ b/test/unittest/ui_ability_lifecycle_manager_third_test/mock/include/mock_app_mgr_service.h @@ -52,6 +52,8 @@ public: MOCK_METHOD2(GetRunningProcessesByBundleType, int(const BundleType bundleType, std::vector& info)); MOCK_METHOD2(GetProcessRunningInfosByUserId, int(std::vector& info, int32_t userId)); + MOCK_METHOD2(GetProcessRunningInfosByAccessTokenId, int32_t(uint32_t accessTokenId, + std::vector& info)); MOCK_METHOD1(GetAllRenderProcesses, int(std::vector& info)); MOCK_METHOD1(GetAllChildrenProcesses, int(std::vector&)); MOCK_METHOD0(GetAmsMgr, sptr());