/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mock_session_manager_service.h"

#include <cstdint>
#include <fcntl.h>
#include <securec.h>
#include <unistd.h>

#include <bundle_mgr_interface.h>
#include <system_ability_definition.h>
#include <cinttypes>
#include <csignal>
#include <iomanip>
#include <ipc_skeleton.h>
#include <iservice_registry.h>
#include <map>
#include <sstream>

#include "window_manager_hilog.h"
#include "unique_fd.h"
#include "parameters.h"
#include "root_scene.h"
#include "string_ex.h"
#include "wm_common.h"
#include "ws_common.h"
#include "scene_board_judgement.h"
#include "scene_session_manager_interface.h"
#include "scene_session_manager_lite_interface.h"
#include "session_manager_service_interface.h"
#include "screen_session_manager_lite.h"
#include "common/include/session_permission.h"
#include "display_manager.h"

#define PATH_LEN 1024
#define O_RDWR   02

namespace OHOS {
namespace Rosen {
namespace {

const std::u16string DEFAULT_USTRING = u"error";
const char DEFAULT_STRING[] = "error";
const std::string ARG_DUMP_HELP = "-h";
const std::string ARG_DUMP_ALL = "-a";
const std::string ARG_DUMP_WINDOW = "-w";
const std::string KEY_SCENE_BOARD_TEST_ENABLE = "persist.scb.testmode.enable";
const std::string SCENE_BOARD_BUNDLE_NAME = "com.ohos.sceneboard";
const std::string TEST_MODULE_NAME_SUFFIX = "_test";
const std::string BOOTEVENT_WMS_READY = "bootevent.wms.ready";
} // namespace


class ClientListenerDeathRecipient : public IRemoteObject::DeathRecipient {
public:
    ClientListenerDeathRecipient(int32_t clientUserId, int32_t instanceUserId,
                                  int32_t pid, bool isLite)
        : clientUserId_(clientUserId), instanceUserId_(instanceUserId),
          pid_(pid), isLite_(isLite)
    {
    }

    void OnRemoteDied(const wptr<IRemoteObject>& wptrDeath) override
    {
        TLOGW(WmsLogTag::WMS_RECOVER, "Client died, pid = %{public}d, isLite = %{public}d", pid_, isLite_);
        TLOGI(WmsLogTag::WMS_RECOVER,
            "clientUserId: %{public}d, instanceUserId: %{public}d, "
            "pid: %{public}d, isLite: %{public}d",
            clientUserId_, instanceUserId_, pid_, isLite_);
        MockSessionManagerService::GetInstance().RemoveSMSRecoverListener(
            clientUserId_, pid_, instanceUserId_, isLite_);
        if (!isLite_) {
            MockSessionManagerService::GetInstance().ResetSpecificWindowZIndex(clientUserId_, pid_);
        }
    }

private:
    int32_t clientUserId_;    // Used to distinguish system/non-system user
    int32_t instanceUserId_;  // Used as key for map removal
    int32_t pid_;
    bool isLite_;
};

WM_IMPLEMENT_SINGLE_INSTANCE(MockSessionManagerService)
MockSessionManagerService::SMSDeathRecipient::SMSDeathRecipient(int32_t userId)
    : userId_(userId), screenId_(DEFAULT_SCREEN_ID)
{
}

void MockSessionManagerService::SMSDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& object)
{
    TLOGI(WmsLogTag::WMS_MULTI_USER, "Scb died with userId_=%{public}d, screenId_=%{public}d", userId_, screenId_);
    MockSessionManagerService::GetInstance().NotifyWMSConnectionChanged(
        userId_, screenId_, false, INVALID_USER_ID, INVALID_PID);
    MockSessionManagerService::GetInstance().RemoveScreenUserMappingIfMatched(screenId_, userId_);

    MockSessionManagerService::GetInstance().RemoveSMSDeathRecipientByUserId(userId_);
    MockSessionManagerService::GetInstance().RemoveSessionManagerServiceByUserId(userId_);
    auto sessionManagerService = object.promote();
    if (!sessionManagerService) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "sessionManagerService is null");
        return;
    }

    if (IsSceneBoardTestMode()) {
        TLOGI(WmsLogTag::WMS_MULTI_USER, "SceneBoard is testing, do not kill foundation.");
        return;
    }
    TLOGI(WmsLogTag::WMS_MULTI_USER, "SessionManagerService died!");
}

void MockSessionManagerService::SMSDeathRecipient::SetScreenId(int32_t screenId)
{
    TLOGI(WmsLogTag::WMS_MULTI_USER, "screenId=%{public}d", screenId);
    screenId_ = screenId;
}

MockSessionManagerService::MockSessionManagerService()
    : SystemAbility(WINDOW_MANAGER_SERVICE_ID, true), defaultWMSUserId_(INVALID_USER_ID)
{
    defaultScreenId_ = DisplayManager::GetInstance().GetDefaultDisplayId();
    TLOGI(WmsLogTag::WMS_MULTI_USER, "MockSessionManagerService initialized. Default screenId: %{public}" PRIu64,
        defaultScreenId_);
}

MockSessionManagerService::~MockSessionManagerService()
{
    TLOGI(WmsLogTag::WMS_MULTI_USER, "destoryed");
}

bool MockSessionManagerService::RegisterMockSessionManagerService()
{
    static bool isRegistered = false;
    static bool isPublished = false;
    if (isRegistered && isPublished) {
        TLOGW(WmsLogTag::WMS_MULTI_USER, "WindowManagerService SA has already been registered and published");
        return true;
    }
    if (!isRegistered) {
        isRegistered = SystemAbility::MakeAndRegisterAbility(this);
        if (isRegistered) {
            TLOGI(WmsLogTag::WMS_MULTI_USER, "Successfully registered WindowManagerService SA");
        } else {
            TLOGE(WmsLogTag::WMS_MULTI_USER, "Failed to register WindowManagerService SA");
        }
    }
    if (!isPublished) {
        isPublished = Publish(this);
        if (isPublished) {
            TLOGI(WmsLogTag::WMS_MULTI_USER, "Successfully published WindowManagerService SA");
        } else {
            TLOGE(WmsLogTag::WMS_MULTI_USER, "Failed to publish WindowManagerService SA");
        }
    }
    return isRegistered && isPublished;
}

void MockSessionManagerService::OnStart()
{
    WLOGFD("OnStart begin");
}

static std::string Str16ToStr8(const std::u16string& str)
{
    if (str == DEFAULT_USTRING) {
        return DEFAULT_STRING;
    }
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert(DEFAULT_STRING);
    std::string result = convert.to_bytes(str);
    return result == DEFAULT_STRING ? "" : result;
}

int MockSessionManagerService::Dump(int fd, const std::vector<std::u16string>& args)
{
    TLOGD(WmsLogTag::DEFAULT, "dump begin fd: %{public}d", fd);
    if (fd < 0) {
        return -1;
    }
    (void) signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE crash
    std::vector<std::string> params;
    for (auto& arg : args) {
        params.emplace_back(Str16ToStr8(arg));
    }

    std::string dumpInfo;
    if (params.empty()) {
        ShowHelpInfo(dumpInfo);
    } else if (params.size() == 1 && params[0] == ARG_DUMP_HELP) { // 1: params num
        ShowHelpInfo(dumpInfo);
    } else {
        int errCode = DumpSessionInfo(params, dumpInfo);
        if (errCode != 0) {
            ShowIllegalArgsInfo(dumpInfo);
        }
    }
    int ret = write(fd, dumpInfo.c_str(), dumpInfo.length());
    if (ret < 0) {
        WLOGFE("write error");
        return -1; // WMError::WM_ERROR_INVALID_OPERATION;
    }
    TLOGD(WmsLogTag::DEFAULT, "dump end");
    return 0;
}

