1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "abstract_screen_controller.h"
17
18#include <sstream>
19
20#include <cinttypes>
21#include <hitrace_meter.h>
22#include <parameters.h>
23#include <screen_manager/rs_screen_mode_info.h>
24#include <screen_manager/screen_types.h>
25#include <surface.h>
26#include <thread>
27
28#include "sys_cap_util.h"
29#include "display_manager_agent_controller.h"
30#include "display_manager_service.h"
31#include "event_runner.h"
32#include "screen_rotation_controller.h"
33#include "window_manager_hilog.h"
34
35#ifdef SOC_PERF_ENABLE
36#include "socperf_client.h"
37#endif
38
39namespace OHOS::Rosen {
40namespace {
41constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "AbstractScreenController"};
42const std::string CONTROLLER_THREAD_ID = "AbstractScreenControllerThread";
43const static uint32_t MAX_RETRY_NUM = 3;
44const static uint32_t RETRY_WAIT_MS = 100;
45}
46
47AbstractScreenController::AbstractScreenController(std::recursive_mutex& mutex)
48    : mutex_(mutex), rsInterface_(RSInterfaces::GetInstance())
49{
50    auto runner = AppExecFwk::EventRunner::Create(CONTROLLER_THREAD_ID);
51    controllerHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
52}
53
54AbstractScreenController::~AbstractScreenController() = default;
55
56void AbstractScreenController::Init()
57{
58    WLOGFI("screen controller init");
59    RegisterRsScreenConnectionChangeListener();
60}
61
62void AbstractScreenController::RegisterRsScreenConnectionChangeListener()
63{
64    WLOGFI("RegisterRsScreenConnectionChangeListener");
65    auto res = rsInterface_.SetScreenChangeCallback(
66        [this](ScreenId rsScreenId, ScreenEvent screenEvent) { OnRsScreenConnectionChange(rsScreenId, screenEvent); });
67    if (res != StatusCode::SUCCESS) {
68        auto task = [this] {
69            RegisterRsScreenConnectionChangeListener();
70        };
71        // post task after 50 ms.
72        controllerHandler_->PostTask(task, "wms:RegisterRsScreenConnectionChangeListener",
73            50, AppExecFwk::EventQueue::Priority::HIGH);
74    }
75}
76
77std::vector<ScreenId> AbstractScreenController::GetAllScreenIds() const
78{
79    std::lock_guard<std::recursive_mutex> lock(mutex_);
80    std::vector<ScreenId> res;
81    for (const auto& iter : dmsScreenMap_) {
82        res.emplace_back(iter.first);
83    }
84    return res;
85}
86
87std::vector<ScreenId> AbstractScreenController::GetAllValidScreenIds(const std::vector<ScreenId>& screenIds) const
88{
89    std::lock_guard<std::recursive_mutex> lock(mutex_);
90    std::vector<ScreenId> validScreenIds;
91    for (ScreenId screenId : screenIds) {
92        auto screenIdIter = std::find(validScreenIds.begin(), validScreenIds.end(), screenId);
93        if (screenIdIter != validScreenIds.end()) {
94            continue;
95        }
96        auto iter = dmsScreenMap_.find(screenId);
97        if (iter != dmsScreenMap_.end() && iter->second->type_ != ScreenType::UNDEFINED) {
98            validScreenIds.emplace_back(screenId);
99        }
100    }
101    return validScreenIds;
102}
103
104const std::shared_ptr<RSDisplayNode>& AbstractScreenController::GetRSDisplayNodeByScreenId(ScreenId dmsScreenId) const
105{
106    static std::shared_ptr<RSDisplayNode> notFound = nullptr;
107    sptr<AbstractScreen> screen = GetAbstractScreen(dmsScreenId);
108    if (screen == nullptr) {
109        WLOGFE("screen is nullptr");
110        return notFound;
111    }
112    if (screen->rsDisplayNode_ == nullptr) {
113        WLOGE("rsDisplayNode_ is nullptr");
114        return notFound;
115    }
116    WLOGI("GetRSDisplayNodeByScreenId: screen: %{public}" PRIu64", nodeId: %{public}" PRIu64" ",
117        screen->dmsId_, screen->rsDisplayNode_->GetId());
118    return screen->rsDisplayNode_;
119}
120
121void AbstractScreenController::UpdateRSTree(ScreenId dmsScreenId, ScreenId parentScreenId,
122    std::shared_ptr<RSSurfaceNode>& surfaceNode, bool isAdd, bool isMultiDisplay)
123{
124    sptr<AbstractScreen> abstractScreen = GetAbstractScreen(dmsScreenId);
125    if (abstractScreen == nullptr) {
126        WLOGE("[UpdateRSTree] can not find abstractScreen");
127        return;
128    }
129    if (isMultiDisplay) {
130        sptr<AbstractScreen> parentAbstractScreen = GetAbstractScreen(parentScreenId);
131        if (parentAbstractScreen == nullptr) {
132            WLOGE("[UpdateRSTree] can not find parentAbstractScreen");
133            return;
134        }
135        if (parentAbstractScreen->rsDisplayNode_ == nullptr) {
136            WLOGE("rsDisplayNode of parentAbstractScreen is nullptr");
137            return;
138        }
139        abstractScreen->UpdateDisplayGroupRSTree(surfaceNode, parentAbstractScreen->rsDisplayNode_->GetId(), isAdd);
140    } else {
141        abstractScreen->UpdateRSTree(surfaceNode, isAdd);
142    }
143}
144
145DMError AbstractScreenController::AddSurfaceNodeToScreen(ScreenId dmsScreenId,
146    std::shared_ptr<RSSurfaceNode>& surfaceNode, bool onTop)
147{
148    sptr<AbstractScreen> abstractScreen = GetAbstractScreen(dmsScreenId);
149    if (abstractScreen == nullptr) {
150        WLOGFE("Can not find abstractScreen");
151        return DMError::DM_ERROR_NULLPTR;
152    }
153    return abstractScreen->AddSurfaceNode(surfaceNode, onTop);
154}
155
156DMError AbstractScreenController::RemoveSurfaceNodeFromScreen(ScreenId dmsScreenId,
157    std::shared_ptr<RSSurfaceNode>& surfaceNode)
158{
159    sptr<AbstractScreen> abstractScreen = GetAbstractScreen(dmsScreenId);
160    if (abstractScreen == nullptr) {
161        WLOGFE("Can not find abstractScreen");
162        return DMError::DM_ERROR_NULLPTR;
163    }
164    return abstractScreen->RemoveSurfaceNode(surfaceNode);
165}
166
167sptr<AbstractScreen> AbstractScreenController::GetAbstractScreen(ScreenId dmsScreenId) const
168{
169    WLOGD("GetAbstractScreen: screenId: %{public}" PRIu64"", dmsScreenId);
170    std::lock_guard<std::recursive_mutex> lock(mutex_);
171    auto iter = dmsScreenMap_.find(dmsScreenId);
172    if (iter == dmsScreenMap_.end()) {
173        WLOGE("did not find screen:%{public}" PRIu64"", dmsScreenId);
174        return nullptr;
175    }
176    return iter->second;
177}
178
179sptr<AbstractScreenGroup> AbstractScreenController::GetAbstractScreenGroup(ScreenId dmsScreenId)
180{
181    std::lock_guard<std::recursive_mutex> lock(mutex_);
182    auto iter = dmsScreenGroupMap_.find(dmsScreenId);
183    if (iter == dmsScreenGroupMap_.end()) {
184        WLOGE("did not find screen:%{public}" PRIu64"", dmsScreenId);
185        return nullptr;
186    }
187    return iter->second;
188}
189
190ScreenId AbstractScreenController::GetDefaultAbstractScreenId()
191{
192    if (defaultRsScreenId_ == SCREEN_ID_INVALID) {
193        defaultRsScreenId_ = rsInterface_.GetDefaultScreenId();
194    }
195    if (defaultRsScreenId_ == SCREEN_ID_INVALID) {
196        WLOGFW("GetDefaultAbstractScreenId, rsDefaultId is invalid.");
197        return SCREEN_ID_INVALID;
198    }
199    std::lock_guard<std::recursive_mutex> lock(mutex_);
200    ScreenId defaultDmsScreenId;
201    if (screenIdManager_.ConvertToDmsScreenId(defaultRsScreenId_, defaultDmsScreenId)) {
202        WLOGFD("GetDefaultAbstractScreenId, screen:%{public}" PRIu64"", defaultDmsScreenId);
203        return defaultDmsScreenId;
204    }
205    WLOGFI("GetDefaultAbstractScreenId, default screen is null, try to get.");
206    ProcessScreenConnected(defaultRsScreenId_);
207    return screenIdManager_.ConvertToDmsScreenId(defaultRsScreenId_);
208}
209
210ScreenId AbstractScreenController::ConvertToRsScreenId(ScreenId dmsScreenId) const
211{
212    std::lock_guard<std::recursive_mutex> lock(mutex_);
213    return screenIdManager_.ConvertToRsScreenId(dmsScreenId);
214}
215
216ScreenId AbstractScreenController::ConvertToDmsScreenId(ScreenId rsScreenId) const
217{
218    std::lock_guard<std::recursive_mutex> lock(mutex_);
219    return screenIdManager_.ConvertToDmsScreenId(rsScreenId);
220}
221
222void AbstractScreenController::RegisterAbstractScreenCallback(sptr<AbstractScreenCallback> cb)
223{
224    std::lock_guard<std::recursive_mutex> lock(mutex_);
225    abstractScreenCallback_ = cb;
226    if (abstractScreenCallback_ == nullptr) {
227        return;
228    }
229    for (auto& iter : dmsScreenMap_) {
230        if (iter.second != nullptr) {
231            WLOGFI("dmsScreenId :%{public}" PRIu64"", iter.first);
232            abstractScreenCallback_->onConnect_(iter.second);
233        }
234    }
235}
236
237void AbstractScreenController::OnRsScreenConnectionChange(ScreenId rsScreenId, ScreenEvent screenEvent)
238{
239    WLOGFI("RS screen event. rsScreenId:%{public}" PRIu64", defaultRsScreenId_:%{public}" PRIu64", event:%{public}u",
240        rsScreenId, static_cast<uint64_t>(defaultRsScreenId_), static_cast<uint32_t>(screenEvent));
241    if (screenEvent == ScreenEvent::CONNECTED) {
242        auto task = [this, rsScreenId] {
243            ProcessScreenConnected(rsScreenId);
244        };
245        controllerHandler_->PostTask(task, "wms:OnRsScreenConnectionChange", 0, AppExecFwk::EventQueue::Priority::HIGH);
246    } else if (screenEvent == ScreenEvent::DISCONNECTED) {
247        auto task = [this, rsScreenId] {
248            ProcessScreenDisconnected(rsScreenId);
249        };
250        controllerHandler_->PostTask(task, "wms:OnRsScreenConnectionChange", 0, AppExecFwk::EventQueue::Priority::HIGH);
251    } else {
252        WLOGE("unknown message:%{public}ud", static_cast<uint8_t>(screenEvent));
253    }
254}
255
256void AbstractScreenController::ProcessDefaultScreenReconnected(ScreenId rsScreenId)
257{
258    std::lock_guard<std::recursive_mutex> lock(mutex_);
259    if (rsScreenId != defaultRsScreenId_ || defaultRsScreenId_ == SCREEN_ID_INVALID) {
260        return;
261    }
262    ScreenId dmsScreenId;
263    if (!screenIdManager_.ConvertToDmsScreenId(rsScreenId, dmsScreenId)) {
264        WLOGFE("disconnect screen, rsScreenId=%{public}" PRIu64" is not in rs2DmsScreenIdMap_", rsScreenId);
265        return;
266    }
267    WLOGFD("rsScreenId=%{public}" PRIu64", dmsScreenId=%{public}" PRIu64", "
268        "defaultRsScreenId: %{public}" PRIu64"", rsScreenId, dmsScreenId, static_cast<uint64_t>(defaultRsScreenId_));
269    auto dmsScreenMapIter = dmsScreenMap_.find(dmsScreenId);
270    if (dmsScreenMapIter != dmsScreenMap_.end()) {
271        auto screen = dmsScreenMapIter->second;
272        if (screen == nullptr) {
273            WLOGFE("screen is nullptr");
274            return;
275        }
276        auto groupDmsId = screen->lastGroupDmsId_;
277        auto iter = dmsScreenGroupMap_.find(groupDmsId);
278        if (iter == dmsScreenGroupMap_.end()) {
279            WLOGFE("groupDmsId: %{public}" PRIu64"is not in dmsScreenGroupMap_.", groupDmsId);
280            return;
281        }
282        sptr<AbstractScreenGroup> screenGroup = iter->second;
283        if (screenGroup == nullptr) {
284            WLOGFE("screenGroup is nullptr");
285            return;
286        }
287        Point point;
288        if (!screenGroup->AddChild(screen, point)) {
289            WLOGE("fail to add screen to group. screen: %{public}" PRIu64"", screen->dmsId_);
290            return;
291        }
292
293        // Recover default screen, set power state again
294        SetScreenPowerForAll(powerState_, PowerStateChangeReason::POWER_BUTTON, false);
295        const uint32_t level = 165;
296        RSInterfaces::GetInstance().SetScreenBacklight(rsScreenId, level);
297    } else {
298        WLOGFE("can't find screen in dmsScreenMap, dmsScreenId: %{public}" PRIu64"", dmsScreenId);
299    }
300}
301
302void AbstractScreenController::ProcessScreenConnected(ScreenId rsScreenId)
303{
304    WLOGFI("start");
305    std::lock_guard<std::recursive_mutex> lock(mutex_);
306    if (screenIdManager_.HasRsScreenId(rsScreenId)) {
307        WLOGFD("reconnect screen, screenId=%{public}" PRIu64"", rsScreenId);
308        ProcessDefaultScreenReconnected(rsScreenId);
309        return;
310    }
311    auto absScreen = InitAndGetScreen(rsScreenId);
312    if (absScreen == nullptr) {
313        return;
314    }
315    sptr<AbstractScreenGroup> screenGroup = AddToGroupLocked(absScreen);
316    if (screenGroup == nullptr) {
317        return;
318    }
319    if (rsScreenId == rsInterface_.GetDefaultScreenId() && absScreen->rsDisplayNode_ != nullptr) {
320        absScreen->screenRequestedOrientation_ = buildInDefaultOrientation_;
321        Rotation rotationAfter = absScreen->CalcRotation(absScreen->screenRequestedOrientation_);
322        WLOGFD("set default rotation to %{public}d for buildin screen", rotationAfter);
323        sptr<SupportedScreenModes> abstractScreenModes = absScreen->GetActiveScreenMode();
324        if (abstractScreenModes != nullptr) {
325            float w = abstractScreenModes->width_;
326            float h = abstractScreenModes->height_;
327            float x = 0;
328            float y = 0;
329            if (!IsVertical(rotationAfter)) {
330                std::swap(w, h);
331                x = (h - w) / 2; // 2: used to calculate offset to center display node
332                y = (w - h) / 2; // 2: used to calculate offset to center display node
333            }
334            // 90.f is base degree
335            absScreen->rsDisplayNode_->SetRotation(-90.0f * static_cast<uint32_t>(rotationAfter));
336            absScreen->rsDisplayNode_->SetFrame(x, y, w, h);
337            absScreen->rsDisplayNode_->SetBounds(x, y, w, h);
338            auto transactionProxy = RSTransactionProxy::GetInstance();
339            if (transactionProxy != nullptr) {
340                transactionProxy->FlushImplicitTransaction();
341            }
342            absScreen->rotation_ = rotationAfter;
343            absScreen->SetOrientation(absScreen->screenRequestedOrientation_);
344        }
345    }
346    NotifyScreenConnected(absScreen->ConvertToScreenInfo());
347    NotifyScreenGroupChanged(absScreen->ConvertToScreenInfo(), ScreenGroupChangeEvent::ADD_TO_GROUP);
348    if (abstractScreenCallback_ != nullptr) {
349        abstractScreenCallback_->onConnect_(absScreen);
350    }
351}
352
353sptr<AbstractScreen> AbstractScreenController::InitAndGetScreen(ScreenId rsScreenId)
354{
355    ScreenId dmsScreenId = screenIdManager_.CreateAndGetNewScreenId(rsScreenId);
356    RSScreenCapability screenCapability = rsInterface_.GetScreenCapability(rsScreenId);
357    WLOGFI("Screen name is %{public}s, phyWidth is %{public}u, phyHeight is %{public}u",
358        screenCapability.GetName().c_str(), screenCapability.GetPhyWidth(), screenCapability.GetPhyHeight());
359
360    sptr<AbstractScreen> absScreen =
361        new(std::nothrow) AbstractScreen(this, screenCapability.GetName(), dmsScreenId, rsScreenId);
362    if (absScreen == nullptr) {
363        WLOGFE("new AbstractScreen failed.");
364        screenIdManager_.DeleteScreenId(dmsScreenId);
365        return nullptr;
366    }
367    absScreen->SetPhyWidth(screenCapability.GetPhyWidth());
368    absScreen->SetPhyHeight(screenCapability.GetPhyHeight());
369
370    if (!InitAbstractScreenModesInfo(absScreen)) {
371        screenIdManager_.DeleteScreenId(dmsScreenId);
372        WLOGFE("InitAndGetScreen failed.");
373        return nullptr;
374    }
375    dmsScreenMap_.insert(std::make_pair(dmsScreenId, absScreen));
376    return absScreen;
377}
378
379void AbstractScreenController::ProcessScreenDisconnected(ScreenId rsScreenId)
380{
381    ScreenId dmsScreenId;
382    std::lock_guard<std::recursive_mutex> lock(mutex_);
383    if (!screenIdManager_.ConvertToDmsScreenId(rsScreenId, dmsScreenId)) {
384        WLOGFE("disconnect screen, rsScreenId=%{public}" PRIu64" is not in rs2DmsScreenIdMap_", rsScreenId);
385        return;
386    }
387    WLOGFI("disconnect screen, rsScreenId= %{public}" PRIu64", dmsScreenId= %{public}" PRIu64"",
388        rsScreenId, dmsScreenId);
389    auto dmsScreenMapIter = dmsScreenMap_.find(dmsScreenId);
390    sptr<AbstractScreenGroup> screenGroup;
391    if (dmsScreenMapIter != dmsScreenMap_.end()) {
392        auto screen = dmsScreenMapIter->second;
393        if (abstractScreenCallback_ != nullptr && CheckScreenInScreenGroup(screen)) {
394            if (rsScreenId == defaultRsScreenId_ && defaultRsScreenId_ != SCREEN_ID_INVALID) {
395                // Disconnect default screen
396                RemoveDefaultScreenFromGroupLocked(screen);
397                return;
398            }
399            abstractScreenCallback_->onDisconnect_(screen);
400        }
401        screenGroup = RemoveFromGroupLocked(screen);
402        if (screenGroup != nullptr) {
403            NotifyScreenGroupChanged(screen->ConvertToScreenInfo(), ScreenGroupChangeEvent::REMOVE_FROM_GROUP);
404        }
405        dmsScreenMap_.erase(dmsScreenMapIter);
406        NotifyScreenDisconnected(dmsScreenId);
407        if (screenGroup != nullptr && screenGroup->combination_ == ScreenCombination::SCREEN_MIRROR &&
408            screen->dmsId_ == screenGroup->mirrorScreenId_ && screenGroup->GetChildCount() != 0) {
409            auto defaultScreenId = GetDefaultAbstractScreenId();
410            std::vector<ScreenId> screens;
411            for (auto& screenItem : screenGroup->GetChildren()) {
412                if (screenItem->dmsId_ != defaultScreenId) {
413                    screens.emplace_back(screenItem->dmsId_);
414                }
415            }
416            MakeMirror(defaultScreenId, screens);
417        }
418    }
419    screenIdManager_.DeleteScreenId(dmsScreenId);
420}
421
422bool AbstractScreenController::InitAbstractScreenModesInfo(sptr<AbstractScreen>& absScreen)
423{
424    std::vector<RSScreenModeInfo> allModes = rsInterface_.GetScreenSupportedModes(absScreen->rsId_);
425    if (allModes.size() == 0) {
426        WLOGE("supported screen mode is 0, screenId=%{public}" PRIu64"", absScreen->rsId_);
427        return false;
428    }
429    for (const RSScreenModeInfo& rsScreenModeInfo : allModes) {
430        sptr<SupportedScreenModes> info = new(std::nothrow) SupportedScreenModes();
431        if (info == nullptr) {
432            WLOGFE("create SupportedScreenModes failed");
433            return false;
434        }
435        info->id_ = static_cast<uint32_t>(rsScreenModeInfo.GetScreenModeId());
436        info->width_ = static_cast<uint32_t>(rsScreenModeInfo.GetScreenWidth());
437        info->height_ = static_cast<uint32_t>(rsScreenModeInfo.GetScreenHeight());
438        info->refreshRate_ = rsScreenModeInfo.GetScreenRefreshRate();
439        absScreen->modes_.push_back(info);
440        WLOGD("fill screen idx:%{public}d w/h:%{public}d/%{public}d",
441            rsScreenModeInfo.GetScreenModeId(), info->width_, info->height_);
442    }
443    int32_t activeModeId = rsInterface_.GetScreenActiveMode(absScreen->rsId_).GetScreenModeId();
444    WLOGD("fill screen activeModeId:%{public}d", activeModeId);
445    if (static_cast<std::size_t>(activeModeId) >= allModes.size()) {
446        WLOGE("activeModeId exceed, screenId=%{public}" PRIu64", activeModeId:%{public}d/%{public}ud",
447            absScreen->rsId_, activeModeId, static_cast<uint32_t>(allModes.size()));
448        return false;
449    }
450    absScreen->activeIdx_ = activeModeId;
451    return true;
452}
453
454sptr<AbstractScreenGroup> AbstractScreenController::AddToGroupLocked(sptr<AbstractScreen> newScreen)
455{
456    sptr<AbstractScreenGroup> res;
457    if (dmsScreenGroupMap_.empty()) {
458        WLOGFI("connect the first screen");
459        res = AddAsFirstScreenLocked(newScreen);
460    } else {
461        res = AddAsSuccedentScreenLocked(newScreen);
462    }
463    return res;
464}
465
466void AbstractScreenController::RemoveDefaultScreenFromGroupLocked(sptr<AbstractScreen> screen)
467{
468    std::lock_guard<std::recursive_mutex> lock(mutex_);
469    if (screen == nullptr) {
470        return;
471    }
472    auto groupDmsId = screen->groupDmsId_;
473    auto iter = dmsScreenGroupMap_.find(groupDmsId);
474    if (iter == dmsScreenGroupMap_.end()) {
475        WLOGFE("groupDmsId:%{public}" PRIu64"is not in dmsScreenGroupMap_.", groupDmsId);
476        return;
477    }
478    sptr<AbstractScreenGroup> screenGroup = iter->second;
479    if (screenGroup == nullptr) {
480        return;
481    }
482    auto rsScreenId = screen->rsId_;
483    bool res = screenGroup->RemoveDefaultScreen(screen);
484    if (!res) {
485        WLOGFE("RemoveDefaultScreen failed, rsScreenId: %{public}" PRIu64"", rsScreenId);
486    }
487}
488
489sptr<AbstractScreenGroup> AbstractScreenController::RemoveFromGroupLocked(sptr<AbstractScreen> screen)
490{
491    std::lock_guard<std::recursive_mutex> lock(mutex_);
492    if (screen == nullptr) {
493        return nullptr;
494    }
495    auto groupDmsId = screen->groupDmsId_;
496    auto iter = dmsScreenGroupMap_.find(groupDmsId);
497    if (iter == dmsScreenGroupMap_.end()) {
498        WLOGFE("groupDmsId:%{public}" PRIu64"is not in dmsScreenGroupMap_.", groupDmsId);
499        return nullptr;
500    }
501    sptr<AbstractScreenGroup> screenGroup = iter->second;
502    if (!RemoveChildFromGroup(screen, screenGroup)) {
503        WLOGFE("RemoveChildFromGroup failed");
504        return nullptr;
505    }
506    return screenGroup;
507}
508
509bool AbstractScreenController::RemoveChildFromGroup(sptr<AbstractScreen> screen, sptr<AbstractScreenGroup> screenGroup)
510{
511    bool res = screenGroup->RemoveChild(screen);
512    if (!res) {
513        WLOGFE("remove screen:%{public}" PRIu64" failed from screenGroup:%{public}" PRIu64".",
514              screen->dmsId_, screen->groupDmsId_);
515        return false;
516    }
517    if (screenGroup->GetChildCount() == 0) {
518        // Group removed, need to do something.
519        std::lock_guard<std::recursive_mutex> lock(mutex_);
520        dmsScreenGroupMap_.erase(screenGroup->dmsId_);
521        dmsScreenMap_.erase(screenGroup->dmsId_);
522    }
523    return true;
524}
525
526bool AbstractScreenController::CheckScreenInScreenGroup(sptr<AbstractScreen> screen) const
527{
528    std::lock_guard<std::recursive_mutex> lock(mutex_);
529    auto groupDmsId = screen->groupDmsId_;
530    auto iter = dmsScreenGroupMap_.find(groupDmsId);
531    if (iter == dmsScreenGroupMap_.end()) {
532        WLOGFE("groupDmsId:%{public}" PRIu64"is not in dmsScreenGroupMap_.", groupDmsId);
533        return false;
534    }
535    sptr<AbstractScreenGroup> screenGroup = iter->second;
536    return screenGroup->HasChild(screen->dmsId_);
537}
538
539sptr<AbstractScreenGroup> AbstractScreenController::AddAsFirstScreenLocked(sptr<AbstractScreen> newScreen)
540{
541    ScreenId dmsGroupScreenId = screenIdManager_.CreateAndGetNewScreenId(SCREEN_ID_INVALID);
542    std::ostringstream buffer;
543    buffer<<"ScreenGroup_"<<dmsGroupScreenId;
544    std::string name = buffer.str();
545    // default ScreenCombination is mirror
546    isExpandCombination_ = system::GetParameter("persist.display.expand.enabled", "0") == "1";
547    sptr<AbstractScreenGroup> screenGroup;
548    if (isExpandCombination_) {
549        screenGroup = new(std::nothrow) AbstractScreenGroup(this, dmsGroupScreenId,
550            SCREEN_ID_INVALID, name, ScreenCombination::SCREEN_EXPAND);
551    } else {
552        screenGroup = new(std::nothrow) AbstractScreenGroup(this, dmsGroupScreenId,
553            SCREEN_ID_INVALID, name, ScreenCombination::SCREEN_MIRROR);
554    }
555
556    if (screenGroup == nullptr) {
557        WLOGE("new AbstractScreenGroup failed");
558        screenIdManager_.DeleteScreenId(dmsGroupScreenId);
559        return nullptr;
560    }
561    Point point;
562    if (!screenGroup->AddChild(newScreen, point)) {
563        WLOGE("fail to add screen to group. screen=%{public}" PRIu64"", newScreen->dmsId_);
564        screenIdManager_.DeleteScreenId(dmsGroupScreenId);
565        return nullptr;
566    }
567    auto iter = dmsScreenGroupMap_.find(dmsGroupScreenId);
568    if (iter != dmsScreenGroupMap_.end()) {
569        WLOGE("group screen existed. id=%{public}" PRIu64"", dmsGroupScreenId);
570        dmsScreenGroupMap_.erase(iter);
571    }
572    dmsScreenGroupMap_.insert(std::make_pair(dmsGroupScreenId, screenGroup));
573    dmsScreenMap_.insert(std::make_pair(dmsGroupScreenId, screenGroup));
574    screenGroup->mirrorScreenId_ = newScreen->dmsId_;
575    WLOGI("connect new group screen, screenId: %{public}" PRIu64", screenGroupId: %{public}" PRIu64", "
576        "combination:%{public}u", newScreen->dmsId_, dmsGroupScreenId, newScreen->type_);
577    return screenGroup;
578}
579
580sptr<AbstractScreenGroup> AbstractScreenController::AddAsSuccedentScreenLocked(sptr<AbstractScreen> newScreen)
581{
582    ScreenId defaultScreenId = GetDefaultAbstractScreenId();
583    auto iter = dmsScreenMap_.find(defaultScreenId);
584    if (iter == dmsScreenMap_.end()) {
585        WLOGE("AddAsSuccedentScreenLocked. defaultScreenId:%{public}" PRIu64" is not in dmsScreenMap_.",
586            defaultScreenId);
587        return nullptr;
588    }
589    auto screen = iter->second;
590    auto screenGroupIter = dmsScreenGroupMap_.find(screen->groupDmsId_);
591    if (screenGroupIter == dmsScreenGroupMap_.end()) {
592        WLOGE("AddAsSuccedentScreenLocked. groupDmsId:%{public}" PRIu64" is not in dmsScreenGroupMap_.",
593            screen->groupDmsId_);
594        return nullptr;
595    }
596    auto screenGroup = screenGroupIter->second;
597    Point point;
598    if (screenGroup->combination_ == ScreenCombination::SCREEN_EXPAND) {
599        for (auto& child : screenGroup->GetChildren()) {
600            WLOGD("AddAsSuccedentScreenLocked. defaultScreen rotation:%d", child->rotation_);
601            if (child->rotation_ == Rotation::ROTATION_90 || child->rotation_ == Rotation::ROTATION_270) {
602                point.posX_ += static_cast<int32_t>(child->GetActiveScreenMode()->height_);
603            } else {
604                point.posX_ += static_cast<int32_t>(child->GetActiveScreenMode()->width_);
605            }
606        }
607        WLOGD("AddAsSuccedentScreenLocked. point:[%d %d]", point.posX_, point.posY_);
608    }
609    screenGroup->AddChild(newScreen, point);
610    return screenGroup;
611}
612
613ScreenId AbstractScreenController::CreateVirtualScreen(VirtualScreenOption option,
614    const sptr<IRemoteObject>& displayManagerAgent)
615{
616    ScreenId rsId = rsInterface_.CreateVirtualScreen(option.name_, option.width_,
617        option.height_, option.surface_, SCREEN_ID_INVALID, option.flags_);
618    WLOGFI("id: %{public}" PRIu64"", rsId);
619    if (rsId == SCREEN_ID_INVALID) {
620        return SCREEN_ID_INVALID;
621    }
622    std::lock_guard<std::recursive_mutex> lock(mutex_);
623    ScreenId dmsScreenId = SCREEN_ID_INVALID;
624    if (!screenIdManager_.ConvertToDmsScreenId(rsId, dmsScreenId)) {
625        dmsScreenId = screenIdManager_.CreateAndGetNewScreenId(rsId);
626        auto absScreen = InitVirtualScreen(dmsScreenId, rsId, option);
627        if (absScreen == nullptr) {
628            screenIdManager_.DeleteScreenId(dmsScreenId);
629            return SCREEN_ID_INVALID;
630        }
631        dmsScreenMap_.insert(std::make_pair(dmsScreenId, absScreen));
632        NotifyScreenConnected(absScreen->ConvertToScreenInfo());
633        if (deathRecipient_ == nullptr) {
634            deathRecipient_ =
635                new AgentDeathRecipient([this](const sptr<IRemoteObject>& agent) { OnRemoteDied(agent); });
636        }
637        auto agIter = screenAgentMap_.find(displayManagerAgent);
638        if (agIter == screenAgentMap_.end()) {
639            displayManagerAgent->AddDeathRecipient(deathRecipient_);
640        }
641        screenAgentMap_[displayManagerAgent].emplace_back(dmsScreenId);
642    } else {
643        WLOGFI("id: %{public}" PRIu64" appears in screenIdManager_. ", rsId);
644    }
645    return dmsScreenId;
646}
647
648sptr<AbstractScreen> AbstractScreenController::InitVirtualScreen(ScreenId dmsScreenId, ScreenId rsId,
649    VirtualScreenOption option)
650{
651    sptr<AbstractScreen> absScreen = new(std::nothrow) AbstractScreen(this, option.name_, dmsScreenId, rsId);
652    sptr<SupportedScreenModes> info = new(std::nothrow) SupportedScreenModes();
653    if (absScreen == nullptr || info == nullptr) {
654        WLOGFI("new AbstractScreen or SupportedScreenModes failed");
655        screenIdManager_.DeleteScreenId(dmsScreenId);
656        rsInterface_.RemoveVirtualScreen(rsId);
657        return nullptr;
658    }
659    info->width_ = option.width_;
660    info->height_ = option.height_;
661    auto defaultScreen = GetAbstractScreen(GetDefaultAbstractScreenId());
662    if (defaultScreen != nullptr && defaultScreen->GetActiveScreenMode() != nullptr) {
663        info->refreshRate_ = defaultScreen->GetActiveScreenMode()->refreshRate_;
664    }
665    absScreen->modes_.emplace_back(info);
666    absScreen->activeIdx_ = 0;
667    absScreen->type_ = ScreenType::VIRTUAL;
668    absScreen->virtualPixelRatio_ = option.density_;
669    return absScreen;
670}
671
672DMError AbstractScreenController::DestroyVirtualScreen(ScreenId screenId)
673{
674    WLOGFI("AbstractScreenController::DestroyVirtualScreen");
675    std::lock_guard<std::recursive_mutex> lock(mutex_);
676    ScreenId rsScreenId = SCREEN_ID_INVALID;
677    screenIdManager_.ConvertToRsScreenId(screenId, rsScreenId);
678
679    sptr<IDisplayManagerAgent> displayManagerAgent = nullptr;
680    bool agentFound = false;
681    for (auto &agentIter : screenAgentMap_) {
682        for (auto iter = agentIter.second.begin(); iter != agentIter.second.end(); iter++) {
683            if (*iter == screenId) {
684                iter = agentIter.second.erase(iter);
685                agentFound = true;
686                break;
687            }
688        }
689        if (agentFound) {
690            if (agentIter.first != nullptr && agentIter.second.empty()) {
691                agentIter.first->RemoveDeathRecipient(deathRecipient_);
692                screenAgentMap_.erase(agentIter.first);
693            }
694            break;
695        }
696    }
697
698    if (rsScreenId != SCREEN_ID_INVALID && GetAbstractScreen(screenId) != nullptr) {
699        ProcessScreenDisconnected(rsScreenId);
700    }
701    screenIdManager_.DeleteScreenId(screenId);
702
703    if (rsScreenId == SCREEN_ID_INVALID) {
704        WLOGFE("DestroyVirtualScreen: No corresponding rsScreenId");
705        return DMError::DM_ERROR_INVALID_PARAM;
706    }
707    rsInterface_.RemoveVirtualScreen(rsScreenId);
708    return DMError::DM_OK;
709}
710
711DMError AbstractScreenController::SetVirtualScreenSurface(ScreenId screenId, sptr<Surface> surface)
712{
713    WLOGFI("begin");
714    std::lock_guard<std::recursive_mutex> lock(mutex_);
715    int32_t res = -1;
716    ScreenId rsScreenId;
717    if (screenIdManager_.ConvertToRsScreenId(screenId, rsScreenId)) {
718        res = rsInterface_.SetVirtualScreenSurface(rsScreenId, surface);
719    }
720    if (res != 0) {
721        WLOGE("SetVirtualScreenSurface failed in RenderService");
722        return DMError::DM_ERROR_RENDER_SERVICE_FAILED;
723    }
724    return DMError::DM_OK;
725}
726
727void AbstractScreenController::SetBuildInDefaultOrientation(Orientation orientation)
728{
729    if (orientation >= Orientation::BEGIN && orientation <= Orientation::END) {
730        buildInDefaultOrientation_ = orientation;
731    }
732}
733
734DMError AbstractScreenController::SetOrientation(ScreenId screenId, Orientation newOrientation,
735    bool isFromWindow, bool withAnimation)
736{
737    WLOGD("set orientation. screen %{public}" PRIu64" orientation %{public}u", screenId, newOrientation);
738    auto screen = GetAbstractScreen(screenId);
739    if (screen == nullptr) {
740        WLOGFE("fail to set orientation, cannot find screen %{public}" PRIu64"", screenId);
741        return DMError::DM_ERROR_NULLPTR;
742    }
743    if (screen->isScreenGroup_) {
744        WLOGE("cannot set orientation to the combination. screen: %{public}" PRIu64"", screenId);
745        return DMError::DM_ERROR_NULLPTR;
746    }
747    if (isFromWindow) {
748        if (newOrientation == Orientation::UNSPECIFIED) {
749            newOrientation = screen->screenRequestedOrientation_;
750            withAnimation = true;
751        }
752    } else {
753        screen->screenRequestedOrientation_ = newOrientation;
754    }
755    if (screen->orientation_ == newOrientation) {
756        WLOGFD("skip setting orientation. screen %{public}" PRIu64" orientation %{public}u", screenId, newOrientation);
757        return DMError::DM_OK;
758    }
759    if (isFromWindow) {
760        ScreenRotationController::ProcessOrientationSwitch(newOrientation, withAnimation);
761    } else {
762        Rotation rotationAfter = screen->CalcRotation(newOrientation);
763        SetRotation(screenId, rotationAfter, false);
764        screen->rotation_ = rotationAfter;
765    }
766    if (!screen->SetOrientation(newOrientation)) {
767        WLOGE("fail to set rotation, screen %{public}" PRIu64"", screenId);
768        return DMError::DM_ERROR_NULLPTR;
769    }
770
771    // Notify rotation event to ScreenManager
772    NotifyScreenChanged(screen->ConvertToScreenInfo(), ScreenChangeEvent::UPDATE_ORIENTATION);
773    // Notify rotation event to AbstractDisplayController
774    if (abstractScreenCallback_ != nullptr) {
775        if (!withAnimation) {
776            abstractScreenCallback_->onChange_(screen, DisplayChangeEvent::UPDATE_ORIENTATION_FROM_WINDOW);
777        } else {
778            abstractScreenCallback_->onChange_(screen, DisplayChangeEvent::UPDATE_ORIENTATION);
779        }
780    }
781
782    auto screenGroup = screen->GetGroup();
783    if (screenGroup) {
784        UpdateScreenGroupLayout(screenGroup);
785    }
786
787    return DMError::DM_OK;
788}
789
790void AbstractScreenController::UpdateScreenGroupLayout(sptr<AbstractScreenGroup> screenGroup)
791{
792    if (screenGroup->combination_ != ScreenCombination::SCREEN_EXPAND) {
793        return;
794    }
795
796    auto screens = screenGroup->GetChildren();
797    if (screens.size() <= 1) {
798        return;
799    }
800
801    // update display node's start point from left to right.
802    std::sort(screens.begin(), screens.end(), [](const auto &a, const auto &b) {
803        return a->startPoint_.posX_ < b->startPoint_.posX_;
804    });
805
806    Point point;
807    uint32_t width = 0;
808    for (auto& screen : screens) {
809        auto mode = screen->GetActiveScreenMode();
810        if (!mode) {
811            WLOGE("no active screen mode");
812            continue;
813        }
814
815        if (screen->startPoint_.posX_ != point.posX_) {
816            screen->UpdateRSDisplayNode(point);
817            if (abstractScreenCallback_ != nullptr) {
818                abstractScreenCallback_->onChange_(screen, DisplayChangeEvent::DISPLAY_SIZE_CHANGED);
819            }
820        }
821
822        if (screen->rotation_ == Rotation::ROTATION_90 ||
823            screen->rotation_ == Rotation::ROTATION_270) {
824            width = mode->height_;
825        } else {
826            width = mode->width_;
827        }
828
829        point.posX_ += static_cast<int32_t>(width);
830    }
831}
832
833void AbstractScreenController::SetScreenRotateAnimation(
834    sptr<AbstractScreen>& screen, ScreenId screenId, Rotation rotationAfter, bool withAnimation)
835{
836    sptr<SupportedScreenModes> abstractScreenModes = screen->GetActiveScreenMode();
837    struct ScreenRect srect = {0, 0, 0, 0};
838    if (abstractScreenModes != nullptr) {
839        srect.h = abstractScreenModes->height_;
840        srect.w = abstractScreenModes->width_;
841    }
842    if (!IsVertical(rotationAfter)) {
843        std::swap(srect.w, srect.h);
844        srect.x = (srect.h - srect.w) / 2; // 2: used to calculate offset to center display node
845        srect.y = (srect.w - srect.h) / 2; // 2: used to calculate offset to center display node
846    }
847    const std::shared_ptr<RSDisplayNode>& displayNode = GetRSDisplayNodeByScreenId(screenId);
848    if (displayNode == nullptr) {
849        return;
850    }
851    if (rotationAfter == Rotation::ROTATION_0 && screen->rotation_ == Rotation::ROTATION_270) {
852        WLOGFD("[FixOrientation] display rotate with animation");
853        // avoid animation 270, 240, 210 ... 30, 0, should play from 90->0
854        displayNode->SetRotation(90.f);
855    } else if (rotationAfter == Rotation::ROTATION_270 && screen->rotation_ == Rotation::ROTATION_0) {
856        WLOGFD("[FixOrientation] display rotate with animation");
857        // avoid animation 0, 30, 60 ... 270, should play from 360->270
858        displayNode->SetRotation(-360.f);
859    }
860    if (withAnimation) {
861        WLOGFD("[FixOrientation] display rotate with animation %{public}u", rotationAfter);
862        std::weak_ptr<RSDisplayNode> weakNode = GetRSDisplayNodeByScreenId(screenId);
863        static const RSAnimationTimingProtocol timingProtocol(600); // animation time
864        // animation curve: cubic [0.2, 0.0, 0.2, 1.0]
865        static const RSAnimationTimingCurve curve = RSAnimationTimingCurve::CreateCubicCurve(0.2, 0.0, 0.2, 1.0);
866#ifdef SOC_PERF_ENABLE
867        // Increase frequency to improve windowRotation perf
868        // 10027 means "gesture" level that setting duration: 800, lit_cpu_min_freq: 1421000, mid_cpu_min_feq: 1882000
869        OHOS::SOCPERF::SocPerfClient::GetInstance().PerfRequest(10027, "");
870#endif
871        RSNode::Animate(timingProtocol, curve, [weakNode, srect, rotationAfter, this]() {
872            auto displayNode = weakNode.lock();
873            if (displayNode == nullptr) {
874                WLOGFE("error, cannot get DisplayNode");
875                return;
876            }
877            SetDisplayNode(rotationAfter, displayNode, srect);
878        }, []() {
879#ifdef SOC_PERF_ENABLE
880            // ClosePerf in finishCallBack
881            OHOS::SOCPERF::SocPerfClient::GetInstance().PerfRequestEx(10027, false, "");
882#endif
883        });
884    } else {
885        WLOGFD("[FixOrientation] display rotate without animation %{public}u", rotationAfter);
886        SetDisplayNode(rotationAfter, displayNode, srect);
887    }
888}
889
890void AbstractScreenController::SetDisplayNode(Rotation rotationAfter,
891    const std::shared_ptr<RSDisplayNode>& displayNode, struct ScreenRect srect)
892{
893    displayNode->SetRotation(-90.f * static_cast<uint32_t>(rotationAfter)); // 90.f is base degree
894    displayNode->SetFrame(srect.x, srect.y, srect.w, srect.h);
895    displayNode->SetBounds(srect.x, srect.y, srect.w, srect.h);
896}
897
898void AbstractScreenController::OpenRotationSyncTransaction()
899{
900     // Before open transaction, it must flush first.
901    auto transactionProxy = RSTransactionProxy::GetInstance();
902    if (!transactionProxy) {
903        return;
904    }
905    transactionProxy->FlushImplicitTransaction();
906    auto syncTransactionController = RSSyncTransactionController::GetInstance();
907    if (syncTransactionController) {
908        syncTransactionController->OpenSyncTransaction();
909    }
910}
911
912void AbstractScreenController::CloseRotationSyncTransaction()
913{
914    auto syncTransactionController = RSSyncTransactionController::GetInstance();
915    if (syncTransactionController) {
916        syncTransactionController->CloseSyncTransaction();
917    }
918}
919
920bool AbstractScreenController::SetRotation(ScreenId screenId, Rotation rotationAfter,
921    bool isFromWindow, bool withAnimation)
922{
923    WLOGFI("Enter SetRotation, screenId: %{public}" PRIu64 ", rotation: %{public}u, isFromWindow: %{public}u,"
924        "animation: %{public}u", screenId, rotationAfter, isFromWindow, withAnimation);
925    auto screen = GetAbstractScreen(screenId);
926    if (screen == nullptr) {
927        WLOGFE("SetRotation error, cannot get screen with screenId: %{public}" PRIu64, screenId);
928        return false;
929    }
930    if (rotationAfter == screen->rotation_) {
931        WLOGFD("rotation not changed. screen %{public}" PRIu64" rotation %{public}u", screenId, rotationAfter);
932        return false;
933    }
934    WLOGFD("set orientation. rotation %{public}u", rotationAfter);
935    OpenRotationSyncTransaction();
936    SetScreenRotateAnimation(screen, screenId, rotationAfter, withAnimation);
937    screen->rotation_ = rotationAfter;
938    CloseRotationSyncTransaction();
939
940    NotifyScreenChanged(screen->ConvertToScreenInfo(), ScreenChangeEvent::UPDATE_ROTATION);
941    // Notify rotation event to AbstractDisplayController
942    if (abstractScreenCallback_ != nullptr) {
943        if (!withAnimation) {
944            abstractScreenCallback_->onChange_(screen, DisplayChangeEvent::UPDATE_ROTATION_FROM_WINDOW);
945        } else {
946            abstractScreenCallback_->onChange_(screen, DisplayChangeEvent::UPDATE_ROTATION);
947        }
948    }
949    return true;
950}
951
952DMError AbstractScreenController::GetScreenSupportedColorGamuts(ScreenId screenId,
953    std::vector<ScreenColorGamut>& colorGamuts)
954{
955    sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
956    if (screen == nullptr) {
957        return DMError::DM_ERROR_INVALID_PARAM;
958    }
959    return screen->GetScreenSupportedColorGamuts(colorGamuts);
960}
961
962DMError AbstractScreenController::GetScreenColorGamut(ScreenId screenId, ScreenColorGamut& colorGamut)
963{
964    sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
965    if (screen == nullptr) {
966        return DMError::DM_ERROR_INVALID_PARAM;
967    }
968    return screen->GetScreenColorGamut(colorGamut);
969}
970
971DMError AbstractScreenController::SetScreenColorGamut(ScreenId screenId, int32_t colorGamutIdx)
972{
973    sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
974    if (screen == nullptr) {
975        return DMError::DM_ERROR_INVALID_PARAM;
976    }
977    return screen->SetScreenColorGamut(colorGamutIdx);
978}
979
980DMError AbstractScreenController::GetScreenGamutMap(ScreenId screenId, ScreenGamutMap& gamutMap)
981{
982    sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
983    if (screen == nullptr) {
984        return DMError::DM_ERROR_INVALID_PARAM;
985    }
986    return screen->GetScreenGamutMap(gamutMap);
987}
988
989DMError AbstractScreenController::SetScreenGamutMap(ScreenId screenId, ScreenGamutMap gamutMap)
990{
991    sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
992    if (screen == nullptr) {
993        return DMError::DM_ERROR_INVALID_PARAM;
994    }
995    return screen->SetScreenGamutMap(gamutMap);
996}
997
998DMError AbstractScreenController::SetScreenColorTransform(ScreenId screenId)
999{
1000    sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
1001    if (screen == nullptr) {
1002        return DMError::DM_ERROR_INVALID_PARAM;
1003    }
1004    return screen->SetScreenColorTransform();
1005}
1006
1007DMError AbstractScreenController::SetScreenActiveMode(ScreenId screenId, uint32_t modeId)
1008{
1009    WLOGI("SetScreenActiveMode: RsScreenId: %{public}" PRIu64", modeId: %{public}u", screenId, modeId);
1010    if (screenId == SCREEN_ID_INVALID) {
1011        WLOGFE("SetScreenActiveMode: invalid screenId");
1012        return DMError::DM_ERROR_NULLPTR;
1013    }
1014    uint32_t usedModeId = 0;
1015    {
1016        std::lock_guard<std::recursive_mutex> lock(mutex_);
1017        auto screen = GetAbstractScreen(screenId);
1018        if (screen == nullptr) {
1019            WLOGFE("SetScreenActiveMode: Get AbstractScreen failed");
1020            return DMError::DM_ERROR_NULLPTR;
1021        }
1022        ScreenId rsScreenId = SCREEN_ID_INVALID;
1023        if (!screenIdManager_.ConvertToRsScreenId(screenId, rsScreenId)) {
1024            WLOGFE("SetScreenActiveMode: No corresponding rsId");
1025            return DMError::DM_ERROR_NULLPTR;
1026        }
1027        rsInterface_.SetScreenActiveMode(rsScreenId, modeId);
1028        usedModeId = static_cast<uint32_t>(screen->activeIdx_);
1029        screen->activeIdx_ = static_cast<int32_t>(modeId);
1030    }
1031    // add thread to process mode change sync event
1032    if (usedModeId != modeId) {
1033        WLOGI("SetScreenActiveMode: modeId: %{public}u ->  %{public}u", usedModeId, modeId);
1034        auto func = [=]() {
1035            ProcessScreenModeChanged(screenId);
1036            return;
1037        };
1038        controllerHandler_->PostTask(func, "wms:ProcessScreenModeChanged", 0, AppExecFwk::EventQueue::Priority::HIGH);
1039    }
1040    return DMError::DM_OK;
1041}
1042
1043void AbstractScreenController::ProcessScreenModeChanged(ScreenId dmsScreenId)
1044{
1045    sptr<AbstractScreen> absScreen = nullptr;
1046    sptr<AbstractScreenCallback> absScreenCallback = nullptr;
1047    sptr<SupportedScreenModes> activeScreenMode = nullptr;
1048    {
1049        std::lock_guard<std::recursive_mutex> lock(mutex_);
1050        auto dmsScreenMapIter = dmsScreenMap_.find(dmsScreenId);
1051        if (dmsScreenMapIter == dmsScreenMap_.end()) {
1052            WLOGFE("dmsScreenId=%{public}" PRIu64" is not in dmsScreenMap", dmsScreenId);
1053            return;
1054        }
1055        absScreen = GetAbstractScreen(dmsScreenId);
1056        if (absScreen == nullptr) {
1057            WLOGFE("screen is nullptr. dmsScreenId=%{public}" PRIu64"", dmsScreenId);
1058            return;
1059        }
1060        activeScreenMode = absScreen->GetActiveScreenMode();
1061        if (activeScreenMode == nullptr) {
1062            WLOGFE("active screen mode is nullptr. dmsScreenId=%{public}" PRIu64"",
1063                dmsScreenId);
1064            return;
1065        }
1066        absScreenCallback = abstractScreenCallback_;
1067    }
1068    uint32_t width = activeScreenMode->width_;
1069    uint32_t height = activeScreenMode->height_;
1070    uint32_t refreshRate = activeScreenMode->refreshRate_;
1071    HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:ProcessScreenModeChanged(%" PRIu64"),\
1072        width*height(%u*%u), refreshRate(%u)", dmsScreenId, width, height, refreshRate);
1073    if (absScreenCallback != nullptr) {
1074        absScreenCallback->onChange_(absScreen, DisplayChangeEvent::DISPLAY_SIZE_CHANGED);
1075    }
1076    NotifyScreenChanged(absScreen->ConvertToScreenInfo(), ScreenChangeEvent::CHANGE_MODE);
1077}
1078
1079DMError AbstractScreenController::MakeMirror(ScreenId screenId, std::vector<ScreenId> screens)
1080{
1081    WLOGI("MakeMirror, screenId:%{public}" PRIu64"", screenId);
1082    sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
1083    if (screen == nullptr || screen->type_ != ScreenType::REAL) {
1084        WLOGFE("screen is nullptr, or screenType is not real.");
1085        return DMError::DM_ERROR_NULLPTR;
1086    }
1087    WLOGFD("GetAbstractScreenGroup start");
1088    auto group = GetAbstractScreenGroup(screen->groupDmsId_);
1089    if (group == nullptr) {
1090        std::lock_guard<std::recursive_mutex> lock(mutex_);
1091        group = AddToGroupLocked(screen);
1092        if (group == nullptr) {
1093            WLOGFE("group is nullptr");
1094            return DMError::DM_ERROR_NULLPTR;
1095        }
1096        NotifyScreenGroupChanged(screen->ConvertToScreenInfo(), ScreenGroupChangeEvent::ADD_TO_GROUP);
1097        if (group != nullptr && abstractScreenCallback_ != nullptr) {
1098            abstractScreenCallback_->onConnect_(screen);
1099        }
1100    }
1101    WLOGFD("GetAbstractScreenGroup end");
1102    Point point;
1103    std::vector<Point> startPoints;
1104    startPoints.insert(startPoints.begin(), screens.size(), point);
1105    bool filterMirroredScreen =
1106        group->combination_ == ScreenCombination::SCREEN_MIRROR && group->mirrorScreenId_ == screen->dmsId_;
1107    group->mirrorScreenId_ = screen->dmsId_;
1108    ChangeScreenGroup(group, screens, startPoints, filterMirroredScreen, ScreenCombination::SCREEN_MIRROR);
1109    WLOGFI("MakeMirror success");
1110    return DMError::DM_OK;
1111}
1112
1113DMError AbstractScreenController::StopScreens(const std::vector<ScreenId>& screenIds, ScreenCombination stopCombination)
1114{
1115    std::lock_guard<std::recursive_mutex> lock(mutex_);
1116    for (ScreenId screenId : screenIds) {
1117        WLOGFI("ScreenId: %{public}" PRIu64"", screenId);
1118        auto screen = GetAbstractScreen(screenId);
1119        if (screen == nullptr) {
1120            WLOGFW("screen:%{public}" PRIu64" is nullptr", screenId);
1121            continue;
1122        }
1123        auto iter = dmsScreenGroupMap_.find(screen->groupDmsId_);
1124        if (iter == dmsScreenGroupMap_.end()) {
1125            WLOGFW("groupDmsId:%{public}" PRIu64"is not in dmsScreenGroupMap_", screen->groupDmsId_);
1126            continue;
1127        }
1128        sptr<AbstractScreenGroup> screenGroup = iter->second;
1129        if (screenGroup == nullptr) {
1130            WLOGFW("screenGroup:%{public}" PRIu64" is nullptr", screen->groupDmsId_);
1131            continue;
1132        }
1133        if (screenGroup->combination_ != stopCombination) {
1134            WLOGFW("try to stop screen in another combination");
1135            continue;
1136        }
1137        if (screenGroup->combination_ == ScreenCombination::SCREEN_MIRROR &&
1138            screen->dmsId_ == screenGroup->mirrorScreenId_) {
1139            WLOGFW("try to stop main mirror screen");
1140            continue;
1141        }
1142
1143        if (abstractScreenCallback_ != nullptr && CheckScreenInScreenGroup(screen)) {
1144            abstractScreenCallback_->onDisconnect_(screen);
1145        }
1146        bool res = RemoveChildFromGroup(screen, screenGroup);
1147        if (res) {
1148            NotifyScreenGroupChanged(screen->ConvertToScreenInfo(), ScreenGroupChangeEvent::REMOVE_FROM_GROUP);
1149        }
1150    }
1151    return DMError::DM_OK;
1152}
1153
1154void AbstractScreenController::ChangeScreenGroup(sptr<AbstractScreenGroup> group, const std::vector<ScreenId>& screens,
1155    const std::vector<Point>& startPoints, bool filterScreen, ScreenCombination combination)
1156{
1157    std::map<ScreenId, bool> removeChildResMap;
1158    std::vector<ScreenId> addScreens;
1159    std::vector<Point> addChildPos;
1160    std::lock_guard<std::recursive_mutex> lock(mutex_);
1161    for (uint64_t i = 0; i != screens.size(); i++) {
1162        ScreenId screenId = screens[i];
1163        WLOGFI("ScreenId: %{public}" PRIu64"", screenId);
1164        auto screen = GetAbstractScreen(screenId);
1165        if (screen == nullptr) {
1166            WLOGFE("screen:%{public}" PRIu64" is nullptr", screenId);
1167            continue;
1168        }
1169        WLOGFI("Screen->groupDmsId_: %{public}" PRIu64"", screen->groupDmsId_);
1170        if (filterScreen && screen->groupDmsId_ == group->dmsId_ && group->HasChild(screen->dmsId_)) {
1171            continue;
1172        }
1173        if (abstractScreenCallback_ != nullptr && CheckScreenInScreenGroup(screen)) {
1174            abstractScreenCallback_->onDisconnect_(screen);
1175        }
1176        auto originGroup = RemoveFromGroupLocked(screen);
1177        addChildPos.emplace_back(startPoints[i]);
1178        removeChildResMap[screenId] = originGroup != nullptr;
1179        addScreens.emplace_back(screenId);
1180    }
1181    group->combination_ = combination;
1182    AddScreenToGroup(group, addScreens, addChildPos, removeChildResMap);
1183}
1184
1185void AbstractScreenController::AddScreenToGroup(sptr<AbstractScreenGroup> group,
1186    const std::vector<ScreenId>& addScreens, const std::vector<Point>& addChildPos,
1187    std::map<ScreenId, bool>& removeChildResMap)
1188{
1189    std::vector<sptr<ScreenInfo>> addToGroup;
1190    std::vector<sptr<ScreenInfo>> removeFromGroup;
1191    std::vector<sptr<ScreenInfo>> changeGroup;
1192    for (uint64_t i = 0; i != addScreens.size(); i++) {
1193        ScreenId screenId = addScreens[i];
1194        sptr<AbstractScreen> screen = GetAbstractScreen(screenId);
1195        if (screen == nullptr) {
1196            continue;
1197        }
1198        Point expandPoint = addChildPos[i];
1199        WLOGFI("screenId: %{public}" PRIu64", Point: %{public}d, %{public}d",
1200            screen->dmsId_, expandPoint.posX_, expandPoint.posY_);
1201        bool addChildRes = group->AddChild(screen, expandPoint);
1202        if (removeChildResMap[screenId] && addChildRes) {
1203            changeGroup.emplace_back(screen->ConvertToScreenInfo());
1204            WLOGFD("changeGroup");
1205        } else if (removeChildResMap[screenId]) {
1206            WLOGFD("removeChild");
1207            removeFromGroup.emplace_back(screen->ConvertToScreenInfo());
1208        } else if (addChildRes) {
1209            WLOGFD("AddChild");
1210            addToGroup.emplace_back(screen->ConvertToScreenInfo());
1211        } else {
1212            WLOGFD("default, AddChild failed");
1213        }
1214        if (abstractScreenCallback_ != nullptr) {
1215            abstractScreenCallback_->onConnect_(screen);
1216        }
1217    }
1218
1219    NotifyScreenGroupChanged(removeFromGroup, ScreenGroupChangeEvent::REMOVE_FROM_GROUP);
1220    NotifyScreenGroupChanged(changeGroup, ScreenGroupChangeEvent::CHANGE_GROUP);
1221    NotifyScreenGroupChanged(addToGroup, ScreenGroupChangeEvent::ADD_TO_GROUP);
1222}
1223
1224bool AbstractScreenController::MakeExpand(std::vector<ScreenId> screenIds, std::vector<Point> startPoints)
1225{
1226    ScreenId defaultScreenId = GetDefaultAbstractScreenId();
1227    WLOGI("MakeExpand, defaultScreenId:%{public}" PRIu64"", defaultScreenId);
1228    auto defaultScreen = GetAbstractScreen(defaultScreenId);
1229    if (defaultScreen == nullptr) {
1230        return false;
1231    }
1232    auto group = GetAbstractScreenGroup(defaultScreen->groupDmsId_);
1233    if (group == nullptr) {
1234        return false;
1235    }
1236    bool filterExpandScreen = group->combination_ == ScreenCombination::SCREEN_EXPAND;
1237    ChangeScreenGroup(group, screenIds, startPoints, filterExpandScreen, ScreenCombination::SCREEN_EXPAND);
1238    WLOGFI("MakeExpand success");
1239    return true;
1240}
1241
1242void AbstractScreenController::RemoveVirtualScreenFromGroup(std::vector<ScreenId> screens)
1243{
1244    if (screens.empty()) {
1245        return;
1246    }
1247    std::vector<sptr<ScreenInfo>> removeFromGroup;
1248    for (ScreenId screenId : screens) {
1249        auto screen = GetAbstractScreen(screenId);
1250        if (screen == nullptr || screen->type_ != ScreenType::VIRTUAL) {
1251            continue;
1252        }
1253        auto originGroup = GetAbstractScreenGroup(screen->groupDmsId_);
1254        if (originGroup == nullptr) {
1255            continue;
1256        }
1257        if (!originGroup->HasChild(screenId)) {
1258            continue;
1259        }
1260        if (abstractScreenCallback_ != nullptr && CheckScreenInScreenGroup(screen)) {
1261            abstractScreenCallback_->onDisconnect_(screen);
1262        }
1263        RemoveFromGroupLocked(screen);
1264        removeFromGroup.emplace_back(screen->ConvertToScreenInfo());
1265    }
1266    NotifyScreenGroupChanged(removeFromGroup, ScreenGroupChangeEvent::REMOVE_FROM_GROUP);
1267}
1268
1269bool AbstractScreenController::OnRemoteDied(const sptr<IRemoteObject>& agent)
1270{
1271    if (agent == nullptr) {
1272        return false;
1273    }
1274    std::lock_guard<std::recursive_mutex> lock(mutex_);
1275    auto agentIter = screenAgentMap_.find(agent);
1276    if (agentIter != screenAgentMap_.end()) {
1277        while (screenAgentMap_[agent].size() > 0) {
1278            auto diedId = screenAgentMap_[agent][0];
1279            WLOGI("destroy screenId in OnRemoteDied: %{public}" PRIu64"", diedId);
1280            DMError res = DestroyVirtualScreen(diedId);
1281            if (res != DMError::DM_OK) {
1282                WLOGE("destroy failed in OnRemoteDied: %{public}" PRIu64"", diedId);
1283            }
1284        }
1285        screenAgentMap_.erase(agent);
1286    }
1287    return true;
1288}
1289
1290ScreenId AbstractScreenController::ScreenIdManager::CreateAndGetNewScreenId(ScreenId rsScreenId)
1291{
1292    ScreenId dmsScreenId = dmsScreenCount_++;
1293    if (dms2RsScreenIdMap_.find(dmsScreenId) != dms2RsScreenIdMap_.end()) {
1294        WLOGFW("dmsScreenId: %{public}" PRIu64" exit in dms2RsScreenIdMap_, warning.", dmsScreenId);
1295    }
1296    dms2RsScreenIdMap_[dmsScreenId] = rsScreenId;
1297    if (rsScreenId == SCREEN_ID_INVALID) {
1298        return dmsScreenId;
1299    }
1300    if (rs2DmsScreenIdMap_.find(rsScreenId) != rs2DmsScreenIdMap_.end()) {
1301        WLOGFW("rsScreenId: %{public}" PRIu64" exit in rs2DmsScreenIdMap_, warning.", rsScreenId);
1302    }
1303    rs2DmsScreenIdMap_[rsScreenId] = dmsScreenId;
1304    return dmsScreenId;
1305}
1306
1307bool AbstractScreenController::ScreenIdManager::DeleteScreenId(ScreenId dmsScreenId)
1308{
1309    auto iter = dms2RsScreenIdMap_.find(dmsScreenId);
1310    if (iter == dms2RsScreenIdMap_.end()) {
1311        return false;
1312    }
1313    ScreenId rsScreenId = iter->second;
1314    dms2RsScreenIdMap_.erase(dmsScreenId);
1315    rs2DmsScreenIdMap_.erase(rsScreenId);
1316    return true;
1317}
1318
1319bool AbstractScreenController::ScreenIdManager::HasDmsScreenId(ScreenId dmsScreenId) const
1320{
1321    return dms2RsScreenIdMap_.find(dmsScreenId) != dms2RsScreenIdMap_.end();
1322}
1323
1324bool AbstractScreenController::ScreenIdManager::HasRsScreenId(ScreenId dmsScreenId) const
1325{
1326    return rs2DmsScreenIdMap_.find(dmsScreenId) != rs2DmsScreenIdMap_.end();
1327}
1328
1329bool AbstractScreenController::ScreenIdManager::ConvertToRsScreenId(ScreenId dmsScreenId, ScreenId& rsScreenId) const
1330{
1331    auto iter = dms2RsScreenIdMap_.find(dmsScreenId);
1332    if (iter == dms2RsScreenIdMap_.end()) {
1333        return false;
1334    }
1335    rsScreenId = iter->second;
1336    return true;
1337}
1338
1339ScreenId AbstractScreenController::ScreenIdManager::ConvertToRsScreenId(ScreenId dmsScreenId) const
1340{
1341    ScreenId rsScreenId = SCREEN_ID_INVALID;
1342    ConvertToRsScreenId(dmsScreenId, rsScreenId);
1343    return rsScreenId;
1344}
1345
1346bool AbstractScreenController::ScreenIdManager::ConvertToDmsScreenId(ScreenId rsScreenId, ScreenId& dmsScreenId) const
1347{
1348    auto iter = rs2DmsScreenIdMap_.find(rsScreenId);
1349    if (iter == rs2DmsScreenIdMap_.end()) {
1350        return false;
1351    }
1352    dmsScreenId = iter->second;
1353    return true;
1354}
1355
1356ScreenId AbstractScreenController::ScreenIdManager::ConvertToDmsScreenId(ScreenId rsScreenId) const
1357{
1358    ScreenId dmsScreenId = SCREEN_ID_INVALID;
1359    ConvertToDmsScreenId(rsScreenId, dmsScreenId);
1360    return dmsScreenId;
1361}
1362
1363void AbstractScreenController::NotifyScreenConnected(sptr<ScreenInfo> screenInfo) const
1364{
1365    if (screenInfo == nullptr) {
1366        WLOGFE("NotifyScreenConnected error, screenInfo is nullptr.");
1367        return;
1368    }
1369    auto task = [=] {
1370        WLOGFI("NotifyScreenConnected,  screenId:%{public}" PRIu64"", screenInfo->GetScreenId());
1371        DisplayManagerAgentController::GetInstance().OnScreenConnect(screenInfo);
1372    };
1373    controllerHandler_->PostTask(task, "wms:OnScreenConnect", 0, AppExecFwk::EventQueue::Priority::HIGH);
1374}
1375
1376void AbstractScreenController::NotifyScreenDisconnected(ScreenId screenId) const
1377{
1378    auto task = [=] {
1379        WLOGFI("NotifyScreenDisconnected,  screenId:%{public}" PRIu64"", screenId);
1380        DisplayManagerAgentController::GetInstance().OnScreenDisconnect(screenId);
1381    };
1382    controllerHandler_->PostTask(task, "wms:NotifyScreenDisconnected", 0, AppExecFwk::EventQueue::Priority::HIGH);
1383}
1384
1385void AbstractScreenController::NotifyScreenChanged(sptr<ScreenInfo> screenInfo, ScreenChangeEvent event) const
1386{
1387    if (screenInfo == nullptr) {
1388        WLOGFE("NotifyScreenChanged error, screenInfo is nullptr.");
1389        return;
1390    }
1391    auto task = [=] {
1392        WLOGFI("NotifyScreenChanged,  screenId:%{public}" PRIu64"", screenInfo->GetScreenId());
1393        DisplayManagerAgentController::GetInstance().OnScreenChange(screenInfo, event);
1394    };
1395    controllerHandler_->PostTask(task, "wms:OnScreenChange", 0, AppExecFwk::EventQueue::Priority::HIGH);
1396}
1397
1398void AbstractScreenController::NotifyScreenGroupChanged(
1399    const sptr<ScreenInfo>& screenInfo, ScreenGroupChangeEvent event) const
1400{
1401    if (screenInfo == nullptr) {
1402        WLOGFE("screenInfo is nullptr.");
1403        return;
1404    }
1405    std::string trigger = SysCapUtil::GetClientName();
1406    auto task = [=] {
1407        WLOGFI("screenId:%{public}" PRIu64", trigger:[%{public}s]", screenInfo->GetScreenId(), trigger.c_str());
1408        DisplayManagerAgentController::GetInstance().OnScreenGroupChange(trigger, screenInfo, event);
1409    };
1410    controllerHandler_->PostTask(task, "wms:OnScreenGroupChange", 0, AppExecFwk::EventQueue::Priority::HIGH);
1411}
1412
1413void AbstractScreenController::NotifyScreenGroupChanged(
1414    const std::vector<sptr<ScreenInfo>>& screenInfo, ScreenGroupChangeEvent event) const
1415{
1416    if (screenInfo.empty()) {
1417        return;
1418    }
1419    std::string trigger = SysCapUtil::GetClientName();
1420    auto task = [=] {
1421        WLOGFI("trigger:[%{public}s]", trigger.c_str());
1422        DisplayManagerAgentController::GetInstance().OnScreenGroupChange(trigger, screenInfo, event);
1423    };
1424    controllerHandler_->PostTask(task, "wms:NotifyScreenGroupChanged", 0, AppExecFwk::EventQueue::Priority::HIGH);
1425}
1426
1427bool AbstractScreenController::SetScreenPowerForAll(ScreenPowerState state,
1428    PowerStateChangeReason reason, bool needToNotify)
1429{
1430    WLOGFI("state:%{public}u, reason:%{public}u", state, reason);
1431    auto screenIds = GetAllScreenIds();
1432    if (screenIds.empty()) {
1433        WLOGFI("no screen info");
1434        return false;
1435    }
1436
1437    ScreenPowerStatus status;
1438    switch (state) {
1439        case ScreenPowerState::POWER_ON: {
1440            status = ScreenPowerStatus::POWER_STATUS_ON;
1441            powerState_ = ScreenPowerState::POWER_ON;
1442            break;
1443        }
1444        case ScreenPowerState::POWER_OFF: {
1445            status = ScreenPowerStatus::POWER_STATUS_OFF;
1446            powerState_ = ScreenPowerState::POWER_OFF;
1447            break;
1448        }
1449        default: {
1450            WLOGFW("SetScreenPowerStatus state not support");
1451            return false;
1452        }
1453    }
1454
1455    bool hasSetScreenPower = false;
1456    for (auto screenId : screenIds) {
1457        auto screen = GetAbstractScreen(screenId);
1458        if (screen == nullptr) {
1459            continue;
1460        }
1461        if (screen->type_ != ScreenType::REAL) {
1462            WLOGD("skip virtual screen %{public}" PRIu64"", screen->dmsId_);
1463            continue;
1464        }
1465        RSInterfaces::GetInstance().SetScreenPowerStatus(screen->rsId_, status);
1466        WLOGFI("set screen power status. rsscreen %{public}" PRIu64", status %{public}u", screen->rsId_, status);
1467        hasSetScreenPower = true;
1468    }
1469    WLOGFI("SetScreenPowerStatus end");
1470    if (!hasSetScreenPower) {
1471        WLOGFI("no real screen");
1472        return false;
1473    }
1474    if (needToNotify) {
1475        return DisplayManagerAgentController::GetInstance().NotifyDisplayPowerEvent(
1476            state == ScreenPowerState::POWER_ON ? DisplayPowerEvent::DISPLAY_ON :
1477            DisplayPowerEvent::DISPLAY_OFF, EventStatus::END);
1478    }
1479    return true;
1480}
1481
1482ScreenPowerState AbstractScreenController::GetScreenPower(ScreenId dmsScreenId) const
1483{
1484    uint32_t retryTimes = 0;
1485    bool res = false;
1486    while (retryTimes < MAX_RETRY_NUM) {
1487        {
1488            std::lock_guard<std::recursive_mutex> lock(mutex_);
1489            if (dmsScreenMap_.find(dmsScreenId) != dmsScreenMap_.end()) {
1490                WLOGFI("find screen %{public}" PRIu64"", dmsScreenId);
1491                res = true;
1492                break;
1493            }
1494        }
1495        retryTimes++;
1496        WLOGFW("not find screen, retry %{public}u times", retryTimes);
1497        std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_WAIT_MS));
1498    }
1499    if (retryTimes >= MAX_RETRY_NUM || !res) {
1500        WLOGFE("cannot find screen %{public}" PRIu64"", dmsScreenId);
1501        return ScreenPowerState::INVALID_STATE;
1502    }
1503
1504    ScreenId rsId = ConvertToRsScreenId(dmsScreenId);
1505    auto state = static_cast<ScreenPowerState>(RSInterfaces::GetInstance().GetScreenPowerStatus(rsId));
1506    WLOGFI("GetScreenPower:%{public}u, rsscreen:%{public}" PRIu64".", state, rsId);
1507    return state;
1508}
1509
1510DMError AbstractScreenController::SetVirtualPixelRatio(ScreenId screenId, float virtualPixelRatio)
1511{
1512    WLOGD("set virtual pixel ratio. screen %{public}" PRIu64" virtualPixelRatio %{public}f",
1513        screenId, virtualPixelRatio);
1514    auto screen = GetAbstractScreen(screenId);
1515    if (screen == nullptr) {
1516        WLOGFE("fail to set virtual pixel ratio, cannot find screen %{public}" PRIu64"", screenId);
1517        return DMError::DM_ERROR_NULLPTR;
1518    }
1519    if (screen->isScreenGroup_) {
1520        WLOGE("cannot set virtual pixel ratio to the combination. screen: %{public}" PRIu64"", screenId);
1521        return DMError::DM_ERROR_NULLPTR;
1522    }
1523    if (fabs(screen->virtualPixelRatio_ - virtualPixelRatio) < 1e-6) { // less to 1e-6 mean equal
1524        WLOGE("The density is equivalent to the original value, no update operation is required, aborted.");
1525        return DMError::DM_OK;
1526    }
1527    screen->SetVirtualPixelRatio(virtualPixelRatio);
1528    // Notify rotation event to AbstractDisplayController
1529    if (abstractScreenCallback_ != nullptr) {
1530        abstractScreenCallback_->onChange_(screen, DisplayChangeEvent::DISPLAY_VIRTUAL_PIXEL_RATIO_CHANGED);
1531    }
1532    NotifyScreenChanged(screen->ConvertToScreenInfo(), ScreenChangeEvent::VIRTUAL_PIXEL_RATIO_CHANGED);
1533    return DMError::DM_OK;
1534}
1535} // namespace OHOS::Rosen
1536