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 
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "DisplayDumper"};
32 
33 constexpr int SCREEN_NAME_MAX_LENGTH = 20;
34 const std::string ARG_DUMP_HELP = "-h";
35 const std::string ARG_DUMP_ALL = "-a";
36 const std::string ARG_DUMP_SCREEN = "-s";
37 const std::string ARG_DUMP_DISPLAY = "-d";
38 // set the output width of screen
39 constexpr int W_SCREEN_NAME = 21;
40 constexpr int W_SCREEN_TYPE = 9;
41 constexpr int W_GROUP_TYPE = 8;
42 constexpr int W_DMS_ID = 6;
43 constexpr int W_RS_ID = 21;
44 constexpr int W_ACTIVE_IDX = 10;
45 constexpr int W_VIR_PIXEL_RATIO = 4;
46 constexpr int W_SCREEN_ROTATION = 9;
47 constexpr int W_ORIENTATION = 12;
48 constexpr int W_REQUESTED_ORIENTATION = 19;
49 constexpr int W_NODE_ID = 21;
50 constexpr int W_MIRROR_TYPE = 11;
51 constexpr int W_MIRROR_NODE_ID = 13;
52 // set the output width of display
53 constexpr int W_DISPLAY_ID = 10;
54 constexpr int W_ABSTR_SCREEN_ID = 9;
55 constexpr int W_REFRESH_RATE = 12;
56 constexpr int W_DISPLAY_ROTATION = 9;
57 constexpr int W_DISPLAY_ORIENTATION = 18;
58 constexpr int W_DISPLAY_FREEZE_FLAG = 11;
59 constexpr int W_DISPLAY_OFFSET_X = 5;
60 constexpr int W_DISPLAY_OFFSET_Y = 5;
61 constexpr int W_DISPLAY_WIDTH = 5;
62 constexpr int W_DISPLAY_HEITHT = 5;
63 }
64 
DisplayDumper(const sptr<AbstractDisplayController> & abstractDisplayController,const sptr<AbstractScreenController> & abstractScreenController,std::recursive_mutex & mutex)65 DisplayDumper::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 
Dump(int fd,const std::vector<std::u16string> & args) const72 DMError 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 
ShowHelpInfo(std::string & dumpInfo) const106 void 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 
ShowIllegalArgsInfo(std::string & dumpInfo,DMError errCode) const121 void 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 
DumpInfo(const std::vector<std::string> & args,std::string & dumpInfo) const136 DMError 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 
DumpAllScreenInfo(std::string & dumpInfo) const157 DMError 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 
DumpScreenInfo(const sptr<AbstractScreenGroup> & screenGroup,std::string & dumpInfo) const194 DMError 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 
DumpSpecifiedScreenInfo(ScreenId screenId,std::string & dumpInfo) const216 DMError 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 
DumpAllDisplayInfo(std::string & dumpInfo) const250 DMError 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 
DumpSpecifiedDisplayInfo(DisplayId displayId,std::string & dumpInfo) const272 DMError 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 
IsValidDigitString(const std::string & idStr) const295 bool 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 
TransferTypeToString(ScreenType type) const310 std::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 
GetScreenInfo(const sptr<AbstractScreen> & screen,std::ostringstream & oss) const327 void 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 
GetDisplayInfo(const sptr<AbstractDisplay> & display,std::ostringstream & oss) const358 void 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 }