From 2bdc488efa4304775057729808a24ee6e3a08310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E8=8F=B2=E5=A2=A8?= Date: Fri, 20 Jun 2025 18:18:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EStartAbilities=5Fbase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 朱菲墨 --- .../service_extension_context.js | 7 +- .../ui_extension_context.js | 7 +- .../native/js_service_extension_context.cpp | 86 ++++++- .../js_ui_extension_context.cpp | 86 ++++++- .../ui_extension_context.cpp | 10 + .../service_extension_context.cpp | 12 +- .../include/ability_manager_client.h | 11 + .../include/ability_manager_errors.h | 28 +++ .../include/ability_manager_interface.h | 14 ++ .../ability_manager_ipc_interface_code.h | 2 + .../js_ui_extension_context.h | 5 +- .../ui_extension_base/ui_extension_context.h | 4 +- .../service_extension_context.h | 4 +- .../include/ability_manager_proxy.h | 11 + .../include/ability_manager_service.h | 19 ++ .../abilitymgr/include/ability_manager_stub.h | 1 + .../ui_ability_lifecycle_manager.h | 16 +- .../include/utils/start_ability_utils.h | 3 +- .../abilitymgr/src/ability_manager_client.cpp | 13 + .../abilitymgr/src/ability_manager_proxy.cpp | 50 ++++ .../src/ability_manager_service.cpp | 228 ++++++++++++++++++ .../abilitymgr/src/ability_manager_stub.cpp | 36 +++ .../ui_ability_lifecycle_manager.cpp | 135 +++++++++++ .../src/utils/start_ability_utils.cpp | 10 + services/common/include/app_utils.h | 8 + services/common/src/app_utils.cpp | 11 + 26 files changed, 807 insertions(+), 10 deletions(-) diff --git a/frameworks/js/napi/service_extension_context/service_extension_context.js b/frameworks/js/napi/service_extension_context/service_extension_context.js index c81ba0f5120..67dfc6e56b3 100644 --- a/frameworks/js/napi/service_extension_context/service_extension_context.js +++ b/frameworks/js/napi/service_extension_context/service_extension_context.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -79,6 +79,11 @@ class ServiceExtensionContext extends ExtensionContext { return this.__context_impl__.startServiceExtensionAbilityWithAccount(want, accountId, callback); } + startAbilities(wantList) { + hilog.sLogI(domainID, TAG, 'startAbilities'); + return this.__context_impl__.startAbilities(wantList); + } + stopServiceExtensionAbility(want, callback) { hilog.sLogI(domainID, TAG, 'stopServiceExtensionAbility'); return this.__context_impl__.stopServiceExtensionAbility(want, callback); diff --git a/frameworks/js/napi/ui_extension_context/ui_extension_context.js b/frameworks/js/napi/ui_extension_context/ui_extension_context.js index cae8c4be3b5..b7892770f8a 100755 --- a/frameworks/js/napi/ui_extension_context/ui_extension_context.js +++ b/frameworks/js/napi/ui_extension_context/ui_extension_context.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -71,6 +71,11 @@ class UIExtensionContext extends ExtensionContext { return this.__context_impl__.startAbilityForResultAsCaller(want, options, callback); } + startAbilities(wantList) { + hilog.sLogI(domainID, TAG, 'startAbilities'); + return this.__context_impl__.startAbilities(wantList); + } + terminateSelfWithResult(abilityResult, callback) { hilog.sLogI(domainID, TAG, 'terminateSelfWithResult'); return this.__context_impl__.terminateSelfWithResult(abilityResult, callback); diff --git a/frameworks/native/ability/native/js_service_extension_context.cpp b/frameworks/native/ability/native/js_service_extension_context.cpp index 04584705793..f64c865cd97 100644 --- a/frameworks/native/ability/native/js_service_extension_context.cpp +++ b/frameworks/native/ability/native/js_service_extension_context.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -45,6 +45,7 @@ constexpr int32_t INDEX_ZERO = 0; constexpr int32_t INDEX_ONE = 1; constexpr int32_t INDEX_TWO = 2; constexpr int32_t INDEX_THREE = 3; +constexpr int32_t INDEX_FOUR = 4; constexpr int32_t ERROR_CODE_ONE = 1; constexpr int32_t ERROR_CODE_TWO = 2; constexpr size_t ARGC_ZERO = 0; @@ -127,6 +128,11 @@ public: GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartAbilityWithAccount); } + static napi_value StartAbilities(napi_env env, napi_callback_info info) + { + GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartAbilities); + } + static napi_value ConnectAbilityWithAccount(napi_env env, napi_callback_info info) { GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnConnectAbilityWithAccount); @@ -743,6 +749,83 @@ private: return true; } + napi_value OnStartAbilities(napi_env env, NapiCallbackInfo& info) + { + TAG_LOGI(AAFwkTag::UI_EXT, "call OnStartAbilities"); + if (info.argc < ARGC_ONE) { + TAG_LOGE(AAFwkTag::UI_EXT, "Too few parameters."); + ThrowTooFewParametersError(env); + return CreateJsUndefined(env); + } + + std::vector wantList; + std::string requestKey = std::to_string(std::chrono::duration_cast(std::chrono:: + system_clock::now().time_since_epoch()).count()); + + if (!UnwrapWantList(env, info, wantList)) { + TAG_LOGE(AAFwkTag::UI_EXT, "Unwrap wantList param failed."); + return CreateJsUndefined(env); + } + + TAG_LOGD(AAFwkTag::UI_EXT, "startAbilities wantListLength: %{public}zu", wantList.size()); + + napi_value result = nullptr; + auto innerErrCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [weak = context_, wantList, requestKey, innerErrCode]() { + auto context = weak.lock(); + if (!context) { + TAG_LOGW(AAFwkTag::UI_EXT, "null context"); + *innerErrCode = static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return; + } + *innerErrCode = context->StartAbilities(wantList, requestKey); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrCode, weak = context_] + (napi_env env, NapiAsyncTask& task, int32_t status) { + TAG_LOGI(AAFwkTag::UI_EXT, "startAbilities complete innerErrCode: %{public}d", *innerErrCode); + if (*innerErrCode == 0) { + task.Resolve(env, CreateJsUndefined(env)); + return; + } + task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode)); + }; + + NapiAsyncTask::ScheduleHighQos("JSUIExtensionConnection::OnStartAbilities", env, + CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result)); + return result; + } + + bool UnwrapWantList(napi_env env, NapiCallbackInfo &info, std::vector &wantList) + { + AppExecFwk::ComplexArrayData jsWantList; + if (!AppExecFwk::UnwrapArrayComplexFromJS(env, info.argv[INDEX_ZERO], jsWantList)) { + TAG_LOGE(AAFwkTag::UI_EXT, "wantList not array."); + ThrowInvalidParamError(env, "wantList not array"); + return false; + } + + size_t jsWantSize = jsWantList.objectList.size(); + if (jsWantSize < INDEX_ONE || jsWantSize > INDEX_FOUR) { + TAG_LOGE(AAFwkTag::UI_EXT, "wantList size not support"); + ThrowInvalidParamError(env, "wantList size error"); + return false; + } + + for (uint32_t index = 0; index < jsWantSize; index++) { + AAFwk::Want curWant; + if (!OHOS::AppExecFwk::UnwrapWant(env, jsWantList.objectList[index], curWant)) { + TAG_LOGE(AAFwkTag::UI_EXT, "startAbilities parse want failed"); + ThrowInvalidParamError(env, "parse want error"); + return false; + } + TAG_LOGD(AAFwkTag::UI_EXT, "startAbilities ability:%{public}s", + curWant.GetElement().GetAbilityName().c_str()); + wantList.emplace_back(curWant); + } + return true; + } + bool CheckConnectAbilityWithAccountInputParam( napi_env env, NapiCallbackInfo& info, AAFwk::Want& want, int32_t& accountId, sptr& connection) const @@ -1404,6 +1487,7 @@ napi_value CreateJsServiceExtensionContext(napi_env env, std::shared_ptr wantList; + std::string requestKey = std::to_string(std::chrono::duration_cast(std::chrono:: + system_clock::now().time_since_epoch()).count()); + + if (!UnwrapWantList(env, info, wantList)) { + TAG_LOGE(AAFwkTag::UI_EXT, "Unwrap wantList param failed."); + return CreateJsUndefined(env); + } + + TAG_LOGD(AAFwkTag::UI_EXT, "startAbilities wantListLength: %{public}zu", wantList.size()); + + napi_value result = nullptr; + auto innerErrCode = std::make_shared(ERR_OK); + NapiAsyncTask::ExecuteCallback execute = [weak = context_, wantList, requestKey, innerErrCode]() { + auto context = weak.lock(); + if (!context) { + TAG_LOGW(AAFwkTag::UI_EXT, "null context"); + *innerErrCode = static_cast(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT); + return; + } + *innerErrCode = context->StartAbilities(wantList, requestKey); + }; + + NapiAsyncTask::CompleteCallback complete = [innerErrCode, weak = context_] + (napi_env env, NapiAsyncTask& task, int32_t status) { + TAG_LOGI(AAFwkTag::UI_EXT, "startAbilities complete innerErrCode: %{public}d", *innerErrCode); + if (*innerErrCode == 0) { + task.Resolve(env, CreateJsUndefined(env)); + return; + } + task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode)); + }; + + NapiAsyncTask::ScheduleHighQos("JSUIExtensionConnection::OnStartAbilities", env, + CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result)); + return result; +} + +bool JsUIExtensionContext::UnwrapWantList(napi_env env, NapiCallbackInfo &info, std::vector &wantList) +{ + AppExecFwk::ComplexArrayData jsWantList; + if (!AppExecFwk::UnwrapArrayComplexFromJS(env, info.argv[INDEX_ZERO], jsWantList)) { + TAG_LOGE(AAFwkTag::UI_EXT, "wantList not array."); + ThrowInvalidParamError(env, "wantList not array"); + return false; + } + + size_t jsWantSize = jsWantList.objectList.size(); + if (jsWantSize < INDEX_ONE || jsWantSize > INDEX_FOUR) { + TAG_LOGE(AAFwkTag::UI_EXT, "wantList size not support"); + ThrowInvalidParamError(env, "wantList size error"); + return false; + } + + for (uint32_t index = 0; index < jsWantSize; index++) { + AAFwk::Want curWant; + if (!OHOS::AppExecFwk::UnwrapWant(env, jsWantList.objectList[index], curWant)) { + TAG_LOGE(AAFwkTag::UI_EXT, "startAbilities parse want failed"); + ThrowInvalidParamError(env, "parse want error"); + return false; + } + TAG_LOGD(AAFwkTag::UI_EXT, "startAbilities ability:%{public}s", + curWant.GetElement().GetAbilityName().c_str()); + wantList.emplace_back(curWant); + } + return true; +} + napi_value JsUIExtensionContext::OnConnectAbility(napi_env env, NapiCallbackInfo& info) { TAG_LOGD(AAFwkTag::UI_EXT, "called"); @@ -1317,6 +1400,7 @@ napi_value JsUIExtensionContext::CreateJsUIExtensionContext(napi_env env, BindNativeFunction(env, objValue, "startAbilityForResult", moduleName, StartAbilityForResult); BindNativeFunction(env, objValue, "terminateSelfWithResult", moduleName, TerminateSelfWithResult); BindNativeFunction(env, objValue, "startAbilityForResultAsCaller", moduleName, StartAbilityForResultAsCaller); + BindNativeFunction(env, objValue, "startAbilities", moduleName, StartAbilities); BindNativeFunction(env, objValue, "connectServiceExtensionAbility", moduleName, ConnectAbility); BindNativeFunction(env, objValue, "disconnectServiceExtensionAbility", moduleName, DisconnectAbility); BindNativeFunction(env, objValue, "reportDrawnCompleted", moduleName, ReportDrawnCompleted); diff --git a/frameworks/native/ability/native/ui_extension_base/ui_extension_context.cpp b/frameworks/native/ability/native/ui_extension_base/ui_extension_context.cpp index 57510b29014..f1f7848d470 100755 --- a/frameworks/native/ability/native/ui_extension_base/ui_extension_context.cpp +++ b/frameworks/native/ability/native/ui_extension_base/ui_extension_context.cpp @@ -136,6 +136,16 @@ ErrCode UIExtensionContext::StartServiceExtensionAbility(const AAFwk::Want& want return ret; } +ErrCode UIExtensionContext::StartAbilities(const std::vector &wantList, const std::string &requestKey) +{ + TAG_LOGD(AAFwkTag::UI_EXT, "call StartAbilities"); + ErrCode err = AAFwk::AbilityManagerClient::GetInstance()->StartAbilities(wantList, requestKey, token_); + if (err != ERR_OK) { + TAG_LOGE(AAFwkTag::UI_EXT, "StartAbilities ret=%{public}d", err); + } + return err; +} + ErrCode UIExtensionContext::StartAbilityForResult(const AAFwk::Want &want, int requestCode, RuntimeTask &&task) { TAG_LOGD(AAFwkTag::UI_EXT, "begin"); diff --git a/frameworks/native/appkit/ability_runtime/service_extension_context.cpp b/frameworks/native/appkit/ability_runtime/service_extension_context.cpp index fd9a99c5616..b20b76ad83d 100644 --- a/frameworks/native/appkit/ability_runtime/service_extension_context.cpp +++ b/frameworks/native/appkit/ability_runtime/service_extension_context.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -154,6 +154,16 @@ ErrCode ServiceExtensionContext::StartAbilityWithAccount( return err; } +ErrCode ServiceExtensionContext::StartAbilities(const std::vector &wantList, const std::string &requestKey) +{ + TAG_LOGD(AAFwkTag::APPKIT, "call StartAbilities"); + ErrCode err = AAFwk::AbilityManagerClient::GetInstance()->StartAbilities(wantList, requestKey, token_); + if (err != ERR_OK) { + TAG_LOGE(AAFwkTag::APPKIT, "StartAbilities ret=%{public}d", err); + } + return err; +} + ErrCode ServiceExtensionContext::StartServiceExtensionAbility(const AAFwk::Want &want, int32_t accountId) const { TAG_LOGD(AAFwkTag::APPKIT, "begin"); diff --git a/interfaces/inner_api/ability_manager/include/ability_manager_client.h b/interfaces/inner_api/ability_manager/include/ability_manager_client.h index 1121e609a31..141e9ceb1bb 100644 --- a/interfaces/inner_api/ability_manager/include/ability_manager_client.h +++ b/interfaces/inner_api/ability_manager/include/ability_manager_client.h @@ -284,6 +284,17 @@ public: int requestCode = DEFAULT_INVAL_VALUE, int32_t userId = DEFAULT_INVAL_VALUE); + /** + * @brief start abilities simultaneously. + * + * @param wantList a list of want to start abilities. + * @param callerToken current caller ability token. + * @param userId, Designation User ID. + * @return Returns ERR_OK if success. + */ + ErrCode StartAbilities(const std::vector &wantList, + const std::string &requestKey, const sptr &callerToken); + /** * Start ui session ability with extension session info, send session info to ability manager service. * 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 08b2c5c6ace..ebe27bb9793 100644 --- a/interfaces/inner_api/ability_manager/include/ability_manager_errors.h +++ b/interfaces/inner_api/ability_manager/include/ability_manager_errors.h @@ -908,6 +908,34 @@ enum { */ ERR_ABILITY_DEBUG_EMPTY_TOKENS = 2097362, + /** + * Result (2097363-2097371) for StartAbilities Error. + */ + START_ABILITIES_NOT_SUPPORT_DLP = 2097363, + + START_ABILITIES_NOT_SUPPORT_START_PLUGIN = 2097364, + + START_ABILITIES_NOT_SUPPORT_CREATE_APP_INSTANCE_KEY = 2097365, + + START_ABILITIES_NOT_SUPPORT_OPERATE_REMOTE = 2097366, + + START_ABILITIES_NOT_SUPPORT_CROSS_USER = 2097367, + + START_ABILITIES_NOT_SUPPORT_IMPLICIT_START = 2097368, + + START_ABILITIES_ONLY_SUPPORT_UI_ABILITY = 2097369, + + START_ABILITIES_INTERCEPTOR_CHECK_FAILED = 2097370, + + START_ABILITIES_WAITTING_SPECIFIED_CODE = 2097371, + + /* + * Result(2097372) for IPC write Int32 failed. + */ + ERR_WRITE_INT32_FAILED = 2097372, + + ERR_WRITE_STRING_FAILED = 2097373, + /** * Native error(3000000) for target bundle not exist. */ diff --git a/interfaces/inner_api/ability_manager/include/ability_manager_interface.h b/interfaces/inner_api/ability_manager/include/ability_manager_interface.h index 20529bbc02c..93a15a3ef4e 100644 --- a/interfaces/inner_api/ability_manager/include/ability_manager_interface.h +++ b/interfaces/inner_api/ability_manager/include/ability_manager_interface.h @@ -304,6 +304,20 @@ public: return 0; } + /** + * @brief start abilities simultaneously. + * + * @param wantList a list of want to start abilities. + * @param callerToken current caller ability token. + * @param userId, Designation User ID. + * @return Returns ERR_OK if success. + */ + virtual ErrCode StartAbilities(const std::vector &wantList, + const std::string &requestKey, const sptr &callerToken) + { + return 0; + } + /** * Start ui session ability with extension session info, send session info to ability manager service. * diff --git a/interfaces/inner_api/ability_manager/include/ability_manager_ipc_interface_code.h b/interfaces/inner_api/ability_manager/include/ability_manager_ipc_interface_code.h index de80df5b372..995255357da 100644 --- a/interfaces/inner_api/ability_manager/include/ability_manager_ipc_interface_code.h +++ b/interfaces/inner_api/ability_manager/include/ability_manager_ipc_interface_code.h @@ -417,6 +417,8 @@ enum class AbilityManagerInterfaceCode { CLOSE_UI_EXTENSION_ABILITY_BY_SCB = 1069, SEND_LOCAL_PENDING_WANT_SENDER = 1070, + // ipc id for start abilities + START_ABILITIES = 1071, // ipc id for continue ability(1101) START_CONTINUATION = 1101, diff --git a/interfaces/kits/native/ability/native/ui_extension_base/js_ui_extension_context.h b/interfaces/kits/native/ability/native/ui_extension_base/js_ui_extension_context.h index 8e74c60d1df..8a6be8a53d4 100755 --- a/interfaces/kits/native/ability/native/ui_extension_base/js_ui_extension_context.h +++ b/interfaces/kits/native/ability/native/ui_extension_base/js_ui_extension_context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -40,6 +40,7 @@ public: static napi_value CreateJsUIExtensionContext(napi_env env, std::shared_ptr context); static napi_value StartAbilityForResult(napi_env env, napi_callback_info info); static napi_value StartAbilityForResultAsCaller(napi_env env, napi_callback_info info); + static napi_value StartAbilities(napi_env env, napi_callback_info info); static napi_value ConnectAbility(napi_env env, napi_callback_info info); static napi_value DisconnectAbility(napi_env env, napi_callback_info info); static napi_value ReportDrawnCompleted(napi_env env, napi_callback_info info); @@ -60,6 +61,7 @@ protected: virtual napi_value OnTerminateSelfWithResult(napi_env env, NapiCallbackInfo& info); virtual napi_value OnStartAbilityForResult(napi_env env, NapiCallbackInfo& info); virtual napi_value OnStartAbilityForResultAsCaller(napi_env env, NapiCallbackInfo &info); + virtual napi_value OnStartAbilities(napi_env env, NapiCallbackInfo& info); virtual napi_value OnConnectAbility(napi_env env, NapiCallbackInfo& info); virtual napi_value OnDisconnectAbility(napi_env env, NapiCallbackInfo& info); virtual napi_value OnReportDrawnCompleted(napi_env env, NapiCallbackInfo& info); @@ -93,6 +95,7 @@ private: const AAFwk::StartOptions &options, size_t unwrapArgc); void AddFreeInstallObserver(napi_env env, const AAFwk::Want &want, napi_value callback, napi_value* result, bool isAbilityResult = false, bool isOpenLink = false); + bool UnwrapWantList(napi_env env, NapiCallbackInfo &info, std::vector &wantList); bool CreateOpenLinkTask(const napi_env &env, const napi_value &lastParam, AAFwk::Want &want, int &requestCode); napi_value OnOpenLink(napi_env env, NapiCallbackInfo& info); diff --git a/interfaces/kits/native/ability/native/ui_extension_base/ui_extension_context.h b/interfaces/kits/native/ability/native/ui_extension_base/ui_extension_context.h index 8f82651f6d6..6c9dec801d7 100755 --- a/interfaces/kits/native/ability/native/ui_extension_base/ui_extension_context.h +++ b/interfaces/kits/native/ability/native/ui_extension_base/ui_extension_context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -98,6 +98,8 @@ public: */ ErrCode StartServiceExtensionAbility(const AAFwk::Want &want, int32_t accountId = -1); + ErrCode StartAbilities(const std::vector &wantList, const std::string &requestKey); + /** * Start other ability for result. * diff --git a/interfaces/kits/native/appkit/ability_runtime/service_extension_context.h b/interfaces/kits/native/appkit/ability_runtime/service_extension_context.h index 3baf1b6f15c..49566a8aea2 100644 --- a/interfaces/kits/native/appkit/ability_runtime/service_extension_context.h +++ b/interfaces/kits/native/appkit/ability_runtime/service_extension_context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -122,6 +122,8 @@ public: ErrCode StartAbilityWithAccount( const AAFwk::Want &want, int accountId, const AAFwk::StartOptions &startOptions) const; + + ErrCode StartAbilities(const std::vector &wantList, const std::string &requestKey); ErrCode StartServiceExtensionAbility(const AAFwk::Want &want, int32_t accountId = -1) const; diff --git a/services/abilitymgr/include/ability_manager_proxy.h b/services/abilitymgr/include/ability_manager_proxy.h index d1bb59d1c7b..bceb677b2c4 100644 --- a/services/abilitymgr/include/ability_manager_proxy.h +++ b/services/abilitymgr/include/ability_manager_proxy.h @@ -216,6 +216,17 @@ public: int requestCode = DEFAULT_INVAL_VALUE, int32_t userId = DEFAULT_INVAL_VALUE) override; + /** + * @brief start abilities simultaneously. + * + * @param wantList a list of want to start abilities. + * @param requestKey, The unique key of this StartAbilities request. + * @param callerToken current caller ability token. + * @return Returns ERR_OK if success. + */ + ErrCode StartAbilities(const std::vector &wantList, + const std::string &requestKey, const sptr &callerToken) override; + /** * Start ui session ability with extension session info, send session info to ability manager service. * diff --git a/services/abilitymgr/include/ability_manager_service.h b/services/abilitymgr/include/ability_manager_service.h index ded50025797..99896a5479b 100644 --- a/services/abilitymgr/include/ability_manager_service.h +++ b/services/abilitymgr/include/ability_manager_service.h @@ -336,6 +336,18 @@ public: int requestCode = DEFAULT_INVAL_VALUE, int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * @brief start abilities simultaneously. + * + * @param wantList a list of want to start abilities. + * @param requestKey, The unique key of this StartAbilities request. + * @param callerToken current caller ability token. + * @return Returns ERR_OK if success. + */ + ErrCode StartAbilities(const std::vector &wantList, + const std::string &requestKey, const sptr &callerToken) override; + /** * Start ui session ability with extension session info, send session info to ability manager service. * @@ -2548,6 +2560,13 @@ private: virtual int RegisterSessionHandler(const sptr &object) override; + int32_t StartAbilitiesHandleWant(std::vector &abilityRequestList, + const Want &want, const sptr &callerToken); + int32_t StartAbilitiesCheckDlp(const Want &want, const sptr &callerToken); + int32_t StartAbilitiesProcessAppIndex(int32_t &appIndex, Want &want, + const sptr &callerToken); + int32_t StartAbilitiesInterceptorCheck(const Want &want, AbilityRequest &abilityRequest, + const sptr &callerToken, int32_t appIndex); /** * Start switch user dialog Extension ability. */ diff --git a/services/abilitymgr/include/ability_manager_stub.h b/services/abilitymgr/include/ability_manager_stub.h index 75ac158a7c0..7894a50b2c1 100644 --- a/services/abilitymgr/include/ability_manager_stub.h +++ b/services/abilitymgr/include/ability_manager_stub.h @@ -296,6 +296,7 @@ private: int StartAbilityForResultAsCallerInner(MessageParcel &data, MessageParcel &reply); int StartAbilityForResultAsCallerForOptionsInner(MessageParcel &data, MessageParcel &reply); + int32_t StartAbilitiesInner(MessageParcel &data, MessageParcel &reply); int32_t StartAbilityOnlyUIAbilityInner(MessageParcel &data, MessageParcel &reply); diff --git a/services/abilitymgr/include/scene_board/ui_ability_lifecycle_manager.h b/services/abilitymgr/include/scene_board/ui_ability_lifecycle_manager.h index c6711837da5..3a8ce8761fc 100644 --- a/services/abilitymgr/include/scene_board/ui_ability_lifecycle_manager.h +++ b/services/abilitymgr/include/scene_board/ui_ability_lifecycle_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Copyright (c) 2023-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -46,6 +46,7 @@ struct SpecifiedRequest { SpecifiedProcessState specifiedProcessState = SpecifiedProcessState::STATE_NONE; int32_t requestId = 0; int32_t persistentId = 0; + int32_t requestListId = -1; uint32_t sceneFlag = 0; uint32_t callingTokenId = 0; AbilityRequest abilityRequest; @@ -53,6 +54,14 @@ struct SpecifiedRequest { SpecifiedRequest(int32_t requestId, AbilityRequest request) : requestId(requestId), abilityRequest(request) {} }; +struct AbilitiesRequest { + std::vector waitingRequestIdList; + std::vector abilityRequestList; + std::vector> UnsortedSessionInfoList; + + AbilitiesRequest(std::vector abilityRequestList) : abilityRequestList(abilityRequestList) {} +}; + class UIAbilityLifecycleManager : public std::enable_shared_from_this { public: UIAbilityLifecycleManager() = default; @@ -164,6 +173,7 @@ public: void SetRootSceneSession(const sptr &rootSceneSession); int NotifySCBToStartUIAbility(AbilityRequest &abilityRequest); + int32_t NotifySCBToStartUIAbilities(std::vector &abilityRequestList); int NotifySCBToPreStartUIAbility(const AbilityRequest &abilityRequest, sptr &sessionInfo); @@ -443,6 +453,8 @@ private: sptr CreateSessionInfo(const AbilityRequest &abilityRequest) const; int NotifySCBPendingActivation(sptr &sessionInfo, const AbilityRequest &abilityRequest, std::string &errMsg); + int32_t BatchNotifySCBPendingActivation(std::vector> &sessionInfoList, + const std::vector &abilityRequestList, std::string &errMsg); bool IsHookModule(const AbilityRequest &abilityRequest) const; int ResolveAbility(const std::shared_ptr &targetAbility, const AbilityRequest &abilityRequest) const; std::vector> GetAbilityRecordsByNameInner(const AppExecFwk::ElementName &element); @@ -566,6 +578,8 @@ private: std::vector> prepareTerminateByPidRecords_; std::unordered_map> hookSpecifiedMap_; + ffrt::mutex startAbilitiesProcessLock_; + std::map> abilitiesRequestMap_; std::mutex startingPidsMutex_; std::vector startingPids_; }; diff --git a/services/abilitymgr/include/utils/start_ability_utils.h b/services/abilitymgr/include/utils/start_ability_utils.h index f6a62e2cb5f..d615898b049 100644 --- a/services/abilitymgr/include/utils/start_ability_utils.h +++ b/services/abilitymgr/include/utils/start_ability_utils.h @@ -22,6 +22,7 @@ #include "ability_info.h" #include "extension_ability_info.h" #include "want.h" +#include "scene_board_judgement.h" namespace OHOS { namespace AAFwk { @@ -59,7 +60,7 @@ struct StartAbilityUtils { static std::vector GetCloneAppIndexes(const std::string &bundleName, int32_t userId); static bool IsCallFromAncoShellOrBroker(const sptr &callerToken); - + static bool IsSupportStartAbilities(); static thread_local std::shared_ptr startAbilityInfo; static thread_local std::shared_ptr callerAbilityInfo; static thread_local bool skipCrowTest; diff --git a/services/abilitymgr/src/ability_manager_client.cpp b/services/abilitymgr/src/ability_manager_client.cpp index 89b5bdc6435..7f7033180e6 100644 --- a/services/abilitymgr/src/ability_manager_client.cpp +++ b/services/abilitymgr/src/ability_manager_client.cpp @@ -261,6 +261,19 @@ ErrCode AbilityManagerClient::StartAbilityForResultAsCaller(const Want &want, co return abms->StartAbilityForResultAsCaller(want, startOptions, callerToken, requestCode, userId); } +ErrCode AbilityManagerClient::StartAbilities(const std::vector &wantList, + const std::string &requestKey, const sptr &callerToken) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGI(AAFwkTag::ABILITYMGR, "call StartAbilities"); + auto abms = GetAbilityManager(); + CHECK_POINTER_RETURN_NOT_CONNECTED(abms); + for (const Want &item : wantList) { + HandleDlpApp(const_cast(item)); + } + return abms->StartAbilities(wantList, requestKey, callerToken); +} + ErrCode AbilityManagerClient::StartAbilityByUIContentSession(const Want &want, const StartOptions &startOptions, sptr callerToken, sptr sessionInfo, int requestCode, int32_t userId) diff --git a/services/abilitymgr/src/ability_manager_proxy.cpp b/services/abilitymgr/src/ability_manager_proxy.cpp index 8854ad86ad3..c563dacd351 100644 --- a/services/abilitymgr/src/ability_manager_proxy.cpp +++ b/services/abilitymgr/src/ability_manager_proxy.cpp @@ -42,6 +42,7 @@ using AutoStartupInfo = AbilityRuntime::AutoStartupInfo; constexpr int32_t CYCLE_LIMIT = 1000; constexpr int32_t MAX_AUTO_STARTUP_COUNT = 100; constexpr int32_t MAX_UPDATE_CONFIG_SIZE = 100; +constexpr int32_t MAX_WANT_LIST_SIZE = 4; bool AbilityManagerProxy::WriteInterfaceToken(MessageParcel &data) { if (!data.WriteInterfaceToken(AbilityManagerProxy::GetDescriptor())) { @@ -497,6 +498,55 @@ int AbilityManagerProxy::StartAbilityForResultAsCaller(const Want &want, const S return reply.ReadInt32(); } +ErrCode AbilityManagerProxy::StartAbilities(const std::vector &wantList, + const std::string &requestKey, const sptr &callerToken) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (callerToken == nullptr) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "null callerToken"); + return INVALID_CALLER_TOKEN; + } + if (!WriteInterfaceToken(data)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "write token fail"); + return ERR_WRITE_INTERFACE_TOKEN_FAILED; + } + + int32_t size = static_cast(wantList.size()); + if (!(size > 0 && size <= MAX_WANT_LIST_SIZE)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "vector size error"); + return ERR_NATIVE_IPC_PARCEL_FAILED; + } + if (!data.WriteInt32(size)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "write size fail"); + return ERR_WRITE_INT32_FAILED; + } + for (const Want &item : wantList) { + if (!data.WriteParcelable(&item)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "write want fail"); + return ERR_WRITE_WANT; + } + } + + if (!data.WriteString(requestKey)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "write requestKey fail"); + return ERR_WRITE_STRING_FAILED; + } + + if (!data.WriteRemoteObject(callerToken)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "write callerToken fail"); + return ERR_WRITE_CALLER_TOKEN_FAILED; + } + + auto error = SendRequest(AbilityManagerInterfaceCode::START_ABILITIES, data, reply, option); + if (error != NO_ERROR) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "request error:%{public}d", error); + return error; + } + return reply.ReadInt32(); +} + int AbilityManagerProxy::CheckUISessionParams(MessageParcel &data, const sptr &callerToken, const sptr &sessionInfo, int32_t userId, int requestCode) { diff --git a/services/abilitymgr/src/ability_manager_service.cpp b/services/abilitymgr/src/ability_manager_service.cpp index 87192be9a16..2eac6f3d09c 100644 --- a/services/abilitymgr/src/ability_manager_service.cpp +++ b/services/abilitymgr/src/ability_manager_service.cpp @@ -2170,6 +2170,234 @@ int AbilityManagerService::StartAbilityForOptionInner(const Want &want, const St return ret; } +ErrCode AbilityManagerService::StartAbilities(const std::vector &wantList, + const std::string &requestKey, const sptr &callerToken) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + XCOLLIE_TIMER_DEFAULT(__PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::ABILITYMGR, "Call StartAbilities"); + std::vector abilityRequestList; + int32_t oriValidUserId = GetValidUserId(DEFAULT_INVAL_VALUE); + + if (!StartAbilityUtils::IsSupportStartAbilities()) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities is not supported"); + return ERR_CAPABILITY_NOT_SUPPORT; + } + + if (callerToken == nullptr || !VerificationAllToken(callerToken)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities %{public}s verificationAllToken failed", __func__); + return ERR_INVALID_CALLER; + } + + for (const Want &want : wantList) { + int32_t ret = StartAbilitiesHandleWant(abilityRequestList, want, callerToken); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities want process block"); + return ret; + } + } + + TAG_LOGD(AAFwkTag::ABILITYMGR, "StartAbilities ready to NotifySCBToStartUIAbilities"); + for (AbilityRequest &abilityRequest : abilityRequestList) { + auto abilityInfo = abilityRequest.abilityInfo; + ReportEventToRSS(abilityInfo, abilityRequest.callerToken); + abilityRequest.userId = oriValidUserId; + abilityRequest.want.SetParam(ServerConstant::IS_CALL_BY_SCB, false); + } + auto uiAbilityManager = GetUIAbilityManagerByUserId(oriValidUserId); + CHECK_POINTER_AND_RETURN(uiAbilityManager, ERR_INVALID_VALUE); + return uiAbilityManager->NotifySCBToStartUIAbilities(abilityRequestList); +} + +int32_t AbilityManagerService::StartAbilitiesHandleWant(std::vector &abilityRequestList, + const Want &want, const sptr &callerToken) +{ + int32_t userId = DEFAULT_INVAL_VALUE; + int32_t validUserId = GetValidUserId(userId); + uint32_t specifyTokenId = 0; + int32_t requestCode = DEFAULT_INVAL_VALUE; + + AbilityUtil::RemoveShowModeKey(const_cast(want)); + + //intent openlink do not RemoveInsightIntent action + if (!want.HasParameter(AppExecFwk::INSIGHT_INTENT_EXECUTE_OPENLINK_FLAG)) { + InsightIntentExecuteParam::RemoveInsightIntent(const_cast(want)); + } + +#ifdef SUPPORT_SCREEN + DmsUtil::GetInstance().UpdateFlagForCollaboration(want); +#endif + + if (AbilityRuntime::StartupUtil::IsStartPlugin(want)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities not support StartPlugin"); + return START_ABILITIES_NOT_SUPPORT_START_PLUGIN; + } + + AbilityUtil::RemoveWindowModeKey(const_cast(want)); + + if (want.GetBoolParam(Want::CREATE_APP_INSTANCE_KEY, false)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities not support CREATE_APP_INSTANCE_KEY"); + return START_ABILITIES_NOT_SUPPORT_CREATE_APP_INSTANCE_KEY; + } + + int32_t ret = StartAbilitiesCheckDlp(want, callerToken); + if (ret != ERR_OK) { + return ret; + } + + int32_t appIndex = 0; + ret = StartAbilitiesProcessAppIndex(appIndex, const_cast(want), callerToken); + if (ret != ERR_OK) { + return ret; + } + ret = AbilityPermissionUtil::GetInstance().CheckMultiInstanceAndAppClone( + const_cast(want), validUserId, appIndex, callerToken, false); + if (ret != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities CheckMultiInstanceAndAppClone failed"); + return ret; + } + + StartAbilityInfoWrap threadLocalInfo(want, validUserId, appIndex, callerToken); + + if (CheckIfOperateRemote(want)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities not support StartRemoteAbility"); + return START_ABILITIES_NOT_SUPPORT_OPERATE_REMOTE; + } + + if (!JudgeMultiUserConcurrency(validUserId)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities multi-user non-concurrent unsatisfied"); + return START_ABILITIES_NOT_SUPPORT_CROSS_USER; + } +#ifdef SUPPORT_SCREEN + if (ImplicitStartProcessor::IsImplicitStartAction(want)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities not support implicit start"); + return START_ABILITIES_NOT_SUPPORT_IMPLICIT_START; + } +#endif + AbilityRequest abilityRequest; + auto result = GenerateAbilityRequest(want, requestCode, abilityRequest, callerToken, validUserId); + auto abilityRecord = Token::GetAbilityRecordByToken(callerToken); + std::string callerBundleName = abilityRecord ? abilityRecord->GetAbilityInfo().bundleName : ""; + if (result != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "generate ability request local error"); + return result; + } + + UpdateCallerInfoUtil::GetInstance().UpdateCallerInfo(abilityRequest.want, callerToken); + + auto abilityInfo = abilityRequest.abilityInfo; + if (abilityInfo.type != AbilityType::PAGE) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities only support UIAbility"); + return START_ABILITIES_ONLY_SUPPORT_UI_ABILITY; + } + + result = CheckStaticCfgPermission(abilityRequest, false, + abilityRequest.want.GetIntParam(Want::PARAM_RESV_CALLER_TOKEN, 0), false, false, false); + if (result != AppExecFwk::Constants::PERMISSION_GRANTED) { + TAG_LOGE(AAFwkTag::ABILITYMGR, + "StartAbilities checkStaticCfgPermission error, result:%{public}d", result); + return ERR_STATIC_CFG_PERMISSION; + } + result = CheckCallPermission(want, abilityInfo, abilityRequest, false, + false, specifyTokenId, callerBundleName); + if (result != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, + "StartAbilities checkCallPermission error, result:%{public}d", result); + return result; + } + + result = StartAbilitiesInterceptorCheck(want, abilityRequest, callerToken, appIndex); + if (result != ERR_OK) { + return result; + } + + Want newWant = abilityRequest.want; + bool isReplaceWantExist = newWant.GetBoolParam("queryWantFromErms", false); + newWant.RemoveParam("queryWantFromErms"); + + auto callerTokenId = IPCSkeleton::GetCallingTokenID(); + RemoveUnauthorizedLaunchReasonMessage(want, abilityRequest, callerTokenId); + + if (!IsAbilityControllerStart(want, abilityInfo.bundleName)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, + "StartAbilities isAbilityControllerStart failed:%{public}s", abilityInfo.bundleName.c_str()); + return ERR_WOULD_BLOCK; + } + abilityRequest.want.RemoveParam(SPECIFY_TOKEN_ID); + abilityRequest.want.RemoveParam(PARAM_SPECIFIED_PROCESS_FLAG); + abilityRequestList.emplace_back(abilityRequest); + return ERR_OK; +} + +int32_t AbilityManagerService::StartAbilitiesCheckDlp(const Want &want, const sptr &callerToken) +{ +#ifdef WITH_DLP + int32_t userId = DEFAULT_INVAL_VALUE; + if (AbilityUtil::HandleDlpApp(const_cast(want))) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities not support Dlp"); + return START_ABILITIES_NOT_SUPPORT_DLP; + } + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "CHECK_DLP"); + if (!DlpUtils::OtherAppsAccessDlpCheck(callerToken, want) || + VerifyAccountPermission(userId) == CHECK_PERMISSION_FAILED || + !DlpUtils::DlpAccessOtherAppsCheck(callerToken, want)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, + "StartAbilities Dlp %{public}s: permission verification failed", __func__); + return CHECK_PERMISSION_FAILED; + } +#endif // WITH_DLP + return ERR_OK; +} + +int32_t AbilityManagerService::StartAbilitiesProcessAppIndex(int32_t &appIndex, Want &want, + const sptr &callerToken) +{ + SetTargetCloneIndexInSameBundle(want, callerToken); + if (!want.HasParameter(AAFwk::Want::PARAM_APP_CLONE_INDEX_KEY)) { + want.SetParam(AAFwk::Want::PARAM_APP_CLONE_INDEX_KEY, 0); + } + if (!StartAbilityUtils::GetAppIndex(want, callerToken, appIndex)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities GetAppIndex failed."); + return ERR_APP_CLONE_INDEX_INVALID; + } + return ERR_OK; +} + +int32_t AbilityManagerService::StartAbilitiesInterceptorCheck(const Want &want, AbilityRequest &abilityRequest, + const sptr &callerToken, int32_t appIndex) +{ + int32_t requestCode = DEFAULT_INVAL_VALUE; + Want newWant = abilityRequest.want; + auto abilityInfo = abilityRequest.abilityInfo; + auto shouldBlockFunc = [aams = shared_from_this()]() { return aams->ShouldBlockAllAppStart(); }; + AbilityInterceptorParam interceptorParam = AbilityInterceptorParam(want, requestCode, GetUserId(), + true, nullptr, shouldBlockFunc); + int32_t result = interceptorExecuter_ == nullptr ? ERR_NULL_INTERCEPTOR_EXECUTER : + interceptorExecuter_->DoProcess(interceptorParam); + if (result == ERR_CROWDTEST_EXPIRED) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities ERR_CROWDTEST_EXPIRED"); + return result; + } + if (result != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities interceptorExecuter_ null or DoProcess error"); + return START_ABILITIES_INTERCEPTOR_CHECK_FAILED; + } + + AbilityInterceptorParam afterCheckParam = AbilityInterceptorParam(newWant, requestCode, GetUserId(), + true, callerToken, std::make_shared(abilityInfo), false, appIndex); + result = afterCheckExecuter_ == nullptr ? ERR_INVALID_VALUE : + afterCheckExecuter_->DoProcess(afterCheckParam); + if (result == ERR_CROWDTEST_EXPIRED) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities ERR_CROWDTEST_EXPIRED"); + return result; + } + if (result != ERR_OK) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities afterCheckExecuter_ null or DoProcess error"); + return START_ABILITIES_INTERCEPTOR_CHECK_FAILED; + } + return ERR_OK; +} + int32_t AbilityManagerService::RequestDialogService(const Want &want, const sptr &callerToken) { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); diff --git a/services/abilitymgr/src/ability_manager_stub.cpp b/services/abilitymgr/src/ability_manager_stub.cpp index a11f4f41b3e..086e8ad9021 100644 --- a/services/abilitymgr/src/ability_manager_stub.cpp +++ b/services/abilitymgr/src/ability_manager_stub.cpp @@ -34,6 +34,7 @@ const std::u16string extensionDescriptor = u"ohos.aafwk.ExtensionManager"; constexpr int32_t CYCLE_LIMIT = 1000; constexpr int32_t MAX_KILL_PROCESS_PID_COUNT = 100; constexpr int32_t MAX_UPDATE_CONFIG_SIZE = 100; +constexpr int32_t MAX_WANT_LIST_SIZE = 4; } // namespace AbilityManagerStub::AbilityManagerStub() {} @@ -578,6 +579,9 @@ int AbilityManagerStub::OnRemoteRequestInnerFourteenth(uint32_t code, MessagePar if (interfaceCode == AbilityManagerInterfaceCode::CLOSE_UI_EXTENSION_ABILITY_BY_SCB) { return CloseUIExtensionAbilityBySCBInner(data, reply); } + if (interfaceCode == AbilityManagerInterfaceCode::START_ABILITIES) { + return StartAbilitiesInner(data, reply); + } return ERR_CODE_NOT_EXIST; } @@ -3861,6 +3865,38 @@ int AbilityManagerStub::StartAbilityForResultAsCallerInner(MessageParcel &data, return NO_ERROR; } +int32_t AbilityManagerStub::StartAbilitiesInner(MessageParcel &data, MessageParcel &reply) +{ + TAG_LOGD(AAFwkTag::ABILITYMGR, "call StartAbilitiesInner"); + + std::vector wantList; + int32_t size = data.ReadInt32(); + if (!(size > 0 && size <= MAX_WANT_LIST_SIZE)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "vector size error"); + return ERR_NATIVE_IPC_PARCEL_FAILED; + } + for (auto i = 0; i < size; i++) { + std::unique_ptr want(data.ReadParcelable()); + if (want == nullptr) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "null want"); + return ERR_NATIVE_IPC_PARCEL_FAILED; + } + wantList.emplace_back(*want); + } + + std::string requestKey = data.ReadString(); + + sptr callerToken = data.ReadRemoteObject(); + if (callerToken == nullptr) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "null callerToken"); + return INVALID_CALLER_TOKEN; + } + + int32_t result = StartAbilities(wantList, requestKey, callerToken); + reply.WriteInt32(result); + return NO_ERROR; +} + int AbilityManagerStub::StartAbilityForResultAsCallerForOptionsInner(MessageParcel &data, MessageParcel &reply) { TAG_LOGD(AAFwkTag::ABILITYMGR, "called"); 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 1682b45bcf1..1a34c328847 100644 --- a/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp +++ b/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp @@ -68,6 +68,7 @@ constexpr int32_t MAX_FIND_UIEXTENSION_CALLER_TIMES = 10; constexpr int32_t START_UI_ABILITY_PER_SECOND_UPPER_LIMIT = 20; constexpr int32_t API20 = 20; constexpr int32_t API_VERSION_MOD = 100; +constexpr int32_t REQUEST_LIST_ID_INIT = -1; constexpr const char* IS_CALLING_FROM_DMS = "supportCollaborativeCallingFromDmsInAAFwk"; constexpr int REMOVE_STARTING_BUNDLE_TIMEOUT_MICRO_SECONDS = 5000000; // 5s @@ -639,6 +640,140 @@ int UIAbilityLifecycleManager::NotifySCBToStartUIAbility(AbilityRequest &ability return ret; } +int UIAbilityLifecycleManager::NotifySCBToStartUIAbilities(std::vector &abilityRequestList) +{ + HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); + TAG_LOGD(AAFwkTag::ABILITYMGR, "StartAbilities Call NotifySCBToStartUIAbilities"); + for (AbilityRequest &abilityRequest : abilityRequestList) { + if (!AddStartCallerTimestamp(abilityRequest.want.GetIntParam(Want::PARAM_RESV_CALLER_UID, -1))) { + return ERR_INVALID_VALUE; + } + abilityRequest.want.SetParam(IS_SHELL_CALL, AAFwk::PermissionVerification::GetInstance()->IsShellCall()); + std::string callerKey = std::to_string(IPCSkeleton::GetCallingPid()) + ":" + + std::to_string(IPCSkeleton::GetCallingUid()); + bool isCallerKilling = IN_PROCESS_CALL(DelayedSingleton::GetInstance()->IsCallerKilling(callerKey)); + if (isCallerKilling) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities caller is killing"); + return ERR_INVALID_VALUE; + } + abilityRequest.want.SetParam(Want::PARAMS_REAL_CALLER_KEY, callerKey); + } + int32_t requestListId; + { + std::lock_guard guard(sessionLock_); + requestListId = GetRequestId(); + } + std::shared_ptr abilitiesRequest = nullptr; + // std::shared_ptr + abilitiesRequest = std::make_shared(abilityRequestList); + // 持锁修改abilitiesRequestMap_ + { + std::lock_guard guard2(startAbilitiesProcessLock_); + abilitiesRequestMap_.emplace(requestListId, abilitiesRequest); + } + // 开始处理分支场景 + for (AbilityRequest &abilityRequest : abilityRequestList) { + if (IsStartSpecifiedProcessRequest(abilityRequest)) { + abilitiesRequestMap_.erase(requestListId); + return ERR_CAPABILITY_NOT_SUPPORT; + } + const auto &abilityInfo = abilityRequest.abilityInfo; + auto requestId = GetRequestId(); + auto isSpecified = (abilityInfo.launchMode == AppExecFwk::LaunchMode::SPECIFIED); + if (isSpecified) { + abilitiesRequestMap_.erase(requestListId); + return ERR_CAPABILITY_NOT_SUPPORT; + } + auto sessionInfo = CreateSessionInfo(abilityRequest); + sessionInfo->requestCode = abilityRequest.requestCode; + sessionInfo->requestId = requestId; + // isCreating 一定是 false 下方场景确认一下 + sessionInfo->persistentId = GetPersistentIdByAbilityRequest(abilityRequest, sessionInfo->reuse); + sessionInfo->userId = userId_; + sessionInfo->isAtomicService = (abilityInfo.applicationInfo.bundleType == AppExecFwk::BundleType::ATOMIC_SERVICE); + TAG_LOGI(AAFwkTag::ABILITYMGR, "Reused sessionId: %{public}d, userId: %{public}d, requestId: %{public}d", + sessionInfo->persistentId, userId_, requestId); + // 将初始化完成的sessionInfo插入对应的abilitiesRequest中 + abilitiesRequest->UnsortedSessionInfoList.emplace_back(sessionInfo); + } + // 判断是否需要等待Specified + if (!abilitiesRequest->waitingRequestIdList.empty()) { + // 新增错误码 返回此错误码表示进入等待 + return START_ABILITIES_WAITTING_SPECIFIED_CODE; + } + // 进入这个分支,SessionInfoList是有序的,不用重排 + std::string errMsg; + TAG_LOGI(AAFwkTag::ABILITYMGR, "StartAbilities normal start. sessionInfoList size: %{public}zu", + abilitiesRequest->UnsortedSessionInfoList.size()); + // sptr sessionInfo0 = &sessionInfoList[0]; + int ret = BatchNotifySCBPendingActivation( + abilitiesRequest->UnsortedSessionInfoList, abilityRequestList, errMsg); + + for (auto sessionInfo : abilitiesRequest->UnsortedSessionInfoList) { + sessionInfo->want.RemoveAllFd(); + } + abilitiesRequestMap_.erase(requestListId); + return ret; +} + +int32_t UIAbilityLifecycleManager::BatchNotifySCBPendingActivation(std::vector> &sessionInfoList, + const std::vector &abilityRequestList, std::string &errMsg) +{ + // process sessionInfoList + for (auto sessionInfo : sessionInfoList) { + if (sessionInfo == nullptr) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "sessionInfo is nullptr"); + errMsg = "sessionInfo is nullptr"; + return ERR_INVALID_VALUE; + } + bool hasStartWindowOption = (sessionInfo->startWindowOption != nullptr); + bool hasStartWindow = hasStartWindowOption ? sessionInfo->startWindowOption->hasStartWindow : false; + std::string backgroundColor = + hasStartWindowOption ? sessionInfo->startWindowOption->startWindowBackgroundColor : ""; + TAG_LOGI(AAFwkTag::ABILITYMGR, "appCloneIndex:%{public}d, instanceKey:%{public}s, " + "hasStartWindow:%{public}d, backgroundColor:%{public}s", + (sessionInfo->want).GetIntParam(Want::PARAM_APP_CLONE_INDEX_KEY, 0), sessionInfo->instanceKey.c_str(), + hasStartWindow, backgroundColor.c_str()); + } + // 获取caller信息 + std::shared_ptr callerAbilityRecord; + callerAbilityRecord = GetAbilityRecordByToken(abilityRequestList[0].callerToken); + if (callerAbilityRecord == nullptr || callerAbilityRecord->GetRestartAppFlag()) + { + // 使用rootSession启动 callerRecord存在 callerSession不存在 + auto tmpSceneSession = iface_cast(rootSceneSession_); + if (tmpSceneSession == nullptr) { + errMsg = "null tmpSceneSession, scb does not exist"; + TAG_LOGE(AAFwkTag::ABILITYMGR, "%{public}s", errMsg.c_str()); + return ERR_INVALID_VALUE; + } + for (auto sessionInfo : sessionInfoList) { + sessionInfo->canStartAbilityFromBackground = true; + } + TAG_LOGI(AAFwkTag::ABILITYMGR, + "scb call, StartAbilities NotifySCBPendingActivation for rootSceneSession"); + return static_cast(tmpSceneSession->PendingSessionActivation(sessionInfoList[0])); + } + // 处理caller + auto callerSessionInfo = callerAbilityRecord->GetSessionInfo(); + CHECK_POINTER_AND_RETURN(callerSessionInfo, ERR_INVALID_VALUE); + CHECK_POINTER_AND_RETURN(callerSessionInfo->sessionToken, ERR_INVALID_VALUE); + auto callerSession = iface_cast(callerSessionInfo->sessionToken); + CHECK_POINTER_AND_RETURN(callerSession, ERR_INVALID_VALUE); + for (auto sessionInfo : sessionInfoList) { + CheckCallerFromBackground(callerAbilityRecord, sessionInfo); + } + for (auto abilityRequest : abilityRequestList) { + auto requestId = abilityRequest.want.GetStringParam(KEY_REQUEST_ID); + if (!requestId.empty()) { + callerAbilityRecord->NotifyAbilityRequestSuccess(requestId, abilityRequest.want.GetElement()); + } + const_cast(abilityRequest).want.RemoveParam(KEY_REQUEST_ID); + } + TAG_LOGI(AAFwkTag::ABILITYMGR, "scb call, StartAbilities BatchNotifySCBPendingActivation for callerSession"); + return static_cast(callerSession->PendingSessionActivation(sessionInfoList[0])); +} + int32_t UIAbilityLifecycleManager::NotifySCBToRecoveryAfterInterception(const AbilityRequest &abilityRequest) { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); diff --git a/services/abilitymgr/src/utils/start_ability_utils.cpp b/services/abilitymgr/src/utils/start_ability_utils.cpp index c0638827351..27f0aca8416 100644 --- a/services/abilitymgr/src/utils/start_ability_utils.cpp +++ b/services/abilitymgr/src/utils/start_ability_utils.cpp @@ -395,5 +395,15 @@ bool StartAbilityUtils::IsCallFromAncoShellOrBroker(const sptr &c } return false; } + +bool StartAbilityUtils::IsSupportStartAbilities() +{ + if (!AppUtils::GetInstance().IsSupportStartAbilities() || + !Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "StartAbilities is not supported"); + return false; + } + return true; +} } } \ No newline at end of file diff --git a/services/common/include/app_utils.h b/services/common/include/app_utils.h index d89cfbafc69..2d8ee786f06 100644 --- a/services/common/include/app_utils.h +++ b/services/common/include/app_utils.h @@ -139,6 +139,13 @@ public: */ bool IsStartOptionsWithAnimation(); + /** + * IsSupportStartAbilities, check whether the StartAbilities API is supported. + * + * @return Whether the StartAbilities API is supported. + */ + bool IsSupportStartAbilities(); + /** * IsStartOptionsWithAnimation, check whether it is a multi-process model. * @@ -416,6 +423,7 @@ private: volatile DeviceConfiguration isConnectSupportCrossUser_ = {false, false}; volatile DeviceConfiguration isSupportAppServiceExtension_ = {false, false}; volatile DeviceConfiguration isGrantTempUriPermission_ = {false, true}; + volatile DeviceConfiguration isSupportStartAbilities_ = {false, false}; DeviceConfiguration>> residentProcessInExtremeMemory_ = {false, {}}; std::mutex residentProcessInExtremeMemoryMutex_; diff --git a/services/common/src/app_utils.cpp b/services/common/src/app_utils.cpp index 9e5bcf1cece..42f6ee488bb 100644 --- a/services/common/src/app_utils.cpp +++ b/services/common/src/app_utils.cpp @@ -42,6 +42,7 @@ constexpr const char* LIMIT_MAXIMUM_OF_RENDER_PROCESS = "persist.sys.abilityms.l constexpr const char* GRANT_PERSIST_URI_PERMISSION = "persist.sys.abilityms.grant_persist_uri_permission"; constexpr const char* GRANT_TEMPORARY_URI_PERMISSION = "persist.sys.abilityms.grant_temporary_uri_permission"; constexpr const char* START_OPTIONS_WITH_ANIMATION = "persist.sys.abilityms.start_options_with_animation"; +constexpr const char* SUPPORT_START_ABILITIES = "persist.sys.abilityms.enable_start_abilities"; constexpr const char* MULTI_PROCESS_MODEL = "persist.sys.abilityms.multi_process_model"; constexpr const char* PARAM_ANCO_APP_IDENTIFIER = "persist.hmos_fusion_mgr.anco_identifier"; constexpr const char* ALLOW_CHILD_PROCESS_IN_MULTI_PROCESS_FEATURE_APP = @@ -225,6 +226,16 @@ bool AppUtils::IsStartOptionsWithAnimation() return isStartOptionsWithAnimation_.value; } +bool AppUtils::IsSupportStartAbilities() +{ + if (!isSupportStartAbilities_.isLoaded) { + isSupportStartAbilities_.value = system::GetBoolParameter(SUPPORT_START_ABILITIES, false); + isSupportStartAbilities_.isLoaded = true; + } + TAG_LOGD(AAFwkTag::DEFAULT, "called %{public}d", isSupportStartAbilities_.value); + return isSupportStartAbilities_.value; +} + bool AppUtils::IsMultiProcessModel() { if (!isMultiProcessModel_.isLoaded) { -- Gitee