bool MockSessionManagerService::SetSessionManagerService(sptr<IRemoteObject> sessionManagerService)
{
    if (!sessionManagerService) {
        TLOGE(WmsLogTag::WMS_SCB, "sessionManagerService is null");
        return false;
    }
    // Get default window manager service userId when sceneboard is started, normally is 100/101 and so on.
    int32_t currentWMSUserId = GetUserIdByCallingUid();
    if (currentWMSUserId <= INVALID_USER_ID) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "userId is illegal: %{public}d", currentWMSUserId);
        return false;
    }
    {
        // Note: Adapt to multi user and multi screen. The defaultWMSUserId_ is assigned here only after the
        // sceneboard is started for the first time. Then, DMS will call NotifyWMSConnected to assign
        // defaultWMSUserId_ by wms userId which in default screen.
        std::lock_guard<std::mutex> lock(defaultWMSUserIdMutex_);
        if (defaultWMSUserId_ == INVALID_USER_ID) {
            defaultWMSUserId_ = currentWMSUserId;
            TLOGI(WmsLogTag::WMS_MULTI_USER, "Set defaultWMSUserId_=%{public}d", defaultWMSUserId_);
        }
    }
    RecoverSCBSnapshotSkipByUserId(currentWMSUserId);
    auto smsDeathRecipient = GetSMSDeathRecipientByUserId(currentWMSUserId);
    if (!smsDeathRecipient) {
        smsDeathRecipient = sptr<SMSDeathRecipient>::MakeSptr(currentWMSUserId);
        std::unique_lock<std::shared_mutex> lock(smsDeathRecipientMapLock_);
        smsDeathRecipientMap_[currentWMSUserId] = smsDeathRecipient;
        TLOGI(WmsLogTag::WMS_MULTI_USER, "Create SMSDeathRecipient for userId: %{public}d", currentWMSUserId);
    }
    if (sessionManagerService->IsProxyObject() && !sessionManagerService->AddDeathRecipient(smsDeathRecipient)) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "Failed to add death recipient");
        return false;
    }
    {
        std::lock_guard<std::mutex> lock(sessionManagerServiceMapMutex_);
        sessionManagerServiceMap_[currentWMSUserId] = sessionManagerService;
    }
    RegisterMockSessionManagerService();
    system::SetParameter(BOOTEVENT_WMS_READY.c_str(), "true");
    GetSceneSessionManager();
    TLOGI(WmsLogTag::WMS_MULTI_USER, "Session manager service set success");
    return true;
}

sptr<MockSessionManagerService::SMSDeathRecipient> MockSessionManagerService::GetSMSDeathRecipientByUserId(
    int32_t userId)
{
    std::shared_lock<std::shared_mutex> lock(smsDeathRecipientMapLock_);
    auto iter = smsDeathRecipientMap_.find(userId);
    return (iter != smsDeathRecipientMap_.end()) ? iter->second : nullptr;
}

void MockSessionManagerService::RemoveSMSDeathRecipientByUserId(int32_t userId)
{
    TLOGI(WmsLogTag::WMS_MULTI_USER, "userId: %{public}d", userId);
    auto sessionManagerService = GetSessionManagerServiceInner(userId);
    if (sessionManagerService == nullptr) {
        return;
    }
    std::unique_lock<std::shared_mutex> lock(smsDeathRecipientMapLock_);
    auto iter = smsDeathRecipientMap_.find(userId);
    if (iter != smsDeathRecipientMap_.end() && iter->second) {
        sessionManagerService->RemoveDeathRecipient(iter->second);
    }
}

ErrCode MockSessionManagerService::GetSessionManagerService(sptr<IRemoteObject>& sessionManagerService)
{
    int32_t clientUserId = GetUserIdByCallingUid();
    if (clientUserId <= INVALID_USER_ID) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "userId is illegal: %{public}d", clientUserId);
        return ERR_INVALID_VALUE;
    }
    if (clientUserId == SYSTEM_USERID) {
        std::lock_guard<std::mutex> lock(defaultWMSUserIdMutex_);
        clientUserId = defaultWMSUserId_;
        TLOGD(WmsLogTag::WMS_MULTI_USER, "use default sessionManagerService with %{public}d", clientUserId);
    }
    sessionManagerService = GetSessionManagerServiceInner(clientUserId);
    if (!sessionManagerService) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "sessionManagerService is null");
        return ERR_INVALID_VALUE;
    }
    return ERR_OK;
}

ErrCode MockSessionManagerService::GetSessionManagerServiceByUserId(int32_t userId,
    sptr<IRemoteObject>& sessionManagerService)
{
    int32_t clientUserId = GetUserIdByCallingUid();
    TLOGI(WmsLogTag::WMS_MULTI_USER, "userId=%{public}d, clientUserId=%{public}d", userId, clientUserId);
    if (clientUserId <= INVALID_USER_ID) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "clientUserId is illegal, clientUserId=%{public}d", clientUserId);
        return ERR_INVALID_VALUE;
    }
    if (clientUserId != SYSTEM_USERID) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "clientUserId is not system, clientUserId=%{public}d", clientUserId);
        return ERR_WOULD_BLOCK;
    }
    sessionManagerService = GetSessionManagerServiceInner(userId);
    if (!sessionManagerService) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "sessionManagerService is null");
        return ERR_INVALID_VALUE;
    }
    return ERR_OK;
}


sptr<IRemoteObject> MockSessionManagerService::GetSessionManagerServiceInner(int32_t userId)
{
    std::lock_guard<std::mutex> lock(sessionManagerServiceMapMutex_);
    auto iter = sessionManagerServiceMap_.find(userId);
    if (iter != sessionManagerServiceMap_.end()) {
        TLOGI(WmsLogTag::WMS_MULTI_USER, "Get session manager service success with userId=%{public}d", userId);
        return iter->second;
    } else {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "Get session manager service failed with userId=%{public}d", userId);
        return nullptr;
    }
}

void MockSessionManagerService::RemoveSessionManagerServiceByUserId(int32_t userId)
{
    TLOGI(WmsLogTag::WMS_MULTI_USER, "userId: %{public}d", userId);
    RemoveFromMap(sessionManagerServiceMap_, sessionManagerServiceMapMutex_, userId);
    RemoveFromMap(sceneSessionManagerLiteMap_, sceneSessionManagerLiteMapMutex_, userId);
    RemoveFromMap(sceneSessionManagerMap_, sceneSessionManagerMapMutex_, userId);
}

void MockSessionManagerService::RemoveFromMap(std::map<int32_t, sptr<IRemoteObject>>& map,
                                              std::mutex& mutex,
                                              int32_t userId)
{
    std::lock_guard<std::mutex> lock(mutex);
    auto iter = map.find(userId);
    if (iter != map.end()) {
        map.erase(iter);
        TLOGI(WmsLogTag::WMS_MULTI_USER, "RemoveFromMap success, userId: %{public}d", userId);
    }
}

