diff --git a/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp b/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp index a0994856ec..2a9e6fae73 100644 --- a/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp +++ b/frameworks/native/ability/native/ability_business_error/ability_business_error.cpp @@ -99,6 +99,7 @@ constexpr const char* ERROR_MSG_INVALID_APP_INSTANCE_KEY = "The app instance key constexpr const char* ERROR_MSG_UPPER_LIMIT = "The number of app instances reaches the limit."; constexpr const char* ERROR_MSG_APP_INSTANCE_KEY_NOT_SUPPORT = "The APP_INSTANCE_KEY cannot be specified."; constexpr const char* ERROR_MSG_CREATE_NEW_INSTANCE_NOT_SUPPORT = "Creating a new instance is not supported."; +constexpr const char* ERROR_MSG_UI_ABILITY_IS_STARTING = "The UIAbility is in starting state."; // follow ERR_BUNDLE_MANAGER_BUNDLE_NOT_EXIST of appexecfwk_errors.h in bundle_framework constexpr int32_t ERR_BUNDLE_MANAGER_BUNDLE_NOT_EXIST = 8521220; @@ -170,6 +171,7 @@ static std::unordered_map ERR_CODE_MAP = { { AbilityErrorCode::ERROR_CODE_UPPER_LIMIT, ERROR_MSG_UPPER_LIMIT }, { AbilityErrorCode::ERROR_CODE_APP_INSTANCE_KEY_NOT_SUPPORT, ERROR_MSG_APP_INSTANCE_KEY_NOT_SUPPORT }, { AbilityErrorCode::ERROR_CODE_CREATE_NEW_INSTANCE_NOT_SUPPORT, ERROR_MSG_CREATE_NEW_INSTANCE_NOT_SUPPORT }, + { AbilityErrorCode::ERROR_CODE_UI_ABILITY_IS_STARTING, ERROR_MSG_UI_ABILITY_IS_STARTING}, }; static std::unordered_map INNER_TO_JS_ERROR_CODE_MAP { @@ -244,6 +246,7 @@ static std::unordered_map INNER_TO_JS_ERROR_CODE_MAP {ERR_UPPER_LIMIT, AbilityErrorCode::ERROR_CODE_UPPER_LIMIT}, {ERR_APP_INSTANCE_KEY_NOT_SUPPORT, AbilityErrorCode::ERROR_CODE_APP_INSTANCE_KEY_NOT_SUPPORT}, {ERR_CREATE_NEW_INSTANCE_NOT_SUPPORT, AbilityErrorCode::ERROR_CODE_CREATE_NEW_INSTANCE_NOT_SUPPORT}, + {ERR_UI_ABILITY_IS_STARTING, AbilityErrorCode::ERROR_CODE_UI_ABILITY_IS_STARTING}, }; } 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 06f3000e44..e04e49417c 100644 --- a/interfaces/inner_api/ability_manager/include/ability_manager_errors.h +++ b/interfaces/inner_api/ability_manager/include/ability_manager_errors.h @@ -650,12 +650,17 @@ enum { * Result (2097278) for replying failed while executing insight intent. */ ERR_INSIGHT_INTENT_EXECUTE_REPLY_FAILED = 2097278, - + /* - * Result (2097278) for get target bundle info failed. + * Result (2097279) for get target bundle info failed. */ ERR_GET_TARGET_BUNDLE_INFO_FAILED = 2097279, + /* + * Result (2097280) for UIAbility in starting state. + */ + ERR_UI_ABILITY_IS_STARTING = 2097280, + /** * Native error(3000000) for target bundle not exist. */ diff --git a/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h b/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h index 56723ea1f2..3fc9441cce 100644 --- a/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h +++ b/interfaces/kits/native/ability/native/ability_business_error/ability_business_error.h @@ -180,6 +180,9 @@ enum class AbilityErrorCode { // Target application not found. ERROR_CODE_GET_BUNFLE_INFO_FAILED = 16000081, + // UIAbility is in starting state. + ERROR_CODE_UI_ABILITY_IS_STARTING = 16000082, + // invalid caller. ERROR_CODE_INVALID_CALLER = 16200001, 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 79f4a73dec..4042963e30 100644 --- a/services/abilitymgr/include/scene_board/ui_ability_lifecycle_manager.h +++ b/services/abilitymgr/include/scene_board/ui_ability_lifecycle_manager.h @@ -455,6 +455,10 @@ private: bool &isColdStart); std::shared_ptr FindRecordFromTmpMap(const AbilityRequest &abilityRequest); bool AddStartCallerTimestamp(int32_t callerUid); + std::shared_ptr FindRecordFromSessionMap(const AbilityRequest &abilityRequest); + bool HasAbilityRequest(const AbilityRequest &abilityRequest); + void AddAbilityRequest(const AbilityRequest &abilityRequest); + void RemoveAbilityRequest(const AbilityRequest &abilityRequest); int32_t userId_ = -1; mutable ffrt::mutex sessionLock_; @@ -475,6 +479,7 @@ private: ffrt::mutex startUIAbilityCallerTimestampsLock_; std::map> startUIAbilityCallerTimestamps_; + std::list> startAbilityCheckList_; }; } // namespace AAFwk } // namespace OHOS diff --git a/services/abilitymgr/src/ability_manager_service.cpp b/services/abilitymgr/src/ability_manager_service.cpp index 3fac6a8241..ac5a049a12 100644 --- a/services/abilitymgr/src/ability_manager_service.cpp +++ b/services/abilitymgr/src/ability_manager_service.cpp @@ -104,6 +104,7 @@ using OHOS::Security::AccessToken::AccessTokenKit; namespace OHOS { using AbilityRuntime::FreezeUtil; +using namespace AbilityRuntime::ServerConstant; namespace AAFwk { using AutoStartupInfo = AbilityRuntime::AutoStartupInfo; using GetExtensionAbilityInfoFlag = AppExecFwk::GetExtensionAbilityInfoFlag; @@ -252,7 +253,6 @@ constexpr const char* NEED_STARTINGWINDOW = "ohos.ability.NeedStartingWindow"; constexpr const char* PERMISSIONMGR_BUNDLE_NAME = "com.ohos.permissionmanager"; constexpr const char* PERMISSIONMGR_ABILITY_NAME = "com.ohos.permissionmanager.GrantAbility"; constexpr const char* SCENEBOARD_BUNDLE_NAME = "com.ohos.sceneboard"; -constexpr const char* IS_CALL_BY_SCB = "isCallBySCB"; constexpr const char* SPECIFY_TOKEN_ID = "specifyTokenId"; constexpr const char* PROCESS_SUFFIX = "embeddable"; constexpr int32_t DEFAULT_DMS_MISSION_ID = -1; @@ -1262,7 +1262,7 @@ int AbilityManagerService::StartAbilityInner(const Want &want, const sptrNotifySCBToStartUIAbility(abilityRequest); @@ -1941,7 +1941,7 @@ int AbilityManagerService::StartAbilityForOptionInner(const Want &want, const St abilityRequest.want.RemoveParam(PARAM_SPECIFIED_PROCESS_FLAG); if (Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) { abilityRequest.userId = oriValidUserId; - abilityRequest.want.SetParam(IS_CALL_BY_SCB, false); + abilityRequest.want.SetParam(ServerConstant::IS_CALL_BY_SCB, false); abilityRequest.processOptions = startOptions.processOptions; if (IPCSkeleton::GetCallingTokenID() == abilityRequest.appInfo.accessTokenId) { abilityRequest.startWindowOption = startOptions.startWindowOption; @@ -2223,7 +2223,7 @@ int AbilityManagerService::StartUIAbilityBySCBDefault(sptr sessionI return ERR_APP_CLONE_INDEX_INVALID; } StartAbilityInfoWrap threadLocalInfo(sessionInfo->want, currentUserId, appIndex, sessionInfo->callerToken); - if (sessionInfo->want.GetBoolParam(IS_CALL_BY_SCB, true)) { + if (sessionInfo->want.GetBoolParam(ServerConstant::IS_CALL_BY_SCB, true)) { TAG_LOGD(AAFwkTag::ABILITYMGR, "interceptorExecuter_ called"); auto shouldBlockFunc = [aams = shared_from_this()]() { return aams->ShouldBlockAllAppStart(); }; AbilityInterceptorParam interceptorParam = AbilityInterceptorParam(sessionInfo->want, requestCode, @@ -2246,7 +2246,7 @@ int AbilityManagerService::StartUIAbilityBySCBDefault(sptr sessionI return result; } - if (sessionInfo->want.GetBoolParam(IS_CALL_BY_SCB, true)) { + if (sessionInfo->want.GetBoolParam(ServerConstant::IS_CALL_BY_SCB, true)) { if (sessionInfo->startSetting != nullptr) { TAG_LOGD(AAFwkTag::ABILITYMGR, "Start by scb, last not."); sessionInfo->startSetting->AddProperty(AbilityStartSetting::IS_START_BY_SCB_KEY, "true"); @@ -2270,7 +2270,7 @@ int AbilityManagerService::StartUIAbilityBySCBDefault(sptr sessionI return ERR_INVALID_VALUE; } - if (sessionInfo->want.GetBoolParam(IS_CALL_BY_SCB, true)) { + if (sessionInfo->want.GetBoolParam(ServerConstant::IS_CALL_BY_SCB, true)) { TAG_LOGD(AAFwkTag::ABILITYMGR, "afterCheckExecuter_ called"); if (sessionInfo->want.GetBoolParam("ohos.ability.params.isSkipErmsFromSCB", false)) { abilityRequest.want.RemoveParam("ohos.ability.params.isSkipErmsFromSCB"); @@ -2312,8 +2312,6 @@ int32_t AbilityManagerService::StartUIAbilityBySCBDefaultCommon(AbilityRequest & ReportAbilityAssociatedStartInfoToRSS(abilityInfo, RES_TYPE_SCB_START_ABILITY, sessionInfo->callerToken); auto uiAbilityManager = GetUIAbilityManagerByUid(IPCSkeleton::GetCallingUid()); CHECK_POINTER_AND_RETURN(uiAbilityManager, ERR_INVALID_VALUE); - // here we don't need want param "IS_CALL_BY_SCB" any more, remove it. - (sessionInfo->want).RemoveParam(IS_CALL_BY_SCB); return uiAbilityManager->StartUIAbility(abilityRequest, sessionInfo, sceneFlag, isColdStart); } @@ -7507,7 +7505,7 @@ int AbilityManagerService::StartAbilityByCall(const Want &want, const sptrResolveLocked(abilityRequest); @@ -12033,7 +12031,7 @@ int32_t AbilityManagerService::PreStartInner(const FreeInstallInfo& taskInfo) // sceneboard abilityRequest.userId = oriValidUserId; - abilityRequest.want.SetParam(IS_CALL_BY_SCB, false); + abilityRequest.want.SetParam(ServerConstant::IS_CALL_BY_SCB, false); std::string sessionId = std::to_string(std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count()); abilityRequest.want.SetParam(KEY_SESSION_ID, sessionId); diff --git a/services/abilitymgr/src/mission/mission_list_manager.cpp b/services/abilitymgr/src/mission/mission_list_manager.cpp index 88f1952f59..0146204e3c 100644 --- a/services/abilitymgr/src/mission/mission_list_manager.cpp +++ b/services/abilitymgr/src/mission/mission_list_manager.cpp @@ -397,13 +397,13 @@ int MissionListManager::GetTargetMission(const AbilityRequest &abilityRequest, s if (targetAbilityRecord->GetPendingState() != AbilityState::INITIAL) { TAG_LOGI(AAFwkTag::ABILITYMGR, "pending state is FOREGROUND or BACKGROUND, dropped."); targetAbilityRecord->SetPendingState(AbilityState::FOREGROUND); - return ERR_OK; + return ERR_UI_ABILITY_IS_STARTING; } else { TAG_LOGD(AAFwkTag::ABILITYMGR, "pending state is not FOREGROUND or BACKGROUND"); targetAbilityRecord->SetPendingState(AbilityState::FOREGROUND); if (targetAbilityRecord->IsLoading()) { TAG_LOGI(AAFwkTag::ABILITYMGR, "ability: %{public}s is loading", abilityRequest.abilityInfo.name.c_str()); - return ERR_OK; + return ERR_UI_ABILITY_IS_STARTING; } } 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 12bc9f6395..b70b4e00d3 100644 --- a/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp +++ b/services/abilitymgr/src/scene_board/ui_ability_lifecycle_manager.cpp @@ -25,6 +25,7 @@ #include "hitrace_meter.h" #include "permission_constants.h" #include "process_options.h" +#include "server_constant.h" #include "start_window_option.h" #include "scene_board/status_bar_delegate_manager.h" #include "session_manager_lite.h" @@ -37,6 +38,7 @@ namespace OHOS { using AbilityRuntime::FreezeUtil; +using namespace AbilityRuntime::ServerConstant; namespace AAFwk { namespace { constexpr const char* SEPARATOR = ":"; @@ -73,6 +75,22 @@ auto g_deleteLifecycleEventTask = [](const sptr &token) { CHECK_POINTER_LOG(token, "token is nullptr."); FreezeUtil::GetInstance().DeleteLifecycleEvent(token->AsObject()); }; + +bool CompareTwoRequest(const AbilityRequest &left, const AbilityRequest &right) +{ + int32_t leftIndex = 0; + (void)AbilityRuntime::StartupUtil::GetAppIndex(left.want, leftIndex); + int32_t rightIndex = 0; + (void)AbilityRuntime::StartupUtil::GetAppIndex(right.want, rightIndex); + + auto LeftInstanceKey = left.want.GetStringParam(Want::APP_INSTANCE_KEY); + auto RightInstanceKey = right.want.GetStringParam(Want::APP_INSTANCE_KEY); + + return leftIndex == rightIndex && LeftInstanceKey == RightInstanceKey && + left.abilityInfo.name == right.abilityInfo.name && + left.abilityInfo.bundleName == right.abilityInfo.bundleName && + left.abilityInfo.moduleName == right.abilityInfo.moduleName; +} } UIAbilityLifecycleManager::UIAbilityLifecycleManager(int32_t userId): userId_(userId) {} @@ -86,6 +104,11 @@ int UIAbilityLifecycleManager::StartUIAbility(AbilityRequest &abilityRequest, sp TAG_LOGE(AAFwkTag::ABILITYMGR, "sessionInfo invalid"); return ERR_INVALID_VALUE; } + auto isCallBySCB = sessionInfo->want.GetBoolParam(ServerConstant::IS_CALL_BY_SCB, true); + if (!isCallBySCB) { + RemoveAbilityRequest(abilityRequest); + } + sessionInfo->want.RemoveParam(ServerConstant::IS_CALL_BY_SCB); abilityRequest.sessionInfo = sessionInfo; TAG_LOGI(AAFwkTag::ABILITYMGR, "session:%{public}d. bundle:%{public}s, ability:%{public}s, instanceKey:%{public}s", @@ -96,7 +119,7 @@ int UIAbilityLifecycleManager::StartUIAbility(AbilityRequest &abilityRequest, sp TAG_LOGD(AAFwkTag::ABILITYMGR, "StartUIAbility"); uiAbilityRecord->SetSpecifyTokenId(abilityRequest.specifyTokenId); - if (uiAbilityRecord->GetPendingState() != AbilityState::INITIAL) { + if (isCallBySCB && uiAbilityRecord->GetPendingState() != AbilityState::INITIAL) { TAG_LOGI(AAFwkTag::ABILITYMGR, "pending state: FOREGROUND/ BACKGROUND, dropped"); uiAbilityRecord->SetPendingState(AbilityState::FOREGROUND); return ERR_OK; @@ -453,6 +476,20 @@ int UIAbilityLifecycleManager::NotifySCBToStartUIAbility(AbilityRequest &ability ++specifiedRequestId_; return ERR_OK; } + + if (abilityRequest.abilityInfo.launchMode == AppExecFwk::LaunchMode::SINGLETON) { + if (HasAbilityRequest(abilityRequest)) { + TAG_LOGW(AAFwkTag::ABILITYMGR, "multi start request"); + return ERR_UI_ABILITY_IS_STARTING; + } + auto abilityRecord = FindRecordFromSessionMap(abilityRequest); + if (abilityRecord && abilityRecord->GetPendingState() == AbilityState::FOREGROUNDING) { + TAG_LOGW(AAFwkTag::ABILITYMGR, "ability is starting"); + return ERR_UI_ABILITY_IS_STARTING; + } + AddAbilityRequest(abilityRequest); + } + auto sessionInfo = CreateSessionInfo(abilityRequest); sessionInfo->requestCode = abilityRequest.requestCode; auto isCreating = abilityRequest.want.GetBoolParam(Want::CREATE_APP_INSTANCE_KEY, false); @@ -2891,5 +2928,62 @@ void UIAbilityLifecycleManager::EnableListForSCBRecovery() isSCBRecovery_ = true; coldStartInSCBRecovery_.clear(); } + +std::shared_ptr UIAbilityLifecycleManager::FindRecordFromSessionMap( + const AbilityRequest &abilityRequest) +{ + int32_t appIndex = 0; + (void)AbilityRuntime::StartupUtil::GetAppIndex(abilityRequest.want, appIndex); + auto instanceKey = abilityRequest.want.GetStringParam(Want::APP_INSTANCE_KEY); + for (const auto &[sessionId, abilityRecord] : sessionAbilityMap_) { + if (abilityRecord) { + const auto &info = abilityRecord->GetAbilityInfo(); + if (info.name == abilityRequest.abilityInfo.name && + info.bundleName == abilityRequest.abilityInfo.bundleName && + info.moduleName == abilityRequest.abilityInfo.moduleName && + appIndex == abilityRecord->GetAppIndex() && instanceKey == abilityRecord->GetInstanceKey()) { + return abilityRecord; + } + } + } + return nullptr; +} + +bool UIAbilityLifecycleManager::HasAbilityRequest(const AbilityRequest &abilityRequest) +{ + for (const auto &item : startAbilityCheckList_) { + if (item && CompareTwoRequest(*item, abilityRequest)) { + return true; + } + } + return false; +} + +void UIAbilityLifecycleManager::AddAbilityRequest(const AbilityRequest &abilityRequest) +{ + auto newRequest = std::make_shared(abilityRequest); + startAbilityCheckList_.push_back(newRequest); + auto taskHandler = DelayedSingleton::GetInstance()->GetTaskHandler(); + CHECK_POINTER(taskHandler); + taskHandler->SubmitTask([wThis = weak_from_this(), wRequest = std::weak_ptr(newRequest)]() { + auto pThis = wThis.lock(); + auto request = wRequest.lock(); + if (pThis && request) { + std::lock_guard guard(pThis->sessionLock_); + pThis->startAbilityCheckList_.remove(request); + } + }, GlobalConstant::COLDSTART_TIMEOUT_MULTIPLE * GlobalConstant::TIMEOUT_UNIT_TIME); +} + +void UIAbilityLifecycleManager::RemoveAbilityRequest(const AbilityRequest &abilityRequest) +{ + for (auto iter = startAbilityCheckList_.begin(); iter != startAbilityCheckList_.end(); ++iter) { + auto item = *iter; + if (item && CompareTwoRequest(*item, abilityRequest)) { + startAbilityCheckList_.erase(iter); + return; + } + } +} } // namespace AAFwk } // namespace OHOS \ No newline at end of file diff --git a/utils/server/constant/server_constant.h b/utils/server/constant/server_constant.h index 8fd65788a6..9ed0e6fa3c 100644 --- a/utils/server/constant/server_constant.h +++ b/utils/server/constant/server_constant.h @@ -19,6 +19,7 @@ namespace OHOS::AbilityRuntime { namespace ServerConstant { constexpr const char* DLP_INDEX = "ohos.dlp.params.index"; +constexpr const char* IS_CALL_BY_SCB = "isCallBySCB"; } // namespace ServerConstant } // namespace OHOS::AbilityRuntime #endif // OHOS_ABILITY_RUNTIME_SERVER_CONSTANT_H \ No newline at end of file