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 "window_dumper.h"
17 
18 #include <cinttypes>
19 #include <csignal>
20 #include <iomanip>
21 #include <map>
22 #include <sstream>
23 
24 #include "display_manager_service_inner.h"
25 #include "string_ex.h"
26 #include "unique_fd.h"
27 #include "display_group_info.h"
28 #include "window_manager_hilog.h"
29 #include "window_manager_service.h"
30 #include "wm_common.h"
31 
32 namespace OHOS {
33 namespace Rosen {
34 namespace {
35 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Dumper"};
36 
37 constexpr int WINDOW_NAME_MAX_LENGTH = 20;
38 const std::string ARG_DUMP_HELP = "-h";
39 const std::string ARG_DUMP_ALL = "-a";
40 const std::string ARG_DUMP_WINDOW = "-w";
41 }
42 
Dump(int fd,const std::vector<std::u16string> & args)43 WMError WindowDumper::Dump(int fd, const std::vector<std::u16string>& args)
44 {
45     WLOGI("Dump begin fd: %{public}d", fd);
46     if (fd < 0) {
47         return WMError::WM_ERROR_INVALID_PARAM;
48     }
49     (void) signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE crash
50     UniqueFd ufd = UniqueFd(fd); // auto close
51     fd = ufd.Get();
52     std::vector<std::string> params;
53     for (auto& arg : args) {
54         params.emplace_back(Str16ToStr8(arg));
55     }
56 
57     std::string dumpInfo;
58     if (params.empty()) {
59         ShowHelpInfo(dumpInfo);
60     } else if (params.size() == 1 && params[0] == ARG_DUMP_HELP) { // 1: params num
61         ShowHelpInfo(dumpInfo);
62     } else {
63         WMError errCode = DumpWindowInfo(params, dumpInfo);
64         if (errCode != WMError::WM_OK) {
65             ShowIllegalArgsInfo(dumpInfo, errCode);
66         }
67     }
68     int ret = dprintf(fd, "%s\n", dumpInfo.c_str());
69     if (ret < 0) {
70         WLOGFE("dprintf error");
71         return WMError::WM_ERROR_INVALID_OPERATION;
72     }
73     WLOGI("Dump end");
74     return WMError::WM_OK;
75 }
76 
DumpScreenGroupWindowInfo(ScreenId screenGroupId,const sptr<WindowNodeContainer> & windowNodeContainer,std::string & dumpInfo)77 WMError WindowDumper::DumpScreenGroupWindowInfo(ScreenId screenGroupId,
78     const sptr<WindowNodeContainer>& windowNodeContainer, std::string& dumpInfo)
79 {
80     if (windowNodeContainer == nullptr) {
81         WLOGFE("windowNodeContainer is null");
82         return WMError::WM_ERROR_NULLPTR;
83     }
84     std::ostringstream oss;
85     oss << "-------------------------------------ScreenGroup " << screenGroupId
86         << "-------------------------------------"
87         << std::endl;
88     oss << "WindowName           DisplayId Pid     WinId Type Mode Flag ZOrd Orientation [ x    y    w    h    ]"
89         << std::endl;
90     std::vector<sptr<WindowNode>> windowNodes;
91     windowNodeContainer->TraverseContainer(windowNodes);
92     int zOrder = static_cast<int32_t>(windowNodes.size());
93     windowRoot_->GetBackgroundNodesByScreenId(screenGroupId, windowNodes);
94     for (auto& windowNode : windowNodes) {
95         if (zOrder < 0) {
96             zOrder = 0;
97         } else if (zOrder == 0) {
98             oss << "---------------------------------------------------------------------------------------"
99                 << std::endl;
100         }
101         if (windowNode == nullptr) {
102             --zOrder;
103             break;
104         }
105         --zOrder;
106         AppendWindowNodeInfo(windowNode, zOrder, oss);
107     }
108     oss << "Focus window: " << windowNodeContainer->GetFocusWindow() << std::endl;
109     oss << "total window num: " << windowRoot_->GetTotalWindowNum()<< std::endl;
110     dumpInfo.append(oss.str());
111     return WMError::WM_OK;
112 }
113 
AppendWindowNodeInfo(const sptr<WindowNode> & windowNode,int zOrder,std::ostringstream & oss)114 void WindowDumper::AppendWindowNodeInfo(const sptr<WindowNode>& windowNode, int zOrder, std::ostringstream& oss)
115 {
116     Rect rect = windowNode->GetWindowRect();
117     const std::string& windowName = windowNode->GetWindowName().size() <= WINDOW_NAME_MAX_LENGTH ?
118         windowNode->GetWindowName() : windowNode->GetWindowName().substr(0, WINDOW_NAME_MAX_LENGTH);
119     // std::setw is used to set the output width and different width values are set to keep the format aligned.
120     oss << std::left << std::setw(21) << windowName                                                   // 21 is width
121         << std::left << std::setw(10) << windowNode->GetDisplayId()                                   // 10 is width
122         << std::left << std::setw(8) << windowNode->GetCallingPid()                                   // 8 is width
123         << std::left << std::setw(6) << windowNode->GetWindowId()                                     // 6 is width
124         << std::left << std::setw(5) << static_cast<uint32_t>(windowNode->GetWindowType())            // 5 is width
125         << std::left << std::setw(5) << static_cast<uint32_t>(windowNode->GetWindowMode())            // 5 is width
126         << std::left << std::setw(5) << windowNode->GetWindowFlags()                                  // 5 is width
127         << std::left << std::setw(5) << zOrder                                                        // 5 is width
128         << std::left << std::setw(12) << static_cast<uint32_t>(windowNode->GetRequestedOrientation()) // 12 is width
129         << "[ "
130         << std::left << std::setw(5) << rect.posX_     // 5 is width
131         << std::left << std::setw(5) << rect.posY_     // 5 is width
132         << std::left << std::setw(5) << rect.width_    // 5 is width
133         << std::left << std::setw(5) << rect.height_   // 5 is width
134         << "]"
135         << std::endl;
136 }
137 
DumpAllWindowInfo(std::string & dumpInfo)138 WMError WindowDumper::DumpAllWindowInfo(std::string& dumpInfo)
139 {
140     std::map<ScreenId, sptr<WindowNodeContainer>> windowNodeContainers;
141     std::vector<DisplayId> displayIds = DisplayGroupInfo::GetInstance().GetAllDisplayIds();
142     for (DisplayId displayId : displayIds) {
143         auto windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId);
144         if (!windowNodeContainer) {
145             return WMError::WM_ERROR_NULLPTR;
146         }
147         ScreenId screenGroupId = DisplayManagerServiceInner::GetInstance().GetScreenGroupIdByDisplayId(displayId);
148         if (windowNodeContainers.count(screenGroupId) == 0) {
149             windowNodeContainers.insert(std::make_pair(screenGroupId, windowNodeContainer));
150         }
151     }
152     for (auto it = windowNodeContainers.begin(); it != windowNodeContainers.end(); it++) {
153         WMError ret = DumpScreenGroupWindowInfo(it->first, it->second, dumpInfo);
154         if (ret != WMError::WM_OK) {
155             return ret;
156         }
157     }
158     return WMError::WM_OK;
159 }
160 
IsValidDigitString(const std::string & windowIdStr)161 bool WindowDumper::IsValidDigitString(const std::string& windowIdStr)
162 {
163     if (windowIdStr.empty()) {
164         return false;
165     }
166     for (char ch : windowIdStr) {
167         if ((ch >= '0' && ch <= '9')) {
168             continue;
169         }
170         WLOGFE("invalid window id");
171         return false;
172     }
173     return true;
174 }
175 
DumpSpecifiedWindowInfo(uint32_t windowId,const std::vector<std::string> & params,std::string & dumpInfo)176 WMError WindowDumper::DumpSpecifiedWindowInfo(uint32_t windowId, const std::vector<std::string>& params,
177     std::string& dumpInfo)
178 {
179     auto node = windowRoot_->GetWindowNode(windowId);
180     if (node == nullptr) {
181         WLOGFE("invalid window");
182         return WMError::WM_ERROR_NULLPTR;
183     }
184     std::ostringstream oss;
185     AppendSpecifiedWindowNodeInfo(node, oss);
186     dumpInfo.append(oss.str());
187     if (node->GetWindowToken() != nullptr) {
188         std::vector<std::string> resetParams;
189         resetParams.assign(params.begin() + 2, params.end()); // 2: params num
190         if (resetParams.empty()) {
191             WLOGI("do not dump ui info");
192             return WMError::WM_OK;
193         }
194         dumpInfoFuture_.ResetLock({});
195         node->GetWindowToken()->DumpInfo(resetParams);
196         auto infos = dumpInfoFuture_.GetResult(2000); // 2000: wait for 2000ms
197         for (auto& info: infos) {
198             dumpInfo.append(info).append("\n");
199         }
200     }
201     return WMError::WM_OK;
202 }
203 
AppendSpecifiedWindowNodeInfo(const sptr<WindowNode> & node,std::ostringstream & oss)204 void WindowDumper::AppendSpecifiedWindowNodeInfo(const sptr<WindowNode>& node, std::ostringstream& oss)
205 {
206     Rect rect = node->GetWindowRect();
207     std::string isShown_ = node->startingWindowShown_ ? "true" : "false";
208     std::string visibilityState = std::to_string(node->GetVisibilityState());
209     std::string Focusable = node->GetWindowProperty()->GetFocusable() ? "true" : "false";
210     std::string DecoStatus = node->GetWindowProperty()->GetDecoStatus() ? "true" : "false";
211     bool PrivacyMode = node->GetWindowProperty()->GetSystemPrivacyMode() ||
212         node->GetWindowProperty()->GetPrivacyMode();
213     bool isSnapshotSkip = node->GetWindowProperty()->GetSnapshotSkip();
214     std::string isPrivacyMode = PrivacyMode ? "true" : "false";
215     oss << "WindowName: " << node->GetWindowName()  << std::endl;
216     oss << "DisplayId: " << node->GetDisplayId() << std::endl;
217     oss << "WinId: " << node->GetWindowId() << std::endl;
218     oss << "Pid: " << node->GetCallingPid() << std::endl;
219     oss << "Type: " << static_cast<uint32_t>(node->GetWindowType()) << std::endl;
220     oss << "Mode: " << static_cast<uint32_t>(node->GetWindowMode()) << std::endl;
221     oss << "Flag: " << node->GetWindowFlags() << std::endl;
222     oss << "Orientation: " << static_cast<uint32_t>(node->GetRequestedOrientation()) << std::endl;
223     oss << "IsStartingWindow: " << isShown_ << std::endl;
224     oss << "FirstFrameCallbackCalled: " << node->firstFrameAvailable_ << std::endl;
225     oss << "VisibilityState: " << visibilityState << std::endl;
226     oss << "Focusable: "  << Focusable << std::endl;
227     oss << "DecoStatus: "  << DecoStatus << std::endl;
228     oss << "IsPrivacyMode: "  << isPrivacyMode << std::endl;
229     oss << "isSnapshotSkip: "  << isSnapshotSkip << std::endl;
230     oss << "WindowRect: " << "[ "
231         << rect.posX_ << ", " << rect.posY_ << ", " << rect.width_ << ", " << rect.height_
232         << " ]" << std::endl;
233     oss << "TouchHotAreas: ";
234     std::vector<Rect> touchHotAreas;
235     node->GetTouchHotAreas(touchHotAreas);
236     int index = 0;
237     for (const auto& area : touchHotAreas) {
238         oss << "[ " << area.posX_ << ", " << area.posY_ << ", " << area.width_ << ", " << area.height_ << " ]";
239         index++;
240         if (index < static_cast<int32_t>(touchHotAreas.size())) {
241             oss <<", ";
242         }
243     }
244     oss << std::endl;
245 }
246 
DumpWindowInfo(const std::vector<std::string> & args,std::string & dumpInfo)247 WMError WindowDumper::DumpWindowInfo(const std::vector<std::string>& args, std::string& dumpInfo)
248 {
249     if (args.empty()) {
250         return WMError::WM_ERROR_INVALID_PARAM;
251     }
252     if (args.size() == 1 && args[0] == ARG_DUMP_ALL) { // 1: params num
253         return DumpAllWindowInfo(dumpInfo);
254     } else if (args.size() >= 2 && args[0] == ARG_DUMP_WINDOW && IsValidDigitString(args[1])) { // 2: params num
255         uint32_t windowId = std::stoul(args[1]);
256         return DumpSpecifiedWindowInfo(windowId, args, dumpInfo);
257     } else {
258         return WMError::WM_ERROR_INVALID_PARAM;
259     }
260 }
261 
ShowIllegalArgsInfo(std::string & dumpInfo,WMError errCode)262 void WindowDumper::ShowIllegalArgsInfo(std::string& dumpInfo, WMError errCode)
263 {
264     switch (errCode) {
265         case WMError::WM_ERROR_INVALID_PARAM:
266             dumpInfo.append("The arguments are illegal and you can enter '-h' for help.");
267             break;
268         case WMError::WM_ERROR_NULLPTR:
269             dumpInfo.append("The window is invalid, you can enter '-a' to get valid window id.");
270             break;
271         default:
272             break;
273     }
274 }
275 
ShowHelpInfo(std::string & dumpInfo)276 void WindowDumper::ShowHelpInfo(std::string& dumpInfo)
277 {
278     dumpInfo.append("Usage:\n")
279         .append(" -h                             ")
280         .append("|help text for the tool\n")
281         .append(" -a                             ")
282         .append("|dump all window information in the system\n")
283         .append(" -w {window id} [ArkUI Option]  ")
284         .append("|dump specified window information\n")
285         .append(" ------------------------------------[ArkUI Option]------------------------------------ \n");
286     ShowAceDumpHelp(dumpInfo);
287 }
288 
ShowAceDumpHelp(std::string & dumpInfo)289 void WindowDumper::ShowAceDumpHelp(std::string& dumpInfo)
290 {
291     auto node = windowRoot_->GetWindowForDumpAceHelpInfo();
292     if (node == nullptr) {
293         WLOGFE("invalid window");
294         return;
295     }
296     if (node->GetWindowToken() != nullptr) {
297         std::vector<std::string> params;
298         params.emplace_back(ARG_DUMP_HELP);
299         dumpInfoFuture_.ResetLock({});
300         node->GetWindowToken()->DumpInfo(params);
301         auto infos = dumpInfoFuture_.GetResult(2000); // 2000: wait for 2000ms
302         for (auto& info: infos) {
303             dumpInfo.append(info).append("\n");
304         }
305     }
306 }
307 }
308 }