ErrCode MockSessionManagerService::RegisterSMSRecoverListener(int32_t userId,
    bool isLite, const sptr<IRemoteObject>& listener)
{
    if (listener == nullptr) {
        TLOGE(WmsLogTag::WMS_RECOVER, "listener is null");
        return ERR_INVALID_VALUE;
    }
    
    int32_t clientUserId = GetUserIdByCallingUid();
    if (clientUserId <= INVALID_USER_ID) {
        TLOGE(WmsLogTag::WMS_RECOVER, "illegal clientUserId: %{public}d", clientUserId);
        return ERR_INVALID_VALUE;
    }
    
    int32_t pid = IPCSkeleton::GetCallingRealPid();
    auto smsListener = iface_cast<ISessionManagerServiceRecoverListener>(listener);
    if (!smsListener) {
        TLOGE(WmsLogTag::WMS_RECOVER, "IPC convert failed");
        return ERR_INVALID_VALUE;
    }
    int32_t instanceUserId = userId;
    int32_t wmsUserId = userId;
    if (clientUserId == SYSTEM_USERID) {
        if (userId == INVALID_USER_ID) {
            std::lock_guard<std::mutex> lock(defaultWMSUserIdMutex_);
            wmsUserId = defaultWMSUserId_;
        }
        TLOGI(WmsLogTag::WMS_RECOVER,
            "clientUserId: %{public}d, wmsUserId: %{public}d, instanceUserId: %{public}d, "
            "pid: %{public}d, isLite: %{public}d",
            clientUserId, wmsUserId, instanceUserId, pid, isLite);
        
        if (!AddClientDeathRecipient(listener, SYSTEM_USERID, instanceUserId, pid, isLite)) {
            return ERR_INVALID_VALUE;
        }
        AddSMSRecoverListener(SYSTEM_USERID, pid, instanceUserId, isLite, smsListener);
        return NotifyWMSConnectionStatus(wmsUserId, smsListener);
    } else {
        TLOGI(WmsLogTag::WMS_RECOVER,
            "clientUserId: %{public}d, pid: %{public}d, isLite: %{public}d",
            clientUserId, pid, isLite);
        
        if (!AddClientDeathRecipient(listener, clientUserId, instanceUserId, pid, isLite)) {
            return ERR_INVALID_VALUE;
        }
        AddSMSRecoverListener(clientUserId, pid, instanceUserId, isLite, smsListener);
        return ERR_WOULD_BLOCK;
    }
}

ErrCode MockSessionManagerService::UnregisterSMSRecoverListener(int32_t userId, bool isLite)
{
    int32_t clientUserId = GetUserIdByCallingUid();
    if (clientUserId <= INVALID_USER_ID) {
        TLOGE(WmsLogTag::WMS_RECOVER, "illegal clientUserId: %{public}d", clientUserId);
        return ERR_INVALID_VALUE;
    }
    
    int32_t instanceUserId = userId;
    
    int32_t pid = IPCSkeleton::GetCallingRealPid();
    TLOGI(WmsLogTag::WMS_RECOVER,
        "clientUserId: %{public}d, instanceUserId: %{public}d, "
        "pid: %{public}d, isLite: %{public}d",
        clientUserId, instanceUserId, pid, isLite);
    RemoveSMSRecoverListener(clientUserId, pid, instanceUserId, isLite);
    return ERR_OK;
}

ErrCode MockSessionManagerService::NotifySetSpecificWindowZIndex()
{
    int32_t pid = IPCSkeleton::GetCallingRealPid();
    int32_t userId = GetUserIdByCallingUid();
    std::lock_guard<std::mutex> lock(specificZIndexByPidMapMutex_);
    specificZIndexByPidMap_[pid] = userId;
    TLOGI(WmsLogTag::WMS_FOCUS, "pid: %{public}d", pid);
    return ERR_OK;
}

void MockSessionManagerService::ResetSpecificWindowZIndex(int32_t clientUserId, int32_t pid)
{
    TLOGI(WmsLogTag::WMS_FOCUS, "clientUserId: %{public}d, pid: %{public}d", clientUserId, pid);
    {
        std::lock_guard<std::mutex> lock(specificZIndexByPidMapMutex_);
        auto iter = specificZIndexByPidMap_.find(pid);
        if (iter == specificZIndexByPidMap_.end()) {
            return;
        }
    }
    sptr<IRemoteObject> remoteObject = GetSceneSessionManagerByUserId(clientUserId);
    if (!remoteObject) {
        TLOGE(WmsLogTag::WMS_FOCUS, "remoteObject is null");
        return;
    }
    sptr<ISceneSessionManager> sceneSessionManagerProxy = iface_cast<ISceneSessionManager>(remoteObject);
    if (sceneSessionManagerProxy == nullptr) {
        TLOGE(WmsLogTag::WMS_FOCUS, "sessionManagerServiceProxy is nullptr");
        return;
    }
    sceneSessionManagerProxy->ResetSpecificWindowZIndex(pid);
    {
        std::lock_guard<std::mutex> lock(specificZIndexByPidMapMutex_);
        specificZIndexByPidMap_.erase(pid);
    }
}

ErrCode MockSessionManagerService::NotifySceneBoardAvailable()
{
    if (!SessionPermission::IsSystemCalling()) {
        TLOGE(WmsLogTag::WMS_RECOVER, "permission denied");
        return ERR_PERMISSION_DENIED;
    }
    int32_t userId = GetUserIdByCallingUid();
    if (userId <= INVALID_USER_ID) {
        TLOGE(WmsLogTag::WMS_RECOVER, "userId is illegal: %{public}d", userId);
        return ERR_INVALID_VALUE;
    }
    TLOGI(WmsLogTag::WMS_RECOVER, "scene board is available with userId=%{public}d", userId);
    // notify lite
    NotifySceneBoardAvailableToSystemAppClient(userId, true);
    NotifySceneBoardAvailableToClient(userId, true);

    NotifySceneBoardAvailableToSystemAppClient(userId, false);
    NotifySceneBoardAvailableToClient(userId, false);
    return ERR_OK;
}

void MockSessionManagerService::NotifySceneBoardAvailableToSystemAppClient(int32_t userId, bool isLite)
{
    auto sessionManagerService = GetSessionManagerServiceInner(userId);
    if (sessionManagerService == nullptr) {
        TLOGE(WmsLogTag::WMS_RECOVER, "SessionManagerService is null");
        return;
    }

    auto listeners = CollectListenersByInstanceUserId(SYSTEM_USERID, userId, isLite);

    int32_t defaultWMSUserId = GetDefaultWMSUserId();
    if (userId == defaultWMSUserId) {
        auto invalidUserIdListeners = CollectListenersByInstanceUserId(SYSTEM_USERID, INVALID_USER_ID, isLite);
        listeners.insert(listeners.end(), invalidUserIdListeners.begin(), invalidUserIdListeners.end());
    }

    TLOGI(WmsLogTag::WMS_RECOVER,
        "userId: %{public}d, isLite: %{public}d, Remote count: %{public}zu",
        userId, isLite, listeners.size());
    for (auto& [pid, listener] : listeners) {
        TLOGI(WmsLogTag::WMS_RECOVER, "Call OnSessionManagerServiceRecover pid: %{public}d", pid);
        listener->OnSessionManagerServiceRecover(sessionManagerService);
    }
}

void MockSessionManagerService::NotifySceneBoardAvailableToClient(int32_t userId, bool isLite)
{
    auto sessionManagerService = GetSessionManagerServiceInner(userId);
    if (sessionManagerService == nullptr) {
        TLOGE(WmsLogTag::WMS_RECOVER, "SessionManagerService is null");
        return;
    }

    auto listeners = CollectListenersByClientUserId(userId, isLite);
    
    TLOGI(WmsLogTag::WMS_RECOVER, "userId: %{public}d, isLite: %{public}d, Remote count: %{public}zu",
        userId, isLite, listeners.size());
    for (auto& [pid, listener] : listeners) {
        TLOGI(WmsLogTag::WMS_RECOVER, "Call OnSessionManagerServiceRecover pid = %{public}d", pid);
        listener->OnSessionManagerServiceRecover(sessionManagerService);
    }
}

