/* * Copyright (c) 2021-2022 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 "screen_manager.h" #include #include #include #include "display_manager_adapter.h" #include "display_manager_agent_default.h" #include "permission.h" #include "singleton_delegator.h" #include "window_manager_hilog.h" namespace OHOS::Rosen { namespace { constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "ScreenManager"}; const static uint32_t MAX_SCREEN_SIZE = 32; } class ScreenManager::Impl : public RefBase { public: Impl() = default; ~Impl(); static inline SingletonDelegator delegator; ScreenId CreateVirtualScreen(VirtualScreenOption option); sptr GetScreen(ScreenId screenId); sptr GetScreenGroup(ScreenId screenId); DMError GetAllScreens(std::vector>& screens); DMError RegisterScreenListener(sptr listener); DMError UnregisterScreenListener(sptr listener); DMError RegisterScreenGroupListener(sptr listener); DMError UnregisterScreenGroupListener(sptr listener); DMError RegisterVirtualScreenGroupListener(sptr listener); DMError UnregisterVirtualScreenGroupListener(sptr listener); DMError RegisterDisplayManagerAgent(); DMError UnregisterDisplayManagerAgent(); void OnRemoteDied(); private: void NotifyScreenConnect(sptr info); void NotifyScreenDisconnect(ScreenId); void NotifyScreenChange(const sptr& screenInfo); void NotifyScreenChange(const std::vector>& screenInfos); bool UpdateScreenInfoLocked(sptr); bool isAllListenersRemoved() const; class ScreenManagerListener; sptr screenManagerListener_; std::map> screenMap_; std::map> screenGroupMap_; std::recursive_mutex mutex_; std::set> screenListeners_; std::set> screenGroupListeners_; std::set> virtualScreenGroupListeners_; sptr virtualScreenAgent_ = nullptr; }; class ScreenManager::Impl::ScreenManagerListener : public DisplayManagerAgentDefault { public: explicit ScreenManagerListener(sptr impl) : pImpl_(impl) { } void OnScreenConnect(sptr screenInfo) { if (screenInfo == nullptr || screenInfo->GetScreenId() == SCREEN_ID_INVALID) { WLOGFE("OnScreenConnect, screenInfo is invalid."); return; } if (pImpl_ == nullptr) { WLOGFE("OnScreenConnect, impl is nullptr."); return; } pImpl_->NotifyScreenConnect(screenInfo); std::lock_guard lock(pImpl_->mutex_); for (auto listener : pImpl_->screenListeners_) { listener->OnConnect(screenInfo->GetScreenId()); } }; void OnScreenDisconnect(ScreenId screenId) { if (screenId == SCREEN_ID_INVALID) { WLOGFE("OnScreenDisconnect, screenId is invalid."); return; } if (pImpl_ == nullptr) { WLOGFE("OnScreenDisconnect, impl is nullptr."); return; } pImpl_->NotifyScreenDisconnect(screenId); std::lock_guard lock(pImpl_->mutex_); for (auto listener : pImpl_->screenListeners_) { listener->OnDisconnect(screenId); } }; void OnScreenChange(const sptr& screenInfo, ScreenChangeEvent event) { if (screenInfo == nullptr) { WLOGFE("OnScreenChange, screenInfo is null."); return; } if (pImpl_ == nullptr) { WLOGFE("OnScreenChange, impl is nullptr."); return; } WLOGFD("OnScreenChange. event %{public}u", event); pImpl_->NotifyScreenChange(screenInfo); std::lock_guard lock(pImpl_->mutex_); for (auto listener: pImpl_->screenListeners_) { listener->OnChange(screenInfo->GetScreenId()); } }; void OnScreenGroupChange(const std::string& trigger, const std::vector>& screenInfos, ScreenGroupChangeEvent groupEvent) { if (screenInfos.empty()) { WLOGFE("screenInfos is empty."); return; } if (pImpl_ == nullptr) { WLOGFE("impl is nullptr."); return; } WLOGFD("trigger %{public}s, event %{public}u", trigger.c_str(), groupEvent); pImpl_->NotifyScreenChange(screenInfos); std::vector screenIds; for (auto screenInfo : screenInfos) { if (screenInfo->GetScreenId() != SCREEN_ID_INVALID) { screenIds.push_back(screenInfo->GetScreenId()); } } std::lock_guard lock(pImpl_->mutex_); for (auto listener: pImpl_->screenGroupListeners_) { listener->OnChange(screenIds, groupEvent); } NotifyVirtualScreenGroupChanged(screenInfos[0], trigger, screenIds, groupEvent); }; private: void NotifyVirtualScreenGroupChanged(sptr screenInfo, const std::string trigger, std::vector& ids, ScreenGroupChangeEvent groupEvent) { // check for invalid scene if (pImpl_->virtualScreenGroupListeners_.size() <= 0) { WLOGFW("no virtual screnn group listeners"); return; } if (screenInfo->GetType() != ScreenType::VIRTUAL) { WLOGFW("not virtual screen type: %{public}u", screenInfo->GetType()); return; } // get the parent of screen ScreenId parent = groupEvent == ScreenGroupChangeEvent::ADD_TO_GROUP ? screenInfo->GetParentId() : screenInfo->GetLastParentId(); WLOGFD("parentId=[%{public}llu], lastParentId=[%{public}llu]", (unsigned long long)screenInfo->GetParentId(), (unsigned long long)screenInfo->GetLastParentId()); if (parent == INVALID_SCREEN_ID) { WLOGFE("parentId is invalid"); return; } auto screenGroup = pImpl_->GetScreenGroup(parent); if (screenGroup == nullptr) { WLOGFE("screenGroup is null"); return; } // notify mirror ScreenCombination comb = screenGroup->GetCombination(); WLOGFD("comb %{public}u", comb); IVirtualScreenGroupListener::ChangeInfo changeInfo = {groupEvent, trigger, ids}; for (auto listener: pImpl_->virtualScreenGroupListeners_) { if (comb == ScreenCombination::SCREEN_MIRROR) { listener->OnMirrorChange(changeInfo); } } } sptr pImpl_; }; WM_IMPLEMENT_SINGLE_INSTANCE(ScreenManager) ScreenManager::ScreenManager() { pImpl_ = new Impl(); } ScreenManager::~ScreenManager() { } ScreenManager::Impl::~Impl() { std::lock_guard lock(mutex_); UnregisterDisplayManagerAgent(); } sptr ScreenManager::Impl::GetScreen(ScreenId screenId) { auto screenInfo = SingletonContainer::Get().GetScreenInfo(screenId); std::lock_guard lock(mutex_); if (!UpdateScreenInfoLocked(screenInfo)) { screenMap_.erase(screenId); return nullptr; } return screenMap_[screenId]; } sptr ScreenManager::GetScreenById(ScreenId screenId) { return pImpl_->GetScreen(screenId); } sptr ScreenManager::Impl::GetScreenGroup(ScreenId screenId) { auto screenGroupInfo = SingletonContainer::Get().GetScreenGroupInfoById(screenId); std::lock_guard lock(mutex_); if (screenGroupInfo == nullptr) { WLOGFE("screenGroupInfo is null"); screenGroupMap_.erase(screenId); return nullptr; } auto iter = screenGroupMap_.find(screenId); if (iter != screenGroupMap_.end() && iter->second != nullptr) { iter->second->UpdateScreenGroupInfo(screenGroupInfo); return iter->second; } sptr screenGroup = new ScreenGroup(screenGroupInfo); screenGroupMap_[screenId] = screenGroup; return screenGroup; } sptr ScreenManager::GetScreenGroup(ScreenId screenId) { return pImpl_->GetScreenGroup(screenId); } DMError ScreenManager::Impl::GetAllScreens(std::vector>& screens) { std::vector> screenInfos; DMError ret = SingletonContainer::Get().GetAllScreenInfos(screenInfos); std::lock_guard lock(mutex_); for (auto info: screenInfos) { if (UpdateScreenInfoLocked(info)) { screens.emplace_back(screenMap_[info->GetScreenId()]); } } screenMap_.clear(); for (auto screen: screens) { screenMap_.insert(std::make_pair(screen->GetId(), screen)); } return ret; } DMError ScreenManager::GetAllScreens(std::vector>& screens) { return pImpl_->GetAllScreens(screens); } DMError ScreenManager::Impl::RegisterScreenListener(sptr listener) { std::lock_guard lock(mutex_); DMError regSucc = RegisterDisplayManagerAgent(); if (regSucc == DMError::DM_OK) { screenListeners_.insert(listener); } return regSucc; } DMError ScreenManager::RegisterScreenListener(sptr listener) { if (listener == nullptr) { WLOGFE("RegisterScreenListener listener is nullptr."); return DMError::DM_ERROR_NULLPTR; } return pImpl_->RegisterScreenListener(listener); } DMError ScreenManager::Impl::UnregisterScreenListener(sptr listener) { std::lock_guard lock(mutex_); if (!Permission::IsSystemCalling() && !Permission::IsStartByHdcd()) { WLOGFE("unregister display manager agent permission denied!"); return DMError::DM_ERROR_NOT_SYSTEM_APP; } auto iter = std::find(screenListeners_.begin(), screenListeners_.end(), listener); if (iter == screenListeners_.end()) { WLOGFE("could not find this listener"); return DMError::DM_ERROR_NULLPTR; } screenListeners_.erase(iter); return isAllListenersRemoved() ? UnregisterDisplayManagerAgent() : DMError::DM_OK; } DMError ScreenManager::UnregisterScreenListener(sptr listener) { if (listener == nullptr) { WLOGFE("UnregisterScreenListener listener is nullptr."); return DMError::DM_ERROR_NULLPTR; } return pImpl_->UnregisterScreenListener(listener); } DMError ScreenManager::Impl::RegisterScreenGroupListener(sptr listener) { std::lock_guard lock(mutex_); DMError regSucc = RegisterDisplayManagerAgent(); if (regSucc == DMError::DM_OK) { screenGroupListeners_.insert(listener); } return regSucc; } DMError ScreenManager::RegisterScreenGroupListener(sptr listener) { if (listener == nullptr) { WLOGFE("RegisterScreenGroupListener listener is nullptr."); return DMError::DM_ERROR_NULLPTR; } return pImpl_->RegisterScreenGroupListener(listener); } DMError ScreenManager::Impl::UnregisterScreenGroupListener(sptr listener) { std::lock_guard lock(mutex_); auto iter = std::find(screenGroupListeners_.begin(), screenGroupListeners_.end(), listener); if (iter == screenGroupListeners_.end()) { WLOGFE("could not find this listener"); return DMError::DM_ERROR_NULLPTR; } screenGroupListeners_.erase(iter); return isAllListenersRemoved() ? UnregisterDisplayManagerAgent() : DMError::DM_OK; } DMError ScreenManager::UnregisterScreenGroupListener(sptr listener) { if (listener == nullptr) { WLOGFE("UnregisterScreenGroupListener listener is nullptr."); return DMError::DM_ERROR_NULLPTR; } return pImpl_->UnregisterScreenGroupListener(listener); } DMError ScreenManager::Impl::RegisterVirtualScreenGroupListener(sptr listener) { std::lock_guard lock(mutex_); DMError regSucc = RegisterDisplayManagerAgent(); if (regSucc == DMError::DM_OK) { virtualScreenGroupListeners_.insert(listener); } return regSucc; } DMError ScreenManager::RegisterVirtualScreenGroupListener(sptr listener) { if (listener == nullptr) { WLOGFE("RegisterVirtualScreenGroupListener listener is nullptr."); return DMError::DM_ERROR_NULLPTR; } return pImpl_->RegisterVirtualScreenGroupListener(listener); } DMError ScreenManager::Impl::UnregisterVirtualScreenGroupListener(sptr listener) { std::lock_guard lock(mutex_); auto iter = std::find(virtualScreenGroupListeners_.begin(), virtualScreenGroupListeners_.end(), listener); if (iter == virtualScreenGroupListeners_.end()) { WLOGFE("could not find this listener"); return DMError::DM_ERROR_NULLPTR; } virtualScreenGroupListeners_.erase(iter); return isAllListenersRemoved() ? UnregisterDisplayManagerAgent() : DMError::DM_OK; } DMError ScreenManager::UnregisterVirtualScreenGroupListener(sptr listener) { if (listener == nullptr) { WLOGFE("UnregisterVirtualScreenGroupListener listener is nullptr."); return DMError::DM_ERROR_NULLPTR; } return pImpl_->UnregisterVirtualScreenGroupListener(listener); } DMError ScreenManager::Impl::RegisterDisplayManagerAgent() { DMError regSucc = DMError::DM_OK; if (screenManagerListener_ == nullptr) { screenManagerListener_ = new ScreenManagerListener(this); regSucc = SingletonContainer::Get().RegisterDisplayManagerAgent( screenManagerListener_, DisplayManagerAgentType::SCREEN_EVENT_LISTENER); if (regSucc != DMError::DM_OK) { screenManagerListener_ = nullptr; WLOGFW("RegisterDisplayManagerAgent failed !"); } } return regSucc; } DMError ScreenManager::Impl::UnregisterDisplayManagerAgent() { DMError unRegSucc = DMError::DM_OK; if (screenManagerListener_ != nullptr) { unRegSucc = SingletonContainer::Get().UnregisterDisplayManagerAgent( screenManagerListener_, DisplayManagerAgentType::SCREEN_EVENT_LISTENER); screenManagerListener_ = nullptr; if (unRegSucc != DMError::DM_OK) { WLOGFW("UnregisterDisplayManagerAgent failed!"); } } return unRegSucc; } DMError ScreenManager::MakeExpand(const std::vector& options, ScreenId& screenGroupId) { WLOGFI("Make expand"); if (options.empty()) { return DMError::DM_ERROR_INVALID_PARAM; } if (options.size() > MAX_SCREEN_SIZE) { WLOGFW("Make expand failed. The options size is bigger than %{public}u.", MAX_SCREEN_SIZE); return DMError::DM_ERROR_INVALID_PARAM; } std::vector screenIds; std::vector startPoints; for (auto& option: options) { if (std::find(screenIds.begin(), screenIds.end(), option.screenId_) != screenIds.end()) { continue; } screenIds.emplace_back(option.screenId_); startPoints.emplace_back(Point(option.startX_, option.startY_)); } DMError ret = SingletonContainer::Get().MakeExpand(screenIds, startPoints, screenGroupId); if (screenGroupId == SCREEN_ID_INVALID) { WLOGFI("Make expand failed"); } return ret; } DMError ScreenManager::MakeMirror(ScreenId mainScreenId, std::vector mirrorScreenId, ScreenId& screenGroupId) { WLOGFI("Make mirror for screen: %{public}" PRIu64"", mainScreenId); if (mirrorScreenId.size() > MAX_SCREEN_SIZE) { WLOGFW("Make Mirror failed. The mirrorScreenId size is bigger than %{public}u.", MAX_SCREEN_SIZE); return DMError::DM_ERROR_INVALID_PARAM; } DMError ret = SingletonContainer::Get().MakeMirror(mainScreenId, mirrorScreenId, screenGroupId); if (screenGroupId == SCREEN_ID_INVALID) { WLOGFI("create mirror failed"); } return ret; } DMError ScreenManager::StopExpand(const std::vector& expandScreenIds) { WLOGFI("Stop expand"); if (expandScreenIds.empty()) { return DMError::DM_OK; } return SingletonContainer::Get().StopExpand(expandScreenIds); } DMError ScreenManager::StopMirror(const std::vector& mirrorScreenIds) { WLOGFI("Stop mirror"); if (mirrorScreenIds.empty()) { return DMError::DM_OK; } return SingletonContainer::Get().StopMirror(mirrorScreenIds); } DMError ScreenManager::RemoveVirtualScreenFromGroup(std::vector screens) { WLOGFI("screens.size=%{public}llu", (unsigned long long)screens.size()); if (screens.empty()) { WLOGFW("RemoveVirtualScreenFromGroup failed. screens is empty."); return DMError::DM_ERROR_INVALID_PARAM; } if (screens.size() > MAX_SCREEN_SIZE) { WLOGFW("RemoveVirtualScreenFromGroup failed. The screens size is bigger than %{public}u.", MAX_SCREEN_SIZE); return DMError::DM_ERROR_INVALID_PARAM; } SingletonContainer::Get().RemoveVirtualScreenFromGroup(screens); return DMError::DM_OK; } ScreenId ScreenManager::CreateVirtualScreen(VirtualScreenOption option) { return pImpl_->CreateVirtualScreen(option); } ScreenId ScreenManager::Impl::CreateVirtualScreen(VirtualScreenOption option) { // After the process creating the virtual screen is killed, DMS needs to delete the virtual screen if (virtualScreenAgent_ == nullptr) { virtualScreenAgent_ = new DisplayManagerAgentDefault(); } return SingletonContainer::Get().CreateVirtualScreen(option, virtualScreenAgent_); } DMError ScreenManager::DestroyVirtualScreen(ScreenId screenId) { return SingletonContainer::Get().DestroyVirtualScreen(screenId); } DMError ScreenManager::SetVirtualScreenSurface(ScreenId screenId, sptr surface) { return SingletonContainer::Get().SetVirtualScreenSurface(screenId, surface); } bool ScreenManager::SetScreenPowerForAll(ScreenPowerState state, PowerStateChangeReason reason) { WLOGFI("state:%{public}u, reason:%{public}u", state, reason); return SingletonContainer::Get().SetScreenPowerForAll(state, reason); } ScreenPowerState ScreenManager::GetScreenPower(ScreenId dmsScreenId) { return SingletonContainer::Get().GetScreenPower(dmsScreenId); } DMError ScreenManager::SetScreenRotationLocked(bool isLocked) { return SingletonContainer::Get().SetScreenRotationLocked(isLocked); } DMError ScreenManager::IsScreenRotationLocked(bool& isLocked) { return SingletonContainer::Get().IsScreenRotationLocked(isLocked); } void ScreenManager::Impl::NotifyScreenConnect(sptr info) { std::lock_guard lock(mutex_); UpdateScreenInfoLocked(info); } void ScreenManager::Impl::NotifyScreenDisconnect(ScreenId screenId) { WLOGFI("screenId:%{public}" PRIu64".", screenId); std::lock_guard lock(mutex_); screenMap_.erase(screenId); } void ScreenManager::Impl::NotifyScreenChange(const sptr& screenInfo) { std::lock_guard lock(mutex_); UpdateScreenInfoLocked(screenInfo); } void ScreenManager::Impl::NotifyScreenChange(const std::vector>& screenInfos) { std::lock_guard lock(mutex_); for (auto screenInfo : screenInfos) { UpdateScreenInfoLocked(screenInfo); } } bool ScreenManager::Impl::UpdateScreenInfoLocked(sptr screenInfo) { if (screenInfo == nullptr) { WLOGFE("displayInfo is null"); return false; } ScreenId screenId = screenInfo->GetScreenId(); WLOGFI("screenId:%{public}" PRIu64".", screenId); if (screenId == SCREEN_ID_INVALID) { WLOGFE("displayId is invalid."); return false; } auto iter = screenMap_.find(screenId); if (iter != screenMap_.end() && iter->second != nullptr) { WLOGFI("get screen in screen map"); iter->second->UpdateScreenInfo(screenInfo); return true; } sptr screen = new Screen(screenInfo); screenMap_[screenId] = screen; return true; } bool ScreenManager::Impl::isAllListenersRemoved() const { return screenListeners_.empty() && screenGroupListeners_.empty() && virtualScreenGroupListeners_.empty(); } void ScreenManager::Impl::OnRemoteDied() { WLOGFI("dms is died"); std::lock_guard lock(mutex_); screenManagerListener_ = nullptr; virtualScreenAgent_ = nullptr; } void ScreenManager::OnRemoteDied() { pImpl_->OnRemoteDied(); } } // namespace OHOS::Rosen