/*
 * Copyright (c) 2022-2024 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 "implicit_start_processor.h"

#include "ability_manager_service.h"
#include "ability_util.h"
#include "app_utils.h"
#include "dialog_session_manager.h"
#include "ecological_rule/ability_ecological_rule_mgr_service.h"
#include "global_constant.h"
#include "hitrace_meter.h"
#include "start_ability_utils.h"
#include "startup_util.h"
#ifdef WITH_DLP
#include "dlp_file_kits.h"
#endif // WITH_DLP

namespace OHOS {
namespace AAFwk {
const size_t IDENTITY_LIST_MAX_SIZE = 10;

const std::string BLACK_ACTION_SELECT_DATA = "ohos.want.action.select";
const std::string ACTION_VIEW = "ohos.want.action.viewData";
const std::string STR_PHONE = "phone";
const std::string STR_DEFAULT = "default";
const std::string TYPE_ONLY_MATCH_WILDCARD = "reserved/wildcard";
const std::string SHOW_DEFAULT_PICKER_FLAG = "ohos.ability.params.showDefaultPicker";
const std::string PARAM_ABILITY_APPINFOS = "ohos.ability.params.appInfos";
const std::string ANCO_PENDING_REQUEST = "ancoPendingRequest";
const int NFC_CALLER_UID = 1027;
const int NFC_QUERY_LENGTH = 2;
const std::string OPEN_LINK_APP_LINKING_ONLY = "appLinkingOnly";
const std::string HTTP_SCHEME_NAME = "http";
const std::string HTTPS_SCHEME_NAME = "https";
const std::string APP_CLONE_INDEX = "ohos.extra.param.key.appCloneIndex";

void SendAbilityEvent(const EventName &eventName, HiSysEventType type, const EventInfo &eventInfo)
{
    auto instance_ = DelayedSingleton<AbilityManagerService>::GetInstance();
    if (instance_ == nullptr) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "instance null.");
        return;
    }
    auto taskHandler = instance_->GetTaskHandler();
    if (taskHandler == nullptr) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "task handler null.");
        return;
    }
    taskHandler->SubmitTask([eventName, type, eventInfo]() {
        EventReport::SendAbilityEvent(eventName, type, eventInfo);
    });
}

bool ImplicitStartProcessor::IsExtensionInWhiteList(AppExecFwk::ExtensionAbilityType type)
{
    switch (type) {
        case AppExecFwk::ExtensionAbilityType::FORM: return true;
        case AppExecFwk::ExtensionAbilityType::INPUTMETHOD: return true;
        case AppExecFwk::ExtensionAbilityType::WALLPAPER: return true;
        case AppExecFwk::ExtensionAbilityType::WINDOW: return true;
        case AppExecFwk::ExtensionAbilityType::THUMBNAIL: return true;
        case AppExecFwk::ExtensionAbilityType::PREVIEW: return true;
        default: return false;
    }
}

bool ImplicitStartProcessor::IsImplicitStartAction(const Want &want)
{
    auto element = want.GetElement();
    if (!element.GetAbilityName().empty()) {
        return false;
    }

    if (want.GetIntParam(AAFwk::SCREEN_MODE_KEY, ScreenMode::IDLE_SCREEN_MODE) != ScreenMode::IDLE_SCREEN_MODE) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "The implicit startup process is not used for the startup of EmbeddaUIAbility");
        return false;
    }

    if (want.GetAction() != BLACK_ACTION_SELECT_DATA) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "implicit start, the action is %{public}s", want.GetAction().data());
        return true;
    }

    return false;
}

int ImplicitStartProcessor::CheckImplicitCallPermission(const AbilityRequest& abilityRequest)
{
    auto abilityMgr = DelayedSingleton<AbilityManagerService>::GetInstance();
    CHECK_POINTER_AND_RETURN(abilityMgr, ERR_INVALID_VALUE);
    bool isBackgroundCall = true;
    if (abilityMgr->IsCallFromBackground(abilityRequest, isBackgroundCall) != ERR_OK) {
        return ERR_INVALID_VALUE;
    }
    if (!isBackgroundCall) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "hap not background");
        return ERR_OK;
    }
    auto ret = AAFwk::PermissionVerification::GetInstance()->VerifyBackgroundCallPermission(isBackgroundCall);
    if (!ret) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "CheckImplicitCallPermission failed");
        return CHECK_PERMISSION_FAILED;
    }
    return ERR_OK;
}

int ImplicitStartProcessor::ImplicitStartAbility(AbilityRequest &request, int32_t userId, int32_t windowMode,
    const std::string &replaceWantString, bool isAppCloneSelector)
{
    HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
    TAG_LOGI(AAFwkTag::ABILITYMGR, "implicit start ability by type: %{public}d", request.callType);
    auto sysDialogScheduler = DelayedSingleton<SystemDialogScheduler>::GetInstance();
    CHECK_POINTER_AND_RETURN(sysDialogScheduler, ERR_INVALID_VALUE);

    auto result = CheckImplicitCallPermission(request);
    if (ERR_OK != result) {
        return result;
    }
    std::vector<DialogAppInfo> dialogAppInfos;
    request.want.RemoveParam(APP_CLONE_INDEX);
    int32_t ret = ERR_OK;
    if (isAppCloneSelector) {
        ret = GenerateAbilityRequestByAppIndexes(userId, request, dialogAppInfos);
    } else {
        ret = GenerateAbilityRequestByAction(userId, request, dialogAppInfos, false);
    }
    if (ret != ERR_OK) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "generate ability request failed.");
        return ret;
    }
    AbilityUtil::WantSetParameterWindowMode(request.want, windowMode);

    auto identity = IPCSkeleton::ResetCallingIdentity();
    auto startAbilityTask = [imp = shared_from_this(), request, userId, identity]
        (const std::string& bundle, const std::string& abilityName) mutable {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "implicit start ability call back.");

        // reset calling indentity
        IPCSkeleton::SetCallingIdentity(identity);

        AAFwk::Want targetWant = request.want;
        targetWant.SetElementName(bundle, abilityName);
        auto callBack = [imp, targetWant, request, userId]() -> int32_t {
            return imp->ImplicitStartAbilityInner(targetWant, request, userId);
        };
        return imp->CallStartAbilityInner(userId, targetWant, callBack, request.callType);
    };

    AAFwk::Want want;
    auto abilityMgr = DelayedSingleton<AbilityManagerService>::GetInstance();
    int32_t tokenId = request.want.GetIntParam(Want::PARAM_RESV_CALLER_TOKEN,
        static_cast<int32_t>(IPCSkeleton::GetCallingTokenID()));
    AddIdentity(tokenId, identity);
    if (dialogAppInfos.size() == 0 && AppUtils::GetInstance().IsSelectorDialogDefaultPossion()) {
        if ((request.want.GetFlags() & Want::FLAG_START_WITHOUT_TIPS) == Want::FLAG_START_WITHOUT_TIPS) {
            TAG_LOGI(AAFwkTag::ABILITYMGR, "hint dialog doesn't generate.");
            return ERR_IMPLICIT_START_ABILITY_FAIL;
        }
        ret = sysDialogScheduler->GetSelectorDialogWant(dialogAppInfos, request.want, want, request.callerToken);
        if (ret != ERR_OK) {
            TAG_LOGE(AAFwkTag::ABILITYMGR, "GetSelectorDialogWant failed.");
            return ret;
        }
        if (want.GetBoolParam("isCreateAppGallerySelector", false)) {
            want.RemoveParam("isCreateAppGallerySelector");
            DialogSessionManager::GetInstance().CreateImplicitSelectorModalDialog(request, want, userId,
                dialogAppInfos);
            return ERR_IMPLICIT_START_ABILITY_FAIL;
        }
        TAG_LOGE(AAFwkTag::ABILITYMGR, "implicit query ability infos failed, show tips dialog.");
        Want dialogWant = sysDialogScheduler->GetTipsDialogWant(request.callerToken);
        abilityMgr->StartAbility(dialogWant);
        return ERR_IMPLICIT_START_ABILITY_FAIL;
    } else if (dialogAppInfos.size() == 0 && !AppUtils::GetInstance().IsSelectorDialogDefaultPossion()) {
        std::string type = MatchTypeAndUri(request.want);
        ret = sysDialogScheduler->GetPcSelectorDialogWant(dialogAppInfos, request.want, want, type,
            userId, request.callerToken);
        if (ret != ERR_OK) {
            TAG_LOGE(AAFwkTag::ABILITYMGR, "GetPcSelectorDialogWant failed.");
            return ret;
        }
        if (want.GetBoolParam("isCreateAppGallerySelector", false)) {
            want.RemoveParam("isCreateAppGallerySelector");
            DialogSessionManager::GetInstance().CreateImplicitSelectorModalDialog(request, want, userId,
                dialogAppInfos);
            return ERR_IMPLICIT_START_ABILITY_FAIL;
        }
        std::vector<DialogAppInfo> dialogAllAppInfos;
        bool isMoreHapList = true;
        ret = GenerateAbilityRequestByAction(userId, request, dialogAllAppInfos, isMoreHapList);
        if (ret != ERR_OK) {
            TAG_LOGE(AAFwkTag::ABILITYMGR, "generate ability request by action failed.");
            return ret;
        }
        if (dialogAllAppInfos.size() == 0) {
            if ((request.want.GetFlags() & Want::FLAG_START_WITHOUT_TIPS) == Want::FLAG_START_WITHOUT_TIPS) {
                TAG_LOGI(AAFwkTag::ABILITYMGR, "hint dialog doesn't generate.");
                return ERR_IMPLICIT_START_ABILITY_FAIL;
            }
            Want dialogWant = sysDialogScheduler->GetTipsDialogWant(request.callerToken);
            abilityMgr->StartAbility(dialogWant);
            return ERR_IMPLICIT_START_ABILITY_FAIL;
        }
        ret = sysDialogScheduler->GetPcSelectorDialogWant(dialogAllAppInfos, request.want, want,
            TYPE_ONLY_MATCH_WILDCARD, userId, request.callerToken);
        if (ret != ERR_OK) {
            TAG_LOGE(AAFwkTag::ABILITYMGR, "GetPcSelectorDialogWant failed.");
            return ret;
        }
        ret = abilityMgr->StartAbility(request.want, request.callerToken);
        // reset calling indentity
        IPCSkeleton::SetCallingIdentity(identity);
        int32_t tokenId = request.want.GetIntParam(Want::PARAM_RESV_CALLER_TOKEN,
            static_cast<int32_t>(IPCSkeleton::GetCallingTokenID()));
        AddIdentity(tokenId, identity);
        return ret;
    }

    //There is a default opening method add Only one application supports
    bool defaultPicker = false;
    defaultPicker = request.want.GetBoolParam(SHOW_DEFAULT_PICKER_FLAG, defaultPicker);
    if (dialogAppInfos.size() == 1 && !defaultPicker) {
        auto info = dialogAppInfos.front();
        TAG_LOGI(
            AAFwkTag::ABILITYMGR, "ImplicitQueryInfos success, target ability: %{public}s", info.abilityName.data());
        return IN_PROCESS_CALL(startAbilityTask(info.bundleName, info.abilityName));
    }

    if (AppUtils::GetInstance().IsSelectorDialogDefaultPossion()) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "ImplicitQueryInfos success, Multiple apps to choose.");
        ret = sysDialogScheduler->GetSelectorDialogWant(dialogAppInfos, request.want, want, request.callerToken);
        if (ret != ERR_OK) {
            TAG_LOGE(AAFwkTag::ABILITYMGR, "GetSelectorDialogWant failed.");
            return ret;
        }
        if (want.GetBoolParam("isCreateAppGallerySelector", false)) {
            want.RemoveParam("isCreateAppGallerySelector");
            if (isAppCloneSelector) {
                return DialogSessionManager::GetInstance().CreateCloneSelectorModalDialog(request, want,
                    userId, dialogAppInfos, replaceWantString);
            }
            return DialogSessionManager::GetInstance().CreateImplicitSelectorModalDialog(request,
                want, userId, dialogAppInfos);
        }
        ret = abilityMgr->ImplicitStartAbilityAsCaller(request.want, request.callerToken, nullptr);
        // reset calling indentity
        IPCSkeleton::SetCallingIdentity(identity);
        return ret;
    }

    TAG_LOGI(AAFwkTag::ABILITYMGR, "ImplicitQueryInfos success, Multiple apps to choose in pc.");
    std::string type = MatchTypeAndUri(request.want);

    ret = sysDialogScheduler->GetPcSelectorDialogWant(dialogAppInfos, request.want, want,
        type, userId, request.callerToken);
    if (ret != ERR_OK) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "GetPcSelectorDialogWant failed.");
        return ret;
    }
    if (want.GetBoolParam("isCreateAppGallerySelector", false)) {
        want.RemoveParam("isCreateAppGallerySelector");
        if (isAppCloneSelector) {
            return DialogSessionManager::GetInstance().CreateCloneSelectorModalDialog(request, want, userId,
                dialogAppInfos, replaceWantString);
        }
        return DialogSessionManager::GetInstance().CreateImplicitSelectorModalDialog(request, want, userId,
            dialogAppInfos);
    }
    ret = abilityMgr->ImplicitStartAbilityAsCaller(request.want, request.callerToken, nullptr);
    // reset calling indentity
    IPCSkeleton::SetCallingIdentity(identity);
    return ret;
}

std::string ImplicitStartProcessor::MatchTypeAndUri(const AAFwk::Want &want)
{
    std::string type = want.GetType();
    if (type.empty()) {
        auto uri = want.GetUriString();
        auto suffixIndex = uri.rfind('.');
        if (suffixIndex == std::string::npos) {
            TAG_LOGE(AAFwkTag::ABILITYMGR, "Get suffix failed, uri is %{public}s", uri.c_str());
            return "";
        }
        type = uri.substr(suffixIndex);
#ifdef WITH_DLP
        if (type == ".dlp") {
            auto suffixDlpIndex = uri.rfind('.', suffixIndex - 1);
            if (suffixDlpIndex == std::string::npos) {
                TAG_LOGE(AAFwkTag::ABILITYMGR, "Get suffix failed, uri is %{public}s", uri.c_str());
                return "";
            }
            type = uri.substr(suffixDlpIndex, suffixIndex - suffixDlpIndex);
        }
#endif // WITH_DLP
    }
    return type;
}

static void ProcessLinkType(std::vector<AppExecFwk::AbilityInfo> &abilityInfos)
{
    bool appLinkingExist = false;
    bool defaultAppExist = false;
    if (!abilityInfos.size()) {
        return;
    }
    for (const auto &info : abilityInfos) {
        if (info.linkType == AppExecFwk::LinkType::APP_LINK) {
            appLinkingExist = true;
        }
        if (info.linkType == AppExecFwk::LinkType::DEFAULT_APP) {
            defaultAppExist = true;
        }
    }
    if (!appLinkingExist && !defaultAppExist) {
        return;
    }
    TAG_LOGI(AAFwkTag::ABILITYMGR, "Open applink first!");
    for (auto it = abilityInfos.begin(); it != abilityInfos.end();) {
        if (it->linkType == AppExecFwk::LinkType::APP_LINK) {
            it++;
            continue;
        }
        if (it->linkType == AppExecFwk::LinkType::DEFAULT_APP && appLinkingExist) {
            TAG_LOGD(AAFwkTag::ABILITYMGR, "%{public}s default deleted.", it->name.c_str());
            it = abilityInfos.erase(it);
            continue;
        }
        if (it->linkType == AppExecFwk::LinkType::DEEP_LINK) {
            TAG_LOGD(AAFwkTag::ABILITYMGR, "%{public}s deleted.", it->name.c_str());
            it = abilityInfos.erase(it);
            continue;
        }
        it++;
    }
}

void ImplicitStartProcessor::OnlyKeepReserveApp(std::vector<AppExecFwk::AbilityInfo> &abilityInfos,
    std::vector<AppExecFwk::ExtensionAbilityInfo> &extensionInfos, const AbilityRequest &request)
{
    if (!request.uriReservedFlag) {
        return;
    }
    if (extensionInfos.size() > 0) {
        extensionInfos.clear();
    }

    for (auto it = abilityInfos.begin(); it != abilityInfos.end();) {
        if (it->bundleName == request.reservedBundleName) {
            it++;
            continue;
        } else {
            TAG_LOGI(AAFwkTag::ABILITYMGR, "Reserve App %{public}s dismatch with bundleName %{public}s.",
                request.reservedBundleName.c_str(), it->bundleName.c_str());
            it = abilityInfos.erase(it);
        }
    }
}

int ImplicitStartProcessor::GenerateAbilityRequestByAction(int32_t userId,
    AbilityRequest &request, std::vector<DialogAppInfo> &dialogAppInfos, bool isMoreHapList)
{
    HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
    TAG_LOGD(AAFwkTag::ABILITYMGR, "%{public}s.", __func__);
    // get abilityinfos from bms
    auto bundleMgrHelper = GetBundleManagerHelper();
    CHECK_POINTER_AND_RETURN(bundleMgrHelper, GET_ABILITY_SERVICE_FAILED);
    auto abilityInfoFlag = AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_DEFAULT
        | AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_SKILL_URI
        | AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_APPLICATION;
    std::vector<AppExecFwk::AbilityInfo> abilityInfos;
    std::vector<AppExecFwk::ExtensionAbilityInfo> extensionInfos;
    bool withDefault = false;
    withDefault = request.want.GetBoolParam(SHOW_DEFAULT_PICKER_FLAG, withDefault) ? false : true;
    bool appLinkingOnly = false;
    bool isOpenLink = false;
    isOpenLink = request.want.HasParameter(OPEN_LINK_APP_LINKING_ONLY);
    appLinkingOnly = request.want.GetBoolParam(OPEN_LINK_APP_LINKING_ONLY, false);

    if (IPCSkeleton::GetCallingUid() == NFC_CALLER_UID &&
        !request.want.GetStringArrayParam(PARAM_ABILITY_APPINFOS).empty()) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "The NFCNeed caller source is NFC.");
        ImplicitStartProcessor::QueryBmsAppInfos(request, userId, dialogAppInfos);
    }

    if (!StartAbilityUtils::IsCallFromAncoShellOrBroker(request.callerToken)) {
        request.want.RemoveParam(ANCO_PENDING_REQUEST);
    }

    if (appLinkingOnly) {
        abilityInfoFlag = static_cast<uint32_t>(abilityInfoFlag) |
            static_cast<uint32_t>(AppExecFwk::GetAbilityInfoFlag::GET_ABILITY_INFO_WITH_APP_LINKING);
    }

    if (request.uriReservedFlag) {
        abilityInfoFlag = static_cast<uint32_t>(abilityInfoFlag) |
            static_cast<uint32_t>(AppExecFwk::GetAbilityInfoFlag::GET_ABILITY_INFO_ONLY_SYSTEM_APP);
    }

    if (isOpenLink) {
        std::string linkUriScheme = request.want.GetUri().GetScheme();
        if (linkUriScheme == HTTPS_SCHEME_NAME || linkUriScheme == HTTP_SCHEME_NAME) {
            request.want.SetAction(ACTION_VIEW);
        }
    }

    IN_PROCESS_CALL_WITHOUT_RET(bundleMgrHelper->ImplicitQueryInfos(
        request.want, abilityInfoFlag, userId, withDefault, abilityInfos, extensionInfos));

    OnlyKeepReserveApp(abilityInfos, extensionInfos, request);
    if (isOpenLink && extensionInfos.size() > 0) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "Clear extensionInfos when isOpenLink.");
        extensionInfos.clear();
    }

    TAG_LOGI(AAFwkTag::ABILITYMGR,
        "ImplicitQueryInfos, abilityInfo size : %{public}zu, extensionInfos size: %{public}zu.", abilityInfos.size(),
        extensionInfos.size());

    if (appLinkingOnly && abilityInfos.size() == 0) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "There isn't match app.");
        return ERR_IMPLICIT_START_ABILITY_FAIL;
    }

    if (!appLinkingOnly) {
        ProcessLinkType(abilityInfos);
    }

#ifdef WITH_DLP
    if (request.want.GetBoolParam(AbilityUtil::DLP_PARAMS_SANDBOX, false)) {
        Security::DlpPermission::DlpFileKits::ConvertAbilityInfoWithSupportDlp(request.want, abilityInfos);
        extensionInfos.clear();
    }
#endif // WITH_DLP

    if (abilityInfos.size() + extensionInfos.size() > 1) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "More than one target application, filter by erms");
        bool ret = FilterAbilityList(request.want, abilityInfos, extensionInfos, userId);
        if (!ret) {
            TAG_LOGE(AAFwkTag::ABILITYMGR, "FilterAbilityList failed");
        }
    }

    auto isExtension = request.callType == AbilityCallType::START_EXTENSION_TYPE;

    Want implicitwant;
    std::string typeName = MatchTypeAndUri(request.want);

    implicitwant.SetAction(request.want.GetAction());
    implicitwant.SetType(TYPE_ONLY_MATCH_WILDCARD);
    std::vector<AppExecFwk::AbilityInfo> implicitAbilityInfos;
    std::vector<AppExecFwk::ExtensionAbilityInfo> implicitExtensionInfos;
    std::vector<std::string> infoNames;
    if (!AppUtils::GetInstance().IsSelectorDialogDefaultPossion() && isMoreHapList) {
        IN_PROCESS_CALL_WITHOUT_RET(bundleMgrHelper->ImplicitQueryInfos(implicitwant, abilityInfoFlag, userId,
            withDefault, implicitAbilityInfos, implicitExtensionInfos));
        if (implicitAbilityInfos.size() != 0 && typeName != TYPE_ONLY_MATCH_WILDCARD) {
            for (auto implicitAbilityInfo : implicitAbilityInfos) {
                infoNames.emplace_back(implicitAbilityInfo.bundleName + "#" +
                    implicitAbilityInfo.moduleName + "#" + implicitAbilityInfo.name);
            }
        }
    }

    if (abilityInfos.size() == 1) {
        auto skillUri =  abilityInfos.front().skillUri;
        SetTargetLinkInfo(skillUri, request.want);
        if (abilityInfos.front().linkType == AppExecFwk::LinkType::APP_LINK) {
            EventInfo eventInfo;
            eventInfo.bundleName = abilityInfos.front().bundleName;
            eventInfo.callerBundleName = request.want.GetStringParam(Want::PARAM_RESV_CALLER_BUNDLE_NAME);
            eventInfo.uri = request.want.GetUriString();
            SendAbilityEvent(EventName::START_ABILITY_BY_APP_LINKING, HiSysEventType::BEHAVIOR, eventInfo);
        }
    }

    {
        HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "for (const auto &info : abilityInfos)");
        bool isExistDefaultApp = IsExistDefaultApp(userId, typeName);
        for (const auto &info : abilityInfos) {
            AddInfoParam param = {
                .info = info,
                .userId = userId,
                .isExtension = isExtension,
                .isMoreHapList = isMoreHapList,
                .withDefault = withDefault,
                .typeName = typeName,
                .infoNames = infoNames,
                .isExistDefaultApp = isExistDefaultApp
            };
            AddAbilityInfoToDialogInfos(param, dialogAppInfos);
        }
    }

    for (const auto &info : extensionInfos) {
        if (!isExtension || !CheckImplicitStartExtensionIsValid(request, info)) {
            continue;
        }
        DialogAppInfo dialogAppInfo;
        dialogAppInfo.abilityName = info.name;
        dialogAppInfo.bundleName = info.bundleName;
        dialogAppInfo.abilityIconId = info.iconId;
        dialogAppInfo.abilityLabelId = info.labelId;
        dialogAppInfo.bundleIconId = info.applicationInfo.iconId;
        dialogAppInfo.bundleLabelId = info.applicationInfo.labelId;
        dialogAppInfo.visible = info.visible;
        dialogAppInfo.appIndex = info.applicationInfo.appIndex;
        dialogAppInfo.multiAppMode = info.applicationInfo.multiAppMode;
        dialogAppInfos.emplace_back(dialogAppInfo);
    }

    return ERR_OK;
}

int ImplicitStartProcessor::GenerateAbilityRequestByAppIndexes(int32_t userId, AbilityRequest &request,
    std::vector<DialogAppInfo> &dialogAppInfos)
{
    auto appIndexes = StartAbilityUtils::GetCloneAppIndexes(request.want.GetBundle(), userId);
    if (appIndexes.size() > AbilityRuntime::GlobalConstant::MAX_APP_CLONE_INDEX) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "The size of appIndexes is too large.");
        return ERR_INVALID_VALUE;
    }
    auto bms = GetBundleManagerHelper();
    CHECK_POINTER_AND_RETURN(bms, GET_ABILITY_SERVICE_FAILED);
    auto abilityInfoFlag = static_cast<uint32_t>(AbilityRuntime::StartupUtil::BuildAbilityInfoFlag()) |
        static_cast<uint32_t>(AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_SKILL);
    std::vector<AppExecFwk::AbilityInfo> abilityInfos;
    abilityInfos.emplace_back(request.abilityInfo);
    for (auto &appIndex: appIndexes) {
        AppExecFwk::AbilityInfo abilityInfo;
        IN_PROCESS_CALL_WITHOUT_RET(bms->QueryCloneAbilityInfo(request.want.GetElement(), abilityInfoFlag, appIndex,
            abilityInfo, userId));
        if (abilityInfo.name.empty() || abilityInfo.bundleName.empty()) {
            int32_t ret = FindExtensionInfo(request.want, abilityInfoFlag, userId, appIndex, abilityInfo);
            if (ret != ERR_OK) {
                TAG_LOGE(AAFwkTag::ABILITYMGR, "query clone extension info failed.");
                return ret;
            }
        }
        abilityInfos.emplace_back(abilityInfo);
    }
    for (const auto &info : abilityInfos) {
        DialogAppInfo dialogAppInfo;
        dialogAppInfo.abilityName = info.name;
        dialogAppInfo.bundleName = info.bundleName;
        dialogAppInfo.moduleName = info.moduleName;
        dialogAppInfo.abilityIconId = info.iconId;
        dialogAppInfo.abilityLabelId = info.labelId;
        dialogAppInfo.bundleIconId = info.applicationInfo.iconId;
        dialogAppInfo.bundleLabelId = info.applicationInfo.labelId;
        dialogAppInfo.visible = info.visible;
        dialogAppInfo.appIndex = info.applicationInfo.appIndex;
        dialogAppInfo.multiAppMode = info.applicationInfo.multiAppMode;
        dialogAppInfos.emplace_back(dialogAppInfo);
    }
    return ERR_OK;
}

int ImplicitStartProcessor::FindExtensionInfo(const Want &want, int32_t flags, int32_t userId,
    int32_t appIndex, AppExecFwk::AbilityInfo &abilityInfo)
{
    HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
    auto bms = GetBundleManagerHelper();
    CHECK_POINTER_AND_RETURN(bms, GET_ABILITY_SERVICE_FAILED);
    AppExecFwk::ExtensionAbilityInfo extensionInfo;
    IN_PROCESS_CALL_WITHOUT_RET(bms->QueryCloneExtensionAbilityInfoWithAppIndex(want.GetElement(),
        flags, appIndex, extensionInfo, userId));
    if (extensionInfo.bundleName.empty() || extensionInfo.name.empty()) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "extensionInfo empty.");
        return RESOLVE_ABILITY_ERR;
    }
    if (AbilityRuntime::StartupUtil::IsSupportAppClone(extensionInfo.type)) {
        AbilityRuntime::StartupUtil::InitAbilityInfoFromExtension(extensionInfo, abilityInfo);
        return ERR_OK;
    }
    return ERR_APP_CLONE_INDEX_INVALID;
}

int ImplicitStartProcessor::QueryBmsAppInfos(AbilityRequest &request, int32_t userId,
    std::vector<DialogAppInfo> &dialogAppInfos)
{
    auto bundleMgrHelper = GetBundleManagerHelper();
    std::vector<AppExecFwk::AbilityInfo> bmsApps;
    auto abilityInfoFlag = AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_DEFAULT
        | AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_SKILL_URI
        | AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_APPLICATION;
    std::vector<std::string> apps = request.want.GetStringArrayParam(PARAM_ABILITY_APPINFOS);
    for (std::string appInfoStr : apps) {
        AppExecFwk::AbilityInfo abilityInfo;
        std::vector<std::string> appInfos = ImplicitStartProcessor::SplitStr(appInfoStr, '/');
        if (appInfos.empty() || appInfos.size() != NFC_QUERY_LENGTH) {
            continue;
        }
        std::string bundleName = appInfos[0];
        std::string abilityName = appInfos[1];
        std::string queryAbilityName = bundleName.append(abilityName);
        Want want;
        want.SetElementName(appInfos[0], queryAbilityName);

        IN_PROCESS_CALL_WITHOUT_RET(bundleMgrHelper->QueryAbilityInfo(want, abilityInfoFlag,
            userId, abilityInfo));
        if (!abilityInfo.name.empty() && !abilityInfo.bundleName.empty() && !abilityInfo.moduleName.empty()) {
            bmsApps.emplace_back(abilityInfo);
        }
    }
    if (!bmsApps.empty()) {
        for (const auto &abilityInfo : bmsApps) {
            DialogAppInfo dialogAppInfo;
            dialogAppInfo.abilityName = abilityInfo.name;
            dialogAppInfo.bundleName = abilityInfo.bundleName;
            dialogAppInfo.moduleName = abilityInfo.moduleName;
            dialogAppInfo.abilityIconId = abilityInfo.iconId;
            dialogAppInfo.abilityLabelId = abilityInfo.labelId;
            dialogAppInfo.bundleIconId = abilityInfo.applicationInfo.iconId;
            dialogAppInfo.bundleLabelId = abilityInfo.applicationInfo.labelId;
            dialogAppInfo.visible = abilityInfo.visible;
            dialogAppInfo.appIndex = abilityInfo.applicationInfo.appIndex;
            dialogAppInfo.multiAppMode = abilityInfo.applicationInfo.multiAppMode;
            dialogAppInfos.emplace_back(dialogAppInfo);
        }
    }
    return ERR_OK;
}

std::vector<std::string> ImplicitStartProcessor::SplitStr(const std::string& str, char delimiter)
{
    std::stringstream ss(str);
    std::vector<std::string> result;
    std::string s;
    while (std::getline(ss, s, delimiter)) {
        result.push_back(s);
    }
    return result;
}

bool ImplicitStartProcessor::CheckImplicitStartExtensionIsValid(const AbilityRequest &request,
    const AppExecFwk::ExtensionAbilityInfo &extensionInfo)
{
    if (!request.want.GetElement().GetBundleName().empty()) {
        return true;
    }
    TAG_LOGD(
        AAFwkTag::ABILITYMGR, "ImplicitStartExtension type: %{public}d.", static_cast<int32_t>(extensionInfo.type));
    if (!IsExtensionInWhiteList(extensionInfo.type)) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "The extension without UI is not allowed ImplicitStart");
        return false;
    }
    return true;
}

int32_t ImplicitStartProcessor::ImplicitStartAbilityInner(const Want &targetWant,
    const AbilityRequest &request, int32_t userId)
{
    HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
    auto abilityMgr = DelayedSingleton<AbilityManagerService>::GetInstance();
    CHECK_POINTER_AND_RETURN(abilityMgr, ERR_INVALID_VALUE);

    int32_t result = ERR_OK;
    switch (request.callType) {
        case AbilityCallType::START_OPTIONS_TYPE: {
            StartOptions startOptions;
            auto displayId = targetWant.GetIntParam(Want::PARAM_RESV_DISPLAY_ID, 0);
            auto windowMode = targetWant.GetIntParam(Want::PARAM_RESV_WINDOW_MODE, 0);
            startOptions.SetDisplayID(static_cast<int32_t>(displayId));
            startOptions.SetWindowMode(static_cast<int32_t>(windowMode));
            result = abilityMgr->ImplicitStartAbility(
                targetWant, startOptions, request.callerToken, userId, request.requestCode);
            break;
        }
        case AbilityCallType::START_SETTINGS_TYPE: {
            CHECK_POINTER_AND_RETURN(request.startSetting, ERR_INVALID_VALUE);
            result = abilityMgr->ImplicitStartAbility(
                targetWant, *request.startSetting, request.callerToken, userId, request.requestCode);
            break;
        }
        case AbilityCallType::START_EXTENSION_TYPE:
            result = abilityMgr->ImplicitStartExtensionAbility(
                targetWant, request.callerToken, userId, request.extensionType);
            break;
        default:
            result = abilityMgr->StartAbilityWrap(
                targetWant, request.callerToken, request.requestCode, false, userId, false, 0, false, true);
            break;
    }

    return result;
}

int ImplicitStartProcessor::CallStartAbilityInner(int32_t userId,
    const Want &want, const StartAbilityClosure &callBack, const AbilityCallType &callType)
{
    EventInfo eventInfo;
    eventInfo.userId = userId;
    eventInfo.bundleName = want.GetElement().GetBundleName();
    eventInfo.moduleName = want.GetElement().GetModuleName();
    eventInfo.abilityName = want.GetElement().GetAbilityName();

    if (callType == AbilityCallType::INVALID_TYPE) {
        SendAbilityEvent(EventName::START_ABILITY, HiSysEventType::BEHAVIOR, eventInfo);
    }

    TAG_LOGI(AAFwkTag::ABILITYMGR, "ability:%{public}s, bundle:%{public}s", eventInfo.abilityName.c_str(),
        eventInfo.bundleName.c_str());

    auto ret = callBack();
    if (ret != ERR_OK) {
        eventInfo.errCode = ret;
        if (callType == AbilityCallType::INVALID_TYPE) {
            SendAbilityEvent(EventName::START_ABILITY_ERROR, HiSysEventType::FAULT, eventInfo);
        }
    }
    return ret;
}

std::shared_ptr<AppExecFwk::BundleMgrHelper> ImplicitStartProcessor::GetBundleManagerHelper()
{
    if (iBundleManagerHelper_ == nullptr) {
        iBundleManagerHelper_ = AbilityUtil::GetBundleManagerHelper();
    }
    return iBundleManagerHelper_;
}

sptr<AppExecFwk::IDefaultApp> ImplicitStartProcessor::GetDefaultAppProxy()
{
    auto bundleMgrHelper = GetBundleManagerHelper();
    if (bundleMgrHelper == nullptr) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "The bundleMgrHelper is nullptr.");
        return nullptr;
    }
    auto defaultAppProxy = bundleMgrHelper->GetDefaultAppProxy();
    if (defaultAppProxy == nullptr) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "The defaultAppProxy is nullptr.");
        return nullptr;
    }
    return defaultAppProxy;
}

bool ImplicitStartProcessor::FilterAbilityList(const Want &want, std::vector<AppExecFwk::AbilityInfo> &abilityInfos,
    std::vector<AppExecFwk::ExtensionAbilityInfo> extensionInfos, int32_t userId)
{
    ErmsCallerInfo callerInfo;
    GetEcologicalCallerInfo(want, callerInfo, userId);
    return true;
}

void ImplicitStartProcessor::GetEcologicalCallerInfo(const Want &want, ErmsCallerInfo &callerInfo, int32_t userId)
{
    callerInfo.packageName = want.GetStringParam(Want::PARAM_RESV_CALLER_BUNDLE_NAME);
    callerInfo.uid = want.GetIntParam(Want::PARAM_RESV_CALLER_UID, IPCSkeleton::GetCallingUid());
    callerInfo.pid = want.GetIntParam(Want::PARAM_RESV_CALLER_PID, IPCSkeleton::GetCallingPid());
    callerInfo.targetAppType = ErmsCallerInfo::TYPE_INVALID;
    callerInfo.callerAppType = ErmsCallerInfo::TYPE_INVALID;

    auto bundleMgrHelper = GetBundleManagerHelper();
    if (bundleMgrHelper == nullptr) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "Get Bubndle manager helper failed.");
        return;
    }

    std::string targetBundleName = want.GetBundle();
    AppExecFwk::ApplicationInfo targetAppInfo;
    bool getTargetResult = IN_PROCESS_CALL(bundleMgrHelper->GetApplicationInfo(targetBundleName,
        AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, targetAppInfo));
    if (!getTargetResult) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "Get targetAppInfo failed.");
    } else if (targetAppInfo.bundleType == AppExecFwk::BundleType::ATOMIC_SERVICE) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "the target type  is atomic service");
        callerInfo.targetAppType = ErmsCallerInfo::TYPE_ATOM_SERVICE;
    } else if (targetAppInfo.bundleType == AppExecFwk::BundleType::APP) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "the target type is app");
        callerInfo.targetAppType = ErmsCallerInfo::TYPE_HARMONY_APP;
    } else {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "the target type is invalid type");
    }

    std::string callerBundleName;
    ErrCode err = IN_PROCESS_CALL(bundleMgrHelper->GetNameForUid(callerInfo.uid, callerBundleName));
    if (err != ERR_OK) {
        TAG_LOGE(AAFwkTag::ABILITYMGR, "Get callerBundleName failed.");
        return;
    }
    AppExecFwk::ApplicationInfo callerAppInfo;
    bool getCallerResult = IN_PROCESS_CALL(bundleMgrHelper->GetApplicationInfo(callerBundleName,
        AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, callerAppInfo));
    if (!getCallerResult) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "Get callerAppInfo failed.");
    } else if (callerAppInfo.bundleType == AppExecFwk::BundleType::ATOMIC_SERVICE) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "the caller type  is atomic service");
        callerInfo.callerAppType = ErmsCallerInfo::TYPE_ATOM_SERVICE;
    } else if (callerAppInfo.bundleType == AppExecFwk::BundleType::APP) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "the caller type is app");
        callerInfo.callerAppType = ErmsCallerInfo::TYPE_HARMONY_APP;
    } else {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "the caller type is invalid type");
    }
}

void ImplicitStartProcessor::AddIdentity(int32_t tokenId, std::string identity)
{
    std::lock_guard guard(identityListLock_);
    if (identityList_.size() == IDENTITY_LIST_MAX_SIZE) {
        identityList_.pop_front();
        identityList_.emplace_back(IdentityNode(tokenId, identity));
        return;
    }
    identityList_.emplace_back(IdentityNode(tokenId, identity));
}

void ImplicitStartProcessor::ResetCallingIdentityAsCaller(int32_t tokenId, bool flag)
{
    std::lock_guard guard(identityListLock_);
    for (auto it = identityList_.begin(); it != identityList_.end(); it++) {
        if (it->tokenId == tokenId) {
            IPCSkeleton::SetCallingIdentity(it->identity);
            if (flag) {
                identityList_.erase(it);
            }
            return;
        }
    }
}

void ImplicitStartProcessor::RemoveIdentity(int32_t tokenId)
{
    std::lock_guard guard(identityListLock_);
    for (auto it = identityList_.begin(); it != identityList_.end(); it++) {
        if (it->tokenId == tokenId) {
            identityList_.erase(it);
            return;
        }
    }
}

void ImplicitStartProcessor::AddAbilityInfoToDialogInfos(const AddInfoParam &param,
    std::vector<DialogAppInfo> &dialogAppInfos)
{
    if (param.isExtension && param.info.type != AbilityType::EXTENSION) {
        return;
    }
    if (!AppUtils::GetInstance().IsSelectorDialogDefaultPossion()) {
        bool isDefaultFlag = param.withDefault && param.isExistDefaultApp;
        if (!param.isMoreHapList && !isDefaultFlag &&
            std::find(param.infoNames.begin(), param.infoNames.end(),
            (param.info.bundleName + "#" + param.info.moduleName + "#" + param.info.name)) != param.infoNames.end()) {
            return;
        }
    }
    DialogAppInfo dialogAppInfo;
    dialogAppInfo.abilityName = param.info.name;
    dialogAppInfo.bundleName = param.info.bundleName;
    dialogAppInfo.moduleName = param.info.moduleName;
    dialogAppInfo.abilityIconId = param.info.iconId;
    dialogAppInfo.abilityLabelId = param.info.labelId;
    dialogAppInfo.bundleIconId = param.info.applicationInfo.iconId;
    dialogAppInfo.bundleLabelId = param.info.applicationInfo.labelId;
    dialogAppInfo.visible = param.info.visible;
    dialogAppInfo.appIndex = param.info.applicationInfo.appIndex;
    dialogAppInfo.multiAppMode = param.info.applicationInfo.multiAppMode;
    dialogAppInfos.emplace_back(dialogAppInfo);
}

bool ImplicitStartProcessor::IsExistDefaultApp(int32_t userId, const std::string &typeName)
{
    auto defaultMgr = GetDefaultAppProxy();
    AppExecFwk::BundleInfo bundleInfo;
    ErrCode ret =
        IN_PROCESS_CALL(defaultMgr->GetDefaultApplication(userId, typeName, bundleInfo));
    if (ret != ERR_OK) {
        return false;
    }

    if (bundleInfo.abilityInfos.size() == 1) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "find default ability.");
        return true;
    } else if (bundleInfo.extensionInfos.size() == 1) {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "find default extension.");
        return true;
    } else {
        TAG_LOGI(AAFwkTag::ABILITYMGR, "GetDefaultApplication failed.");
        return false;
    }
}

void ImplicitStartProcessor::SetTargetLinkInfo(const std::vector<AppExecFwk::SkillUriForAbilityAndExtension> &skillUri,
    Want &want)
{
    for (const auto& iter : skillUri) {
        if (iter.isMatch) {
            want.RemoveParam("send_to_erms_targetLinkFeature");
            want.SetParam("send_to_erms_targetLinkFeature", iter.linkFeature);
            want.RemoveParam("send_to_erms_targetLinkType");
            if (want.GetBoolParam(OPEN_LINK_APP_LINKING_ONLY, false)) {
                want.SetParam("send_to_erms_targetLinkType", AbilityCallerInfo::LINK_TYPE_UNIVERSAL_LINK);
            } else if ((iter.scheme == "https" || iter.scheme == "http") &&
                want.GetAction().compare(ACTION_VIEW) == 0) {
                want.SetParam("send_to_erms_targetLinkType", AbilityCallerInfo::LINK_TYPE_WEB_LINK);
            } else {
                want.SetParam("send_to_erms_targetLinkType", AbilityCallerInfo::LINK_TYPE_DEEP_LINK);
            }
        }
    }
}
}  // namespace AAFwk
}  // namespace OHOS