void MockSessionManagerService::NotifyWMSConnected(int32_t userId, DisplayId screenId, bool isColdStart)
{
    TLOGI(WmsLogTag::WMS_MULTI_USER, "userId: %{public}d, screenId: [%{public}" PRIu64"], isColdStart: %{public}d",
        userId, screenId, isColdStart);
    UpdateUserId2PidMapping(userId, IPCSkeleton::GetCallingPid());

    int32_t fromUserId = INVALID_USER_ID;
    int32_t fromPid = INVALID_PID;
    fromUserId = GetUserIdOnScreen(screenId, userId);
    fromPid = GetWmsPidByUserId(fromUserId);

    TLOGI(WmsLogTag::WMS_MULTI_USER,
        "userId: %{public}d, screenId: [%{public}" PRIu64"], isColdStart: %{public}d, "
        "fromUserId: %{public}d, fromPid: %{public}d",
        userId, screenId, isColdStart, fromUserId, fromPid);

    UpdateScreenUserInfo(userId, screenId);

    if (screenId == defaultScreenId_) {
        // Note: Adapt to multi user and multi screen. When default screen notified by DMS,
        // set defaultWMSUserId_ to current sceneboard wms userId.
        std::lock_guard<std::mutex> lock(defaultWMSUserIdMutex_);
        defaultWMSUserId_ = userId;
        TLOGI(WmsLogTag::WMS_MULTI_USER, "Set defaultWMSUserId_=%{public}d", defaultWMSUserId_);
    }
    auto smsDeathRecipient = GetSMSDeathRecipientByUserId(userId);
    if (smsDeathRecipient != nullptr) {
        smsDeathRecipient->SetScreenId(screenId);
    } else {
        TLOGW(WmsLogTag::WMS_MULTI_USER, "failed to set screenId");
    }
    if (!isColdStart) {
        TLOGI(WmsLogTag::WMS_MULTI_USER, "User switched");
        GetSceneSessionManager();
    }
    NotifyWMSConnectionChanged(userId, screenId, true, fromUserId, fromPid);
}

void MockSessionManagerService::NotifyWMSConnectionChanged(int32_t wmsUserId,
    DisplayId screenId, bool isConnected, int32_t fromUserId, int32_t fromPid)
{
    int32_t pid = GetWmsPidByUserId(wmsUserId);

    TLOGI(WmsLogTag::WMS_MULTI_USER,
        "wmsUserId=%{public}d, isConnected=%{public}d, pid=%{public}d, "
        "fromUserId=%{public}d, fromPid=%{public}d",
        wmsUserId, isConnected, pid, fromUserId, fromPid);
    {
        std::lock_guard<std::mutex> lock(wmsConnectionStatusLock_);
        wmsConnectionStatusMap_[wmsUserId] = isConnected;
    }

    NotifyWMSConnectionChangedToClient(wmsUserId, screenId, isConnected, true, pid, fromUserId, fromPid);
    NotifyWMSConnectionChangedToClient(wmsUserId, screenId, isConnected, false, pid, fromUserId, fromPid);
}

void MockSessionManagerService::NotifyWMSConnectionChangedToClient(int32_t wmsUserId,
    DisplayId screenId, bool isConnected, bool isLite,
    int32_t wmsPid, int32_t fromUserId, int32_t fromPid)
{
    auto sessionManagerService = GetSessionManagerServiceInner(wmsUserId);
    if (!sessionManagerService) {
        TLOGE(WmsLogTag::WMS_RECOVER, "sessionManagerService is null");
        return;
    }

    auto listeners = CollectListenersByClientUserId(SYSTEM_USERID, isLite);
    TLOGI(WmsLogTag::WMS_MULTI_USER,
        "wmsUserId: %{public}d, isLite: %{public}d, isConnected: %{public}d, screenId: %{public}" PRIu64
        " remote count: %{public}zu, fromUserId: %{public}d, fromPid: %{public}d",
        wmsUserId, isLite, isConnected, screenId, listeners.size(), fromUserId, fromPid);
    for (auto& [pid, listener] : listeners) {
        TLOGI(WmsLogTag::WMS_MULTI_USER, "OnWMSConnectionChanged pid: %{public}d, wmsPid: %{public}d", pid, wmsPid);
        listener->OnWMSConnectionChanged(wmsUserId, screenId,
            isConnected, wmsPid, fromUserId, fromPid, sessionManagerService);
    }
}

ErrCode MockSessionManagerService::GetScreenSessionManagerLite(sptr<IRemoteObject>& screenSessionManagerLite)
{
    std::lock_guard<std::mutex> lock(screenSessionManagerMutex_);
    if (screenSessionManager_) {
        screenSessionManagerLite = screenSessionManager_;
        return ERR_OK;
    }
    screenSessionManager_ = ScreenSessionManagerLite::GetInstance().AsObject();
    screenSessionManagerLite = screenSessionManager_;
    return ERR_OK;
}

void MockSessionManagerService::ShowIllegalArgsInfo(std::string& dumpInfo)
{
    dumpInfo.append("The arguments are illegal and you can enter '-h' for help.");
}

sptr<IRemoteObject> MockSessionManagerService::GetSceneSessionManager()
{
    int32_t defaultWMSUserId = GetDefaultWMSUserId();
    TLOGI(WmsLogTag::DEFAULT, "defaultWMSUserId=%{public}d", defaultWMSUserId);
    auto sessionManagerService = GetSessionManagerServiceInner(defaultWMSUserId);
    if (sessionManagerService == nullptr) {
        TLOGE(WmsLogTag::DEFAULT, "Get session mgr service remote failed");
        return nullptr;
    }
    auto sessionManagerServiceProxy = iface_cast<ISessionManagerService>(sessionManagerService);
    if (!sessionManagerServiceProxy) {
        TLOGE(WmsLogTag::DEFAULT, "Get session mgr service proxy failed");
        return nullptr;
    }
    sptr<IRemoteObject> remoteObject = sessionManagerServiceProxy->GetSceneSessionManager();
    if (!remoteObject) {
        TLOGE(WmsLogTag::DEFAULT, "Get scene session mgr remote failed");
        return nullptr;
    }
    UpdateSceneSessionManagerFromCache(defaultWMSUserId, false, remoteObject);
    std::lock_guard<std::mutex> lock(defaultSceneSessionManagerMutex_);
    defaultSceneSessionManager_ = remoteObject;
    return defaultSceneSessionManager_;
}

int MockSessionManagerService::DumpSessionInfo(const std::vector<std::string>& args, std::string& dumpInfo)
{
    if (args.empty()) {
        return -1;  // WMError::WM_ERROR_INVALID_PARAM;
    }
    int32_t defaultWMSUserId = GetDefaultWMSUserId();
    auto sessionManagerService = GetSessionManagerServiceInner(defaultWMSUserId);
    if (sessionManagerService == nullptr) {
        TLOGE(WmsLogTag::DEFAULT, "sessionManagerService is null");
        return -1;
    }
    sptr<IRemoteObject> defaultSSMRemote = GetSceneSessionManager();
    if (!defaultSSMRemote) {
        TLOGE(WmsLogTag::DEFAULT, "Get scene session mgr remote failed");
        return -1;
    }
    auto sceneSessionManagerProxy = iface_cast<ISceneSessionManager>(defaultSSMRemote);
    if (sceneSessionManagerProxy == nullptr) {
        WLOGFW("sessionManagerServiceProxy is nullptr");
        return -1;
    }
    WSError ret = sceneSessionManagerProxy->GetSessionDumpInfo(args, dumpInfo);
    if (ret != WSError::WS_OK) {
        WLOGFD("sessionManagerService set success!");
        return -1;
    }
    return 0; // WMError::WM_OK;
}

void MockSessionManagerService::ShowHelpInfo(std::string& dumpInfo)
{
    dumpInfo.append("Usage:\n")
        .append(" -h                             ")
        .append("|help text for the tool\n")
        .append(" -a                             ")
        .append("|dump all window information in the system\n")
        .append(" -w {window id} [ArkUI Option]  ")
        .append("|dump specified window information\n")
        .append(" ------------------------------------[ArkUI Option]------------------------------------ \n");
    ShowAceDumpHelp(dumpInfo);
}

void MockSessionManagerService::ShowAceDumpHelp(std::string& dumpInfo)
{
}

bool MockSessionManagerService::SMSDeathRecipient::IsSceneBoardTestMode()
{
    if (!OHOS::system::GetBoolParameter(KEY_SCENE_BOARD_TEST_ENABLE, false)) {
        WLOGFD("SceneBoard testmode is disabled.");
        return false;
    }
    auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (systemAbilityMgr == nullptr) {
        WLOGFE("Failed to get SystemAbilityManager.");
        return false;
    }

    auto bmsObj = systemAbilityMgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
    if (bmsObj == nullptr) {
        WLOGFE("Failed to get BundleManagerService.");
        return false;
    }
    sptr<AppExecFwk::IBundleMgr> bundleMgr_ = iface_cast<AppExecFwk::IBundleMgr>(bmsObj);
    AppExecFwk::BundleInfo bundleInfo;
    int uid = IPCSkeleton::GetCallingUid();
    int userId = uid / 200000;
    bool result = bundleMgr_->GetBundleInfo(SCENE_BOARD_BUNDLE_NAME,
        AppExecFwk::BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO, bundleInfo, userId);
    if (!result) {
        WLOGFE("Failed to query bundleInfo, userId:%{public}d", userId);
        return true;
    }
    auto hapModulesList = bundleInfo.hapModuleInfos;
    if (hapModulesList.empty()) {
        WLOGFE("hapModulesList is empty");
        return false;
    }
    std::string suffix = TEST_MODULE_NAME_SUFFIX;
    for (auto hapModule: hapModulesList) {
        std::string moduleName = hapModule.moduleName;
        if (moduleName.length() < suffix.length()) {
            continue;
        }
        if (moduleName.compare(moduleName.length() - suffix.length(), suffix.length(), suffix) == 0) {
            WLOGFI("Found test module name: %{public}s", moduleName.c_str());
            return true;
        }
    }
    return false;
}

void MockSessionManagerService::GetProcessSurfaceNodeIdByPersistentId(const int32_t pid,
    const std::vector<uint64_t>& windowIdList, std::vector<uint64_t>& surfaceNodeIds)
{
    int32_t defaultUserId = GetDefaultWMSUserId();
    auto sessionManagerService = GetSessionManagerServiceInner(defaultUserId);
    if (sessionManagerService == nullptr) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Get session manager remote failed");
        return;
    }
    sptr<IRemoteObject> defaultSSMRemote = GetSceneSessionManager();
    if (!defaultSSMRemote) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Get scene session manager remote failed");
        return;
    }
    if (windowIdList.empty()) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "windowIdList is null, no need to get surfaceNodeId");
        return;
    }
    std::vector<int32_t> persistentIds(windowIdList.size());
    std::transform(windowIdList.begin(), windowIdList.end(),
        persistentIds.begin(), [](uint64_t id) { return static_cast<int32_t>(id); });
    auto sceneSessionManagerProxy = iface_cast<ISceneSessionManager>(defaultSSMRemote);
    if (sceneSessionManagerProxy == nullptr) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Get session mgr proxy failed");
        return;
    }
    WMError ret = sceneSessionManagerProxy->GetProcessSurfaceNodeIdByPersistentId(
        pid, persistentIds, surfaceNodeIds);
    if (ret != WMError::WM_OK) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Get process surfaceNodeId by persistentId failed!");
    }
}

void MockSessionManagerService::AddSkipSelfWhenShowOnVirtualScreenList(
    const std::vector<int32_t>& persistentIds, int32_t userId)
{
    sptr<IRemoteObject> sceneSessionManager = GetSceneSessionManagerByUserId(userId);
    if (!sceneSessionManager) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Get scene session manager failed");
        return;
    }
    sptr<ISceneSessionManager> sceneSessionManagerProxy = iface_cast<ISceneSessionManager>(sceneSessionManager);
    if (sceneSessionManagerProxy == nullptr) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "sessionManagerServiceProxy is nullptr");
        return;
    }
    WMError ret = sceneSessionManagerProxy->AddSkipSelfWhenShowOnVirtualScreenList(persistentIds);
    if (ret != WMError::WM_OK) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "add virtual screen black list failed!");
    }
}

void MockSessionManagerService::RemoveSkipSelfWhenShowOnVirtualScreenList(
    const std::vector<int32_t>& persistentIds, int32_t userId)
{
    sptr<IRemoteObject> sceneSessionManager = GetSceneSessionManagerByUserId(userId);
    if (!sceneSessionManager) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "Get scene session manager failed");
        return;
    }
    sptr<ISceneSessionManager> sceneSessionManagerProxy = iface_cast<ISceneSessionManager>(sceneSessionManager);
    if (sceneSessionManagerProxy == nullptr) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "sessionManagerServiceProxy is nullptr");
        return;
    }
    WMError ret = sceneSessionManagerProxy->RemoveSkipSelfWhenShowOnVirtualScreenList(persistentIds);
    if (ret != WMError::WM_OK) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "remove virtual screen black list failed!");
    }
}

void MockSessionManagerService::SetScreenPrivacyWindowTagSwitch(
    uint64_t screenId, const std::vector<std::string>& privacyWindowTags, bool enable)
{
    if (privacyWindowTags.empty()) {
        TLOGI(WmsLogTag::WMS_ATTRIBUTE, "PrivacyWindowTags is empty");
        return;
    }
    int32_t defaultWMSUserId;
    {
        std::lock_guard<std::mutex> lock(defaultWMSUserIdMutex_);
        defaultWMSUserId = defaultWMSUserId_;
    }
    auto sessionManagerService = GetSessionManagerServiceInner(defaultWMSUserId);
    if (sessionManagerService == nullptr) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "sessionManagerService is nullptr");
        return;
    }
    if (!defaultSceneSessionManager_) {
        GetSceneSessionManager();
        if (!defaultSceneSessionManager_) {
            TLOGW(WmsLogTag::WMS_ATTRIBUTE, "get scene session manager proxy failed, nullptr");
            return;
        }
    }
    sptr<ISceneSessionManager> sceneSessionManagerProxy = iface_cast<ISceneSessionManager>(defaultSceneSessionManager_);
    if (sceneSessionManagerProxy == nullptr) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "sessionManagerServiceProxy is nullptr");
        return;
    }
    WMError ret = sceneSessionManagerProxy->SetScreenPrivacyWindowTagSwitch(screenId, privacyWindowTags, enable);
    if (ret != WMError::WM_OK) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "remove virtual screen black list failed!");
    }
}

sptr<IRemoteObject> MockSessionManagerService::GetSceneSessionManagerByUserId(int32_t userId)
{
    auto sessionManagerService = GetSessionManagerServiceInner(userId);
    if (sessionManagerService == nullptr) {
        WLOGFE("sessionManagerService is nullptr");
        return nullptr;
    }
    sptr<ISessionManagerService> sessionManagerServiceProxy =
        iface_cast<ISessionManagerService>(sessionManagerService);
    if (sessionManagerServiceProxy == nullptr) {
        WLOGFE("sessionManagerServiceProxy is nullptr");
        return nullptr;
    }
    sptr<IRemoteObject> remoteObject = sessionManagerServiceProxy->GetSceneSessionManager();
    if (remoteObject == nullptr) {
        WLOGFW("Get scene session manager proxy failed");
    }
    return remoteObject;
}

ErrCode MockSessionManagerService::GetSceneSessionManagerLiteByClient(int32_t userId,
                                                                      sptr<IRemoteObject>& sceneSessionManagerLite)
{
    ErrCode code = CheckClientIsSystemUser();
    if (code != ERR_OK) {
        return code;
    }
    sceneSessionManagerLite = GetSceneSessionManagerInner(userId, true);
    return ERR_OK;
}

ErrCode MockSessionManagerService::GetSceneSessionManagerByClient(int32_t userId,
                                                                  sptr<IRemoteObject>& sceneSessionManager)
{
    ErrCode code = CheckClientIsSystemUser();
    if (code != ERR_OK) {
        return code;
    }
    sceneSessionManager = GetSceneSessionManagerInner(userId, false);
    return ERR_OK;
}

sptr<ISceneSessionManagerLite> MockSessionManagerService::GetSceneSessionManagerLiteBySA(int32_t userId)
{
    sptr<ISceneSessionManagerLite> result;
    GetSceneSessionManagerByUserIdImpl<ISceneSessionManagerLite>(userId, true, false, result);
    return result;
}

sptr<ISceneSessionManager> MockSessionManagerService::GetSceneSessionManagerBySA(int32_t userId)
{
    sptr<ISceneSessionManager> result;
    GetSceneSessionManagerByUserIdImpl<ISceneSessionManager>(userId, false, false, result);
    return result;
}

template ErrCode MockSessionManagerService::GetSceneSessionManagerByUserIdImpl<ISceneSessionManagerLite>(
    int32_t userId,
    bool isLite,
    bool checkClient,
    sptr<ISceneSessionManagerLite>& result);
template ErrCode MockSessionManagerService::GetSceneSessionManagerByUserIdImpl<ISceneSessionManager>(
    int32_t userId,
    bool isLite,
    bool checkClient,
    sptr<ISceneSessionManager>& result);
template <typename T>
ErrCode MockSessionManagerService::GetSceneSessionManagerByUserIdImpl(int32_t userId,
                                                                      bool isLite,
                                                                      bool checkClient,
                                                                      sptr<T>& result)
{
    TLOGD(WmsLogTag::WMS_MULTI_USER,
          "userId: %{public}d, isLite: %{public}d, checkClient: %{public}d",
          userId,
          isLite,
          checkClient);
    if (checkClient) {
        ErrCode err = CheckClientIsSystemUser();
        if (err != ERR_OK) {
            return err;
        }
    }
    auto sceneSessionManagerProxyObject = GetSceneSessionManagerInner(userId, isLite);
    if (sceneSessionManagerProxyObject == nullptr) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "smsProxy null");
        return ERR_DEAD_OBJECT;
    }
    result = iface_cast<T>(sceneSessionManagerProxyObject);
    if (!result) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "ssmProxy iface_cast null");
        return ERR_DEAD_OBJECT;
    }
    return ERR_OK;
}

sptr<IRemoteObject> MockSessionManagerService::GetSceneSessionManagerInner(int32_t userId, bool isLite)
{
    sptr<IRemoteObject> SSMRemoteObject = GetSceneSessionManagerFromCache(userId, isLite);
    if (SSMRemoteObject != nullptr) {
        return SSMRemoteObject;
    }
    auto sessionManagerService = GetSessionManagerServiceInner(userId);
    if (sessionManagerService == nullptr) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "SMS is nullptr, userId: %{public}d", userId);
        return nullptr;
    }
    sptr<ISessionManagerService> sessionManagerServiceProxy = iface_cast<ISessionManagerService>(sessionManagerService);
    if (sessionManagerServiceProxy == nullptr) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "SMSProxy iface_cast null, userId: %{public}d", userId);
        return nullptr;
    }
    SSMRemoteObject = isLite ? sessionManagerServiceProxy->GetSceneSessionManagerLite()
                             : sessionManagerServiceProxy->GetSceneSessionManager();
    if (SSMRemoteObject == nullptr) {
        TLOGE(WmsLogTag::WMS_MULTI_USER,
              "SSMRemoteObject is null, userId: %{public}d, isLite: %{public}d",
              userId,
              isLite);
        return nullptr;
    }
    UpdateSceneSessionManagerFromCache(userId, isLite, SSMRemoteObject);
    return SSMRemoteObject;
}

sptr<IRemoteObject> MockSessionManagerService::GetSceneSessionManagerFromCache(int32_t userId, bool isLite)
{
    TLOGD(WmsLogTag::WMS_MULTI_USER, "userId: %{public}d, isLite: %{public}d", userId, isLite);
    if (isLite) {
        std::lock_guard<std::mutex> lock(sceneSessionManagerLiteMapMutex_);
        auto iter = sceneSessionManagerLiteMap_.find(userId);
        if (iter != sceneSessionManagerLiteMap_.end()) {
            TLOGD(WmsLogTag::WMS_MULTI_USER, "get success with userId: %{public}d, isLite: %{public}d", userId, isLite);
            return iter->second;
        }
    } else {
        std::lock_guard<std::mutex> lock(sceneSessionManagerMapMutex_);
        auto iter = sceneSessionManagerMap_.find(userId);
        if (iter != sceneSessionManagerMap_.end()) {
            TLOGD(WmsLogTag::WMS_MULTI_USER, "get success with userId: %{public}d, isLite: %{public}d", userId, isLite);
            return iter->second;
        }
    }
    TLOGD(WmsLogTag::WMS_MULTI_USER,
        "GetSceneSessionManagerFromCache miss, userId: %{public}d, isLite: %{public}d", userId, isLite);
    return nullptr;
}

void MockSessionManagerService::UpdateSceneSessionManagerFromCache(int32_t userId,
                                                                   bool isLite,
                                                                   sptr<IRemoteObject>& sceneSessionManager)
{
    if (sceneSessionManager == nullptr) {
        TLOGW(WmsLogTag::WMS_MULTI_USER, "ssm is nullptr userId: %{public}d", userId);
        return;
    }
    TLOGD(WmsLogTag::WMS_MULTI_USER, "update ssm cache, userId: %{public}d, isLite: %{public}d", userId, isLite);
    if (isLite) {
        std::lock_guard<std::mutex> lock(sceneSessionManagerLiteMapMutex_);
        sceneSessionManagerLiteMap_[userId] = sceneSessionManager;
    } else {
        std::lock_guard<std::mutex> lock(sceneSessionManagerMapMutex_);
        sceneSessionManagerMap_[userId] = sceneSessionManager;
    }
}

ErrCode MockSessionManagerService::RecoverSCBSnapshotSkipByUserId(int32_t userId)
{
    std::unique_lock<std::mutex> lock(userIdBundleNamesMapLock_);
    auto iter = userIdBundleNamesMap_.find(userId);
    if (iter == userIdBundleNamesMap_.end()) {
        TLOGW(WmsLogTag::WMS_MULTI_USER,
            "userId %{public}d not found in userIdBundleNamesMap, skip recover", userId);
        return ERR_INVALID_VALUE;
    }
    sptr<IRemoteObject> remoteObject = GetSceneSessionManagerByUserId(userId);
    if (!remoteObject) {
        return ERR_DEAD_OBJECT;
    }
    return NotifySCBSnapshotSkipByUserIdAndBundleNames(userId, iter->second, remoteObject);
}

ErrCode MockSessionManagerService::NotifySCBSnapshotSkipByUserIdAndBundleNames(int32_t userId,
    const std::vector<std::string>& bundleNameList, const sptr<IRemoteObject>& remoteObject)
{
    sptr<ISceneSessionManager> sceneSessionManagerProxy = iface_cast<ISceneSessionManager>(remoteObject);
    WMError ret = sceneSessionManagerProxy->SkipSnapshotByUserIdAndBundleNames(userId, bundleNameList);
    if (ret != WMError::WM_OK) {
        TLOGE(WmsLogTag::WMS_ATTRIBUTE, "failed!");
        return ERR_INVALID_OPERATION;
    }
    return ERR_OK;
}

ErrCode MockSessionManagerService::SetSnapshotSkipByUserIdAndBundleNames(int32_t userId,
    const std::vector<std::string>& bundleNameList)
{
    if (!SceneBoardJudgement::IsSceneBoardEnabled()) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "service not supported!");
        return ERR_WOULD_BLOCK;
    }
    if (!SessionPermission::VerifyCallingPermission("ohos.permission.MANAGE_EDM_POLICY")) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "permission denied!");
        return ERR_PERMISSION_DENIED;
    }
    return SetSnapshotSkipByUserIdAndBundleNamesInner(userId, bundleNameList);
}

ErrCode MockSessionManagerService::SetSnapshotSkipByUserIdAndBundleNamesInner(int32_t userId,
    const std::vector<std::string>& bundleNameList)
{
    {
        std::unique_lock<std::mutex> lock(userIdBundleNamesMapLock_);
        userIdBundleNamesMap_[userId] = bundleNameList;
    }
    sptr<IRemoteObject> remoteObject = GetSceneSessionManagerByUserId(userId);
    if (!remoteObject) {
        TLOGW(WmsLogTag::WMS_MULTI_USER, "user:%{public}d isn't active.", userId);
        return ERR_OK;
    }
    return NotifySCBSnapshotSkipByUserIdAndBundleNames(userId, bundleNameList, remoteObject);
}

ErrCode MockSessionManagerService::SetSnapshotSkipByIdNamesMap(
    const std::unordered_map<int32_t, std::vector<std::string>>& userIdAndBunldeNames)
{
    if (!SceneBoardJudgement::IsSceneBoardEnabled()) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "service not supported!");
        return ERR_WOULD_BLOCK;
    }
    if (!SessionPermission::VerifyCallingPermission("ohos.permission.MANAGE_EDM_POLICY")) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "permission denied");
        return ERR_PERMISSION_DENIED;
    }
    return SetSnapshotSkipByIdNamesMapInner(userIdAndBunldeNames);
}

ErrCode MockSessionManagerService::SetSnapshotSkipByIdNamesMapInner(
    const std::unordered_map<int32_t, std::vector<std::string>>& userIdAndBunldeNames)
{
    std::unique_lock<std::mutex> lock(userIdBundleNamesMapLock_);
    userIdBundleNamesMap_ = userIdAndBunldeNames;
    TLOGI(WmsLogTag::WMS_MULTI_USER,
        "SetSnapshotSkipByIdNamesMapInner, total userIds: %{public}zu", userIdBundleNamesMap_.size());
    for (const auto& [userId, bundleNameList] : userIdBundleNamesMap_) {
        sptr<IRemoteObject> remoteObject = GetSceneSessionManagerByUserId(userId);
        if (!remoteObject) {
            TLOGW(WmsLogTag::WMS_MULTI_USER, "user:%{public}d isn't active", userId);
            continue;
        }
        ErrCode err = NotifySCBSnapshotSkipByUserIdAndBundleNames(userId, bundleNameList, remoteObject);
        if (err != ERR_OK) {
            TLOGE(WmsLogTag::DEFAULT, "failed");
            return err;
        }
    }
    return ERR_OK;
}

ErrCode MockSessionManagerService::NotifyWMSConnectionStatus(int32_t userId,
    const sptr<ISessionManagerServiceRecoverListener>& smsListener)
{
    bool isWMSConnected = false;
    {
        std::lock_guard<std::mutex> lock(wmsConnectionStatusLock_);
        if (wmsConnectionStatusMap_.find(userId) != wmsConnectionStatusMap_.end()) {
            isWMSConnected = wmsConnectionStatusMap_[userId];
        }
    }
    if (smsListener && isWMSConnected) {
        auto sessionManagerService = GetSessionManagerServiceInner(userId);
        if (sessionManagerService == nullptr) {
            TLOGE(WmsLogTag::WMS_RECOVER, "SessionManagerService is null");
            return ERR_DEAD_OBJECT;
        }
        TLOGI(WmsLogTag::WMS_MULTI_USER, "wms is already connected, notify client");
        DisplayId screenId = DEFAULT_SCREEN_ID;
        {
            std::lock_guard<std::mutex> lock(userId2ScreenIdMutex_);
            screenId = userId2ScreenId_[userId];
        }
        int32_t wmsPid = GetWmsPidByUserId(userId);
        TLOGI(WmsLogTag::WMS_MULTI_USER,
            "OnWMSConnectionChanged userId: %{public}d, wmsPid: %{public}d", userId, wmsPid);
        smsListener->OnWMSConnectionChanged(userId, screenId, true,
            wmsPid, INVALID_USER_ID, INVALID_PID, sessionManagerService);
    }
    return ERR_OK;
}

int32_t MockSessionManagerService::GetUserIdByCallingUid()
{
    int32_t uid = IPCSkeleton::GetCallingUid();
    if (uid <= INVALID_UID) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "uid is illegal: %{public}d", uid);
        return INVALID_USER_ID;
    }
    return GetUserIdByUid(uid);
}

ErrCode MockSessionManagerService::CheckClientIsSystemUser()
{
    int32_t clientUserId = GetUserIdByCallingUid();
    if (clientUserId <= INVALID_USER_ID) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "userId is illegal: %{public}d", clientUserId);
        return ERR_INVALID_VALUE;
    }
    if (clientUserId != SYSTEM_USERID) {
        TLOGE(WmsLogTag::WMS_MULTI_USER, "clientUserId is not system user id: %{public}d", clientUserId);
        return ERR_WOULD_BLOCK;
    }
    return ERR_OK;
}

void MockSessionManagerService::AddSMSRecoverListener(
    int32_t clientUserId, int32_t pid, int32_t instanceUserId, bool isLite,
    const sptr<ISessionManagerServiceRecoverListener>& smsListener)
{
    auto& recoverListenerMap = isLite ? liteRecoverListenerMap_ : recoverListenerMap_;
    auto& mutex = isLite ? liteRecoverListenerMutex_ : recoverListenerMutex_;
    
    {
        std::lock_guard<std::mutex> lock(mutex);
        recoverListenerMap[clientUserId][pid][instanceUserId] = smsListener;
    }
    TLOGI(WmsLogTag::WMS_RECOVER,
        "AddSMSRecoverListener success, clientUserId: %{public}d, pid: %{public}d, "
        "instanceUserId: %{public}d, isLite: %{public}d",
        clientUserId, pid, instanceUserId, isLite);
}

void MockSessionManagerService::UpdateUserId2PidMapping(int32_t userId, int32_t pid)
{
    std::lock_guard<std::mutex> lock(userId2PidMapMutex_);
    userId2PidMap_[userId] = pid;
    TLOGD(WmsLogTag::WMS_MULTI_USER, "Update userId2PidMap: userId=%{public}d, pid=%{public}d", userId, pid);
}

int32_t MockSessionManagerService::GetWmsPidByUserId(int32_t userId)
{
    std::lock_guard<std::mutex> lock(userId2PidMapMutex_);
    auto iter = userId2PidMap_.find(userId);
    return (iter != userId2PidMap_.end()) ? iter->second : INVALID_PID;
}

void MockSessionManagerService::RemoveUserId2PidMapping(int32_t userId)
{
    std::lock_guard<std::mutex> lock(userId2PidMapMutex_);
    auto iter = userId2PidMap_.find(userId);
    if (iter != userId2PidMap_.end()) {
        TLOGI(WmsLogTag::WMS_MULTI_USER, "Clean userId2PidMap for userId=%{public}d, pid=%{public}d",
              userId, iter->second);
        userId2PidMap_.erase(iter);
    }
}

int32_t MockSessionManagerService::GetDefaultWMSUserId()
{
    std::lock_guard<std::mutex> lock(defaultWMSUserIdMutex_);
    return defaultWMSUserId_;
}

void MockSessionManagerService::RemoveSMSRecoverListener(int32_t clientUserId,
                                                         int32_t pid,
                                                         int32_t instanceUserId,
                                                         bool isLite)
{
    auto& recoverListenerMap = isLite ? liteRecoverListenerMap_ : recoverListenerMap_;
    std::lock_guard<std::mutex> lock(isLite ? liteRecoverListenerMutex_ : recoverListenerMutex_);

    auto clientIter = recoverListenerMap.find(clientUserId);
    if (clientIter == recoverListenerMap.end()) {
        TLOGW(WmsLogTag::WMS_RECOVER,
            "RemoveSMSRecoverListener: clientUserId %{public}d not found", clientUserId);
        return;
    }

    auto& pidMap = clientIter->second;
    auto pidIter = pidMap.find(pid);
    if (pidIter == pidMap.end()) {
        TLOGW(WmsLogTag::WMS_RECOVER,
            "RemoveSMSRecoverListener: pid %{public}d not found for clientUserId %{public}d",
            pid, clientUserId);
        return;
    }

    auto& instanceMap = pidIter->second;
    instanceMap.erase(instanceUserId);

    if (instanceMap.empty()) {
        pidMap.erase(pidIter);
    }
    if (pidMap.empty()) {
        recoverListenerMap.erase(clientIter);
    }

    TLOGI(WmsLogTag::WMS_RECOVER,
          "RemoveSMSRecoverListener success, clientUserId: %{public}d, pid: %{public}d, "
          "instanceUserId: %{public}d, isLite: %{public}d",
          clientUserId, pid, instanceUserId, isLite);
}

RecoverListenerPairs MockSessionManagerService::CollectListenersByClientUserId(int32_t clientUserId, bool isLite)
{
    RecoverListenerPairs listeners;
    auto& recoverListenerMap = isLite ? liteRecoverListenerMap_ : recoverListenerMap_;

    std::lock_guard<std::mutex> lock(isLite ? liteRecoverListenerMutex_ : recoverListenerMutex_);
    auto clientIter = recoverListenerMap.find(clientUserId);
    if (clientIter == recoverListenerMap.end()) {
        return listeners;
    }

    for (const auto& [pid, instanceMap] : clientIter->second) {
        for (const auto& [instanceUserId, listener] : instanceMap) {
            if (listener) {
                TLOGD(WmsLogTag::WMS_RECOVER,
                    "CollectListenersByClientUserId: found listener, pid: %{public}d, instanceUserId: %{public}d",
                    pid, instanceUserId);
                listeners.push_back({ pid, listener });
            }
        }
    }
    TLOGI(WmsLogTag::WMS_RECOVER,
        "CollectListenersByClientUserId end, clientUserId: %{public}d, isLite: %{public}d, "
        "collected listeners: %{public}zu", clientUserId, isLite, listeners.size());
    return listeners;
}

RecoverListenerPairs MockSessionManagerService::CollectListenersByInstanceUserId(int32_t clientUserId,
                                                                                 int32_t instanceUserId,
                                                                                 bool isLite)
{
    RecoverListenerPairs listeners;
    auto& recoverListenerMap = isLite ? liteRecoverListenerMap_ : recoverListenerMap_;

    std::lock_guard<std::mutex> lock(isLite ? liteRecoverListenerMutex_ : recoverListenerMutex_);
    auto clientIter = recoverListenerMap.find(clientUserId);
    if (clientIter == recoverListenerMap.end()) {
        return listeners;
    }

    for (const auto& [pid, instanceMap] : clientIter->second) {
        auto instanceIter = instanceMap.find(instanceUserId);
        if (instanceIter != instanceMap.end() && instanceIter->second) {
            TLOGD(WmsLogTag::WMS_RECOVER,
                "CollectListenersByInstanceUserId: found listener, pid: %{public}d, instanceUserId: %{public}d",
                pid, instanceUserId);
            listeners.push_back({ pid, instanceIter->second });
        }
    }
    TLOGI(WmsLogTag::WMS_RECOVER,
        "CollectListenersByInstanceUserId end, clientUserId: %{public}d, "
        "instanceUserId: %{public}d, isLite: %{public}d, collected listeners: %{public}zu",
        clientUserId, instanceUserId, isLite, listeners.size());
    return listeners;
}

bool MockSessionManagerService::AddClientDeathRecipient(const sptr<IRemoteObject>& listener,
                                                        int32_t clientUserId,
                                                        int32_t instanceUserId,
                                                        int32_t pid,
                                                        bool isLite)
{
    auto clientDeathListener = sptr<ClientListenerDeathRecipient>::MakeSptr(clientUserId, instanceUserId, pid, isLite);
    if (listener->IsProxyObject() && !listener->AddDeathRecipient(clientDeathListener)) {
        TLOGE(WmsLogTag::WMS_RECOVER, "failed to add death recipient");
        return false;
    }
    TLOGI(WmsLogTag::WMS_RECOVER,
          "AddClientDeathRecipient success, clientUserId: %{public}d, pid: %{public}d, instanceUserId: %{public}d, "
          "isLite: %{public}d", clientUserId, pid, instanceUserId, isLite);
    return true;
}

ErrCode MockSessionManagerService::GetActiveUserIds(std::vector<int32_t>& activeUserIds)
{
    activeUserIds.clear();
    {
        std::lock_guard<std::mutex> lock(screenId2UserIdMutex_);
        for (const auto& [screenId, uid] : screenId2UserId_) {
            if (uid > INVALID_USER_ID) {
                activeUserIds.push_back(uid);
            }
        }
    }
    TLOGD(WmsLogTag::WMS_MULTI_USER,
        "GetActiveUserIds returns %{public}zu active users",
        activeUserIds.size());
    return ERR_OK;
}

void MockSessionManagerService::UpdateScreenUserInfo(int32_t userId, DisplayId screenId)
{
    TLOGD(WmsLogTag::WMS_MULTI_USER, "UpdateScreenUserInfo userId: %{public}d, screenId: %{public}" PRIu64,
        userId, screenId);
    {
        std::lock_guard<std::mutex> lock(screenId2UserIdMutex_);
        screenId2UserId_[screenId] = userId;
        TLOGD(WmsLogTag::WMS_MULTI_USER,
            "screenId2UserId_ updated: screenId=%{public}" PRIu64 " -> userId=%{public}d", screenId, userId);
    }
    {
        std::lock_guard<std::mutex> lock(userId2ScreenIdMutex_);
        userId2ScreenId_[userId] = screenId;
        TLOGD(WmsLogTag::WMS_MULTI_USER,
            "userId2ScreenId_ updated: userId=%{public}d -> screenId=%{public}" PRIu64, userId, screenId);
    }
}

int32_t MockSessionManagerService::GetUserIdOnScreen(DisplayId screenId, int32_t userId)
{
    int32_t prevUserId = INVALID_USER_ID;
    {
        std::lock_guard<std::mutex> lock(screenId2UserIdMutex_);
        auto iter = screenId2UserId_.find(screenId);
        if (iter != screenId2UserId_.end() && iter->second != userId) {
            prevUserId = iter->second;
        }
        TLOGD(WmsLogTag::WMS_MULTI_USER,
            "GetUserIdOnScreen: screenId=%{public}" PRIu64 ", userId=%{public}d, prevUserId=%{public}d",
            screenId, userId, prevUserId);
    }
    return prevUserId;
}

void MockSessionManagerService::RemoveScreenUserMappingIfMatched(DisplayId screenId, int32_t userId)
{
    std::lock_guard<std::mutex> lock(screenId2UserIdMutex_);
    auto iter = screenId2UserId_.find(screenId);
    if (iter != screenId2UserId_.end() && iter->second == userId) {
        screenId2UserId_.erase(iter);
        TLOGI(WmsLogTag::WMS_MULTI_USER,
            "screenId2UserId_ erased: screenId=%{public}" PRIu64 " (userId=%{public}d matched)",
            screenId, userId);
    }
}

} // namespace Rosen
} // namespace OHOS