1/*
2 * Copyright (c) 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 "display_dumper.h"
17
18#include <cinttypes>
19#include <csignal>
20#include <iomanip>
21#include <map>
22#include <sstream>
23#include <string_ex.h>
24#include <unique_fd.h>
25
26#include "window_manager_hilog.h"
27
28namespace OHOS {
29namespace Rosen {
30namespace {
31constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "DisplayDumper"};
32
33constexpr int SCREEN_NAME_MAX_LENGTH = 20;
34const std::string ARG_DUMP_HELP = "-h";
35const std::string ARG_DUMP_ALL = "-a";
36const std::string ARG_DUMP_SCREEN = "-s";
37const std::string ARG_DUMP_DISPLAY = "-d";
38// set the output width of screen
39constexpr int W_SCREEN_NAME = 21;
40constexpr int W_SCREEN_TYPE = 9;
41constexpr int W_GROUP_TYPE = 8;
42constexpr int W_DMS_ID = 6;
43constexpr int W_RS_ID = 21;
44constexpr int W_ACTIVE_IDX = 10;
45constexpr int W_VIR_PIXEL_RATIO = 4;
46constexpr int W_SCREEN_ROTATION = 9;
47constexpr int W_ORIENTATION = 12;
48constexpr int W_REQUESTED_ORIENTATION = 19;
49constexpr int W_NODE_ID = 21;
50constexpr int W_MIRROR_TYPE = 11;
51constexpr int W_MIRROR_NODE_ID = 13;
52// set the output width of display
53constexpr int W_DISPLAY_ID = 10;
54constexpr int W_ABSTR_SCREEN_ID = 9;
55constexpr int W_REFRESH_RATE = 12;
56constexpr int W_DISPLAY_ROTATION = 9;
57constexpr int W_DISPLAY_ORIENTATION = 18;
58constexpr int W_DISPLAY_FREEZE_FLAG = 11;
59constexpr int W_DISPLAY_OFFSET_X = 5;
60constexpr int W_DISPLAY_OFFSET_Y = 5;
61constexpr int W_DISPLAY_WIDTH = 5;
62constexpr int W_DISPLAY_HEITHT = 5;
63}
64
65DisplayDumper::DisplayDumper(const sptr<AbstractDisplayController>& abstractDisplayController,
66    const sptr<AbstractScreenController>& abstractScreenController, std::recursive_mutex& mutex)
67    : abstractDisplayController_(abstractDisplayController), abstractScreenController_(abstractScreenController),
68    mutex_(mutex)
69{
70}
71
72DMError DisplayDumper::Dump(int fd, const std::vector<std::u16string>& args) const
73{
74    WLOGFI("Dump begin fd: %{public}d", fd);
75    if (fd < 0) {
76        return DMError::DM_ERROR_INVALID_PARAM;
77    }
78    (void) signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE crash
79    UniqueFd ufd = UniqueFd(fd); // auto close
80    fd = ufd.Get();
81    std::vector<std::string> params;
82    for (auto& arg : args) {
83        params.emplace_back(Str16ToStr8(arg));
84    }
85
86    std::string dumpInfo;
87    if (params.empty()) {
88        ShowHelpInfo(dumpInfo);
89    } else if (params.size() == 1 && params[0] == ARG_DUMP_HELP) { // 1: params num
90        ShowHelpInfo(dumpInfo);
91    } else {
92        DMError errCode = DumpInfo(params, dumpInfo);
93        if (errCode != DMError::DM_OK) {
94            ShowIllegalArgsInfo(dumpInfo, errCode);
95        }
96    }
97    int ret = dprintf(fd, "%s\n", dumpInfo.c_str());
98    if (ret < 0) {
99        WLOGFE("dprintf error");
100        return DMError::DM_ERROR_UNKNOWN;
101    }
102    WLOGFI("Dump end");
103    return DMError::DM_OK;
104}
105
106void DisplayDumper::ShowHelpInfo(std::string& dumpInfo) const
107{
108    dumpInfo.append("Usage:\n")
109        .append(" -h                          ")
110        .append("|help text for the tool\n")
111        .append(" -s -a                       ")
112        .append("|dump all screen information in the system\n")
113        .append(" -d -a                       ")
114        .append("|dump all display information in the system\n")
115        .append(" -s {screen id}              ")
116        .append("|dump specified screen information\n")
117        .append(" -d {display id}             ")
118        .append("|dump specified display information\n");
119}
120
121void DisplayDumper::ShowIllegalArgsInfo(std::string& dumpInfo, DMError errCode) const
122{
123    switch (errCode) {
124        case DMError::DM_ERROR_INVALID_PARAM:
125            dumpInfo.append("The arguments are illegal and you can enter '-h' for help.");
126            break;
127        case DMError::DM_ERROR_NULLPTR:
128            dumpInfo.append("The screen or display is invalid, ")
129                .append("you can enter '-s -a' or '-d -a' to get valid screen or display id.");
130            break;
131        default:
132            break;
133    }
134}
135
136DMError DisplayDumper::DumpInfo(const std::vector<std::string>& args, std::string& dumpInfo) const
137{
138    if (args.size() != 2) { // 2: params num
139        return DMError::DM_ERROR_INVALID_PARAM;
140    }
141
142    if (args[0] == ARG_DUMP_SCREEN && args[1] == ARG_DUMP_ALL) {
143        return DumpAllScreenInfo(dumpInfo);
144    } else if (args[0] == ARG_DUMP_DISPLAY && args[1] == ARG_DUMP_ALL) {
145        return DumpAllDisplayInfo(dumpInfo);
146    } else if (args[0] == ARG_DUMP_SCREEN && IsValidDigitString(args[1])) {
147        ScreenId screenId = std::stoull(args[1]);
148        return DumpSpecifiedScreenInfo(screenId, dumpInfo);
149    } else if (args[0] == ARG_DUMP_DISPLAY && IsValidDigitString(args[1])) {
150        DisplayId displayId = std::stoull(args[1]);
151        return DumpSpecifiedDisplayInfo(displayId, dumpInfo);
152    } else {
153        return DMError::DM_ERROR_INVALID_PARAM;
154    }
155}
156
157DMError DisplayDumper::DumpAllScreenInfo(std::string& dumpInfo) const
158{
159    std::map<ScreenId, sptr<AbstractScreenGroup>> screenGroups;
160    std::vector<ScreenId> screenIds = abstractScreenController_->GetAllScreenIds();
161    std::ostringstream oss;
162    oss << "--------------------------------------Free Screen"
163        << "--------------------------------------"
164        << std::endl;
165    oss << "ScreenName           Type     IsGroup DmsId RsId                 ActiveIdx VPR Rotation Orientation "
166        << "RequestOrientation NodeId               IsMirrored MirrorNodeId"
167        << std::endl;
168    std::lock_guard<std::recursive_mutex> lock(mutex_);
169    for (ScreenId screenId : screenIds) {
170        auto screen = abstractScreenController_->GetAbstractScreen(screenId);
171        if (screen == nullptr) {
172            WLOGFE("screen is null");
173            return DMError::DM_ERROR_NULLPTR;
174        }
175        if (SCREEN_ID_INVALID == screen->groupDmsId_ || screen->isScreenGroup_) {
176            GetScreenInfo(screen, oss);
177        }
178        if (screen->isScreenGroup_) {
179            auto screenGroup = abstractScreenController_->GetAbstractScreenGroup(screenId);
180            screenGroups.insert(std::make_pair(screenId, screenGroup));
181        }
182    }
183    oss << "total screen num: " << screenIds.size() << std::endl;
184    dumpInfo.append(oss.str());
185    for (auto it = screenGroups.begin(); it != screenGroups.end(); it++) {
186        DMError ret = DumpScreenInfo(it->second, dumpInfo);
187        if (ret != DMError::DM_OK) {
188            return ret;
189        }
190    }
191    return DMError::DM_OK;
192}
193
194DMError DisplayDumper::DumpScreenInfo(const sptr<AbstractScreenGroup>& screenGroup, std::string& dumpInfo) const
195{
196    if (screenGroup == nullptr) {
197        WLOGFE("screenGroup is null");
198        return DMError::DM_ERROR_NULLPTR;
199    }
200    std::ostringstream oss;
201    oss << "-------------------------------------ScreenGroup " << screenGroup->dmsId_
202        << "-------------------------------------"
203        << std::endl;
204    oss << "ScreenName           Type     IsGroup DmsId RsId                 "
205        << "ActiveIdx VPR Rotation Orientation "
206        << "RequestOrientation NodeId               IsMirrored MirrorNodeId"
207        << std::endl;
208    auto childrenScreen = screenGroup->GetChildren();
209    for (auto screen : childrenScreen) {
210        GetScreenInfo(screen, oss);
211    }
212    dumpInfo.append(oss.str());
213    return DMError::DM_OK;
214}
215
216DMError DisplayDumper::DumpSpecifiedScreenInfo(ScreenId screenId, std::string& dumpInfo) const
217{
218    auto screen = abstractScreenController_->GetAbstractScreen(screenId);
219    if (screen == nullptr) {
220        WLOGFE("screen is null");
221        return DMError::DM_ERROR_NULLPTR;
222    }
223
224    const std::string& name = screen->GetScreenName();
225    const std::string& screenName = name.size() <= SCREEN_NAME_MAX_LENGTH ?
226        name : name.substr(0, SCREEN_NAME_MAX_LENGTH);
227    std::string isGroup = screen->isScreenGroup_ ? "true" : "false";
228    std::string screenType = TransferTypeToString(screen->type_);
229    std::string isMirrored = screen->rSDisplayNodeConfig_.isMirrored ? "true" : "false";
230    NodeId nodeId = (screen->rsDisplayNode_ == nullptr) ? SCREEN_ID_INVALID : screen->rsDisplayNode_->GetId();
231    std::ostringstream oss;
232    oss << "ScreenName: " << screenName << std::endl;
233    oss << "Type: " << screenType << std::endl;
234    oss << "IsGroup: " << isGroup << std::endl;
235    oss << "DmsId: " << screen->dmsId_ << std::endl;
236    oss << "RsId: " << screen->rsId_ << std::endl;
237    oss << "GroupDmsId: " << screen->groupDmsId_ << std::endl;
238    oss << "ActiveIdx: " << screen->activeIdx_ << std::endl;
239    oss << "VPR: " << screen->virtualPixelRatio_ << std::endl;
240    oss << "Rotation: " << static_cast<uint32_t>(screen->rotation_) << std::endl;
241    oss << "Orientation: " << static_cast<uint32_t>(screen->orientation_) << std::endl;
242    oss << "RequestOrientation: " << static_cast<uint32_t>(screen->screenRequestedOrientation_) << std::endl;
243    oss << "NodeId: " << nodeId << std::endl;
244    oss << "IsMirrored: " << isMirrored << std::endl;
245    oss << "MirrorNodeId: " << screen->rSDisplayNodeConfig_.mirrorNodeId << std::endl;
246    dumpInfo.append(oss.str());
247    return DMError::DM_OK;
248}
249
250DMError DisplayDumper::DumpAllDisplayInfo(std::string& dumpInfo) const
251{
252    std::vector<DisplayId> displayIds = abstractDisplayController_->GetAllDisplayIds();
253    std::ostringstream oss;
254    oss << "--------------------------------------Display Info"
255        << "--------------------------------------"
256        << std::endl;
257    oss << "DisplayId ScreenId RefreshRate VPR Rotation Orientation DisplayOrientation FreezeFlag [ x   y   w   h   ]"
258        << std::endl;
259    std::lock_guard<std::recursive_mutex> lock(mutex_);
260    for (DisplayId displayId : displayIds) {
261        auto display = abstractDisplayController_->GetAbstractDisplay(displayId);
262        if (display == nullptr) {
263            WLOGFE("display is null");
264            return DMError::DM_ERROR_NULLPTR;
265        }
266        GetDisplayInfo(display, oss);
267    }
268    dumpInfo.append(oss.str());
269    return DMError::DM_OK;
270}
271
272DMError DisplayDumper::DumpSpecifiedDisplayInfo(DisplayId displayId, std::string& dumpInfo) const
273{
274    auto display = abstractDisplayController_->GetAbstractDisplay(displayId);
275    if (display == nullptr) {
276        WLOGFE("display is null");
277        return DMError::DM_ERROR_NULLPTR;
278    }
279    std::ostringstream oss;
280    oss << "DisplayId: " << display->GetId() << std::endl;
281    oss << "ScreenId: " << display->GetAbstractScreenId() << std::endl;
282    oss << "RefreshRate: " << display->GetRefreshRate() << std::endl;
283    oss << "VPR: " << display->GetVirtualPixelRatio() << std::endl;
284    oss << "Rotation: " << static_cast<uint32_t>(display->GetRotation()) << std::endl;
285    oss << "Orientation: " << static_cast<uint32_t>(display->GetOrientation()) << std::endl;
286    oss << "DisplayOrientation: " << static_cast<uint32_t>(display->GetDisplayOrientation()) << std::endl;
287    oss << "FreezeFlag: " << static_cast<uint32_t>(display->GetFreezeFlag()) << std::endl;
288    oss << "DisplayRect: " << "[ "
289        << display->GetOffsetX() << ", " << display->GetOffsetY() << ", "
290        << display->GetWidth() << ", " << display->GetHeight() << " ]" << std::endl;
291    dumpInfo.append(oss.str());
292    return DMError::DM_OK;
293}
294
295bool DisplayDumper::IsValidDigitString(const std::string& idStr) const
296{
297    if (idStr.empty()) {
298        return false;
299    }
300    for (char ch : idStr) {
301        if ((ch >= '0' && ch <= '9')) {
302            continue;
303        }
304        WLOGFE("invalid id");
305        return false;
306    }
307    return true;
308}
309
310std::string DisplayDumper::TransferTypeToString(ScreenType type) const
311{
312    std::string screenType;
313    switch (type) {
314        case ScreenType::REAL:
315            screenType = "REAL";
316            break;
317        case ScreenType::VIRTUAL:
318            screenType = "VIRTUAL";
319            break;
320        default:
321            screenType = "UNDEFINED";
322            break;
323    }
324    return screenType;
325}
326
327void DisplayDumper::GetScreenInfo(const sptr<AbstractScreen>& screen, std::ostringstream& oss) const
328{
329    if (screen == nullptr) {
330        WLOGFE("screen is null");
331        return;
332    }
333
334    const std::string& name = screen->GetScreenName();
335    const std::string& screenName = name.size() <= SCREEN_NAME_MAX_LENGTH ?
336        name : name.substr(0, SCREEN_NAME_MAX_LENGTH);
337    std::string isGroup = screen->isScreenGroup_ ? "true" : "false";
338    std::string screenType = TransferTypeToString(screen->type_);
339    std::string isMirrored = screen->rSDisplayNodeConfig_.isMirrored ? "true" : "false";
340    NodeId nodeId = (screen->rsDisplayNode_ == nullptr) ? SCREEN_ID_INVALID : screen->rsDisplayNode_->GetId();
341    // std::setw is used to set the output width and different width values are set to keep the format aligned.
342    oss << std::left << std::setw(W_SCREEN_NAME) << screenName
343        << std::left << std::setw(W_SCREEN_TYPE) << screenType
344        << std::left << std::setw(W_GROUP_TYPE) << isGroup
345        << std::left << std::setw(W_DMS_ID) << screen->dmsId_
346        << std::left << std::setw(W_RS_ID) << screen->rsId_
347        << std::left << std::setw(W_ACTIVE_IDX) << screen->activeIdx_
348        << std::left << std::setw(W_VIR_PIXEL_RATIO) << screen->virtualPixelRatio_
349        << std::left << std::setw(W_SCREEN_ROTATION) << static_cast<uint32_t>(screen->rotation_)
350        << std::left << std::setw(W_ORIENTATION) << static_cast<uint32_t>(screen->orientation_)
351        << std::left << std::setw(W_REQUESTED_ORIENTATION) << static_cast<uint32_t>(screen->screenRequestedOrientation_)
352        << std::left << std::setw(W_NODE_ID) << nodeId
353        << std::left << std::setw(W_MIRROR_TYPE) << isMirrored
354        << std::left << std::setw(W_MIRROR_NODE_ID) << screen->rSDisplayNodeConfig_.mirrorNodeId
355        << std::endl;
356}
357
358void DisplayDumper::GetDisplayInfo(const sptr<AbstractDisplay>& display, std::ostringstream& oss) const
359{
360    if (display == nullptr) {
361        WLOGFE("display is null");
362        return;
363    }
364    // std::setw is used to set the output width and different width values are set to keep the format aligned.
365    oss << std::left << std::setw(W_DISPLAY_ID) << display->GetId()
366        << std::left << std::setw(W_ABSTR_SCREEN_ID) << display->GetAbstractScreenId()
367        << std::left << std::setw(W_REFRESH_RATE) << display->GetRefreshRate()
368        << std::left << std::setw(W_VIR_PIXEL_RATIO) << display->GetVirtualPixelRatio()
369        << std::left << std::setw(W_DISPLAY_ROTATION) << static_cast<uint32_t>(display->GetRotation())
370        << std::left << std::setw(W_ORIENTATION) << static_cast<uint32_t>(display->GetOrientation())
371        << std::left << std::setw(W_DISPLAY_ORIENTATION) << static_cast<uint32_t>(display->GetDisplayOrientation())
372        << std::left << std::setw(W_DISPLAY_FREEZE_FLAG) << static_cast<uint32_t>(display->GetFreezeFlag())
373        << "[ "
374        << std::left << std::setw(W_DISPLAY_OFFSET_X) << display->GetOffsetX()
375        << std::left << std::setw(W_DISPLAY_OFFSET_Y) << display->GetOffsetY()
376        << std::left << std::setw(W_DISPLAY_WIDTH) << display->GetWidth()
377        << std::left << std::setw(W_DISPLAY_HEITHT) << display->GetHeight()
378        << "]"
379        << std::endl;
380}
381}
382}