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 Rect rect = windowNode->GetWindowRect();
106 const std::string& windowName = windowNode->GetWindowName().size() <= WINDOW_NAME_MAX_LENGTH ?
107 windowNode->GetWindowName() : windowNode->GetWindowName().substr(0, WINDOW_NAME_MAX_LENGTH);
108 // std::setw is used to set the output width and different width values are set to keep the format aligned.
109 oss << std::left << std::setw(21) << windowName
110 << std::left << std::setw(10) << windowNode->GetDisplayId()
111 << std::left << std::setw(8) << windowNode->GetCallingPid()
112 << std::left << std::setw(6) << windowNode->GetWindowId()
113 << std::left << std::setw(5) << static_cast<uint32_t>(windowNode->GetWindowType())
114 << std::left << std::setw(5) << static_cast<uint32_t>(windowNode->GetWindowMode())
115 << std::left << std::setw(5) << windowNode->GetWindowFlags()
116 << std::left << std::setw(5) << --zOrder
117 << std::left << std::setw(12) << static_cast<uint32_t>(windowNode->GetRequestedOrientation())
118 << "[ "
119 << std::left << std::setw(5) << rect.posX_
120 << std::left << std::setw(5) << rect.posY_
121 << std::left << std::setw(5) << rect.width_
122 << std::left << std::setw(5) << rect.height_
123 << "]"
124 << std::endl;
125 }
126 oss << "Focus window: " << windowNodeContainer->GetFocusWindow() << std::endl;
127 oss << "total window num: " << windowRoot_->GetTotalWindowNum()<< std::endl;
128 dumpInfo.append(oss.str());
129 return WMError::WM_OK;
130 }
131
DumpAllWindowInfo(std::string & dumpInfo)132 WMError WindowDumper::DumpAllWindowInfo(std::string& dumpInfo)
133 {
134 std::map<ScreenId, sptr<WindowNodeContainer>> windowNodeContainers;
135 std::vector<DisplayId> displayIds = DisplayGroupInfo::GetInstance().GetAllDisplayIds();
136 for (DisplayId displayId : displayIds) {
137 auto windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId);
138 if (!windowNodeContainer) {
139 return WMError::WM_ERROR_NULLPTR;
140 }
141 ScreenId screenGroupId = DisplayManagerServiceInner::GetInstance().GetScreenGroupIdByDisplayId(displayId);
142 if (windowNodeContainers.count(screenGroupId) == 0) {
143 windowNodeContainers.insert(std::make_pair(screenGroupId, windowNodeContainer));
144 }
145 }
146 for (auto it = windowNodeContainers.begin(); it != windowNodeContainers.end(); it++) {
147 WMError ret = DumpScreenGroupWindowInfo(it->first, it->second, dumpInfo);
148 if (ret != WMError::WM_OK) {
149 return ret;
150 }
151 }
152 return WMError::WM_OK;
153 }
154
IsValidDigitString(const std::string & windowIdStr)155 bool WindowDumper::IsValidDigitString(const std::string& windowIdStr)
156 {
157 if (windowIdStr.empty()) {
158 return false;
159 }
160 for (char ch : windowIdStr) {
161 if ((ch >= '0' && ch <= '9')) {
162 continue;
163 }
164 WLOGFE("invalid window id");
165 return false;
166 }
167 return true;
168 }
169
DumpSpecifiedWindowInfo(uint32_t windowId,const std::vector<std::string> & params,std::string & dumpInfo)170 WMError WindowDumper::DumpSpecifiedWindowInfo(uint32_t windowId, const std::vector<std::string>& params,
171 std::string& dumpInfo)
172 {
173 auto node = windowRoot_->GetWindowNode(windowId);
174 if (node == nullptr) {
175 WLOGFE("invalid window");
176 return WMError::WM_ERROR_NULLPTR;
177 }
178 Rect rect = node->GetWindowRect();
179 std::string isShown_ = node->startingWindowShown_ ? "true" : "false";
180 std::string visibilityState = std::to_string(node->GetVisibilityState());
181 std::string Focusable = node->GetWindowProperty()->GetFocusable() ? "true" : "false";
182 std::string DecoStatus = node->GetWindowProperty()->GetDecoStatus() ? "true" : "false";
183 bool PrivacyMode = node->GetWindowProperty()->GetSystemPrivacyMode() ||
184 node->GetWindowProperty()->GetPrivacyMode();
185 bool isSnapshotSkip = node->GetWindowProperty()->GetSnapshotSkip();
186 std::string isPrivacyMode = PrivacyMode ? "true" : "false";
187 std::ostringstream oss;
188 oss << "WindowName: " << node->GetWindowName() << std::endl;
189 oss << "DisplayId: " << node->GetDisplayId() << std::endl;
190 oss << "WinId: " << node->GetWindowId() << std::endl;
191 oss << "Pid: " << node->GetCallingPid() << std::endl;
192 oss << "Type: " << static_cast<uint32_t>(node->GetWindowType()) << std::endl;
193 oss << "Mode: " << static_cast<uint32_t>(node->GetWindowMode()) << std::endl;
194 oss << "Flag: " << node->GetWindowFlags() << std::endl;
195 oss << "Orientation: " << static_cast<uint32_t>(node->GetRequestedOrientation()) << std::endl;
196 oss << "IsStartingWindow: " << isShown_ << std::endl;
197 oss << "FirstFrameCallbackCalled: " << node->firstFrameAvailable_ << std::endl;
198 oss << "VisibilityState: " << visibilityState << std::endl;
199 oss << "Focusable: " << Focusable << std::endl;
200 oss << "DecoStatus: " << DecoStatus << std::endl;
201 oss << "IsPrivacyMode: " << isPrivacyMode << std::endl;
202 oss << "isSnapshotSkip: " << isSnapshotSkip << std::endl;
203 oss << "WindowRect: " << "[ "
204 << rect.posX_ << ", " << rect.posY_ << ", " << rect.width_ << ", " << rect.height_
205 << " ]" << std::endl;
206 oss << "TouchHotAreas: ";
207 std::vector<Rect> touchHotAreas;
208 node->GetTouchHotAreas(touchHotAreas);
209 int index = 0;
210 for (const auto& area : touchHotAreas) {
211 oss << "[ " << area.posX_ << ", " << area.posY_ << ", " << area.width_ << ", " << area.height_ << " ]";
212 index++;
213 if (index < static_cast<int32_t>(touchHotAreas.size())) {
214 oss <<", ";
215 }
216 }
217 oss << std::endl;
218 dumpInfo.append(oss.str());
219 if (node->GetWindowToken() != nullptr) {
220 std::vector<std::string> resetParams;
221 resetParams.assign(params.begin() + 2, params.end()); // 2: params num
222 if (resetParams.empty()) {
223 WLOGI("do not dump ui info");
224 return WMError::WM_OK;
225 }
226 dumpInfoFuture_.ResetLock({});
227 node->GetWindowToken()->DumpInfo(resetParams);
228 auto infos = dumpInfoFuture_.GetResult(2000); // 2000: wait for 2000ms
229 for (auto& info: infos) {
230 dumpInfo.append(info).append("\n");
231 }
232 }
233 return WMError::WM_OK;
234 }
235
DumpWindowInfo(const std::vector<std::string> & args,std::string & dumpInfo)236 WMError WindowDumper::DumpWindowInfo(const std::vector<std::string>& args, std::string& dumpInfo)
237 {
238 if (args.empty()) {
239 return WMError::WM_ERROR_INVALID_PARAM;
240 }
241 if (args.size() == 1 && args[0] == ARG_DUMP_ALL) { // 1: params num
242 return DumpAllWindowInfo(dumpInfo);
243 } else if (args.size() >= 2 && args[0] == ARG_DUMP_WINDOW && IsValidDigitString(args[1])) { // 2: params num
244 uint32_t windowId = std::stoul(args[1]);
245 return DumpSpecifiedWindowInfo(windowId, args, dumpInfo);
246 } else {
247 return WMError::WM_ERROR_INVALID_PARAM;
248 }
249 }
250
ShowIllegalArgsInfo(std::string & dumpInfo,WMError errCode)251 void WindowDumper::ShowIllegalArgsInfo(std::string& dumpInfo, WMError errCode)
252 {
253 switch (errCode) {
254 case WMError::WM_ERROR_INVALID_PARAM:
255 dumpInfo.append("The arguments are illegal and you can enter '-h' for help.");
256 break;
257 case WMError::WM_ERROR_NULLPTR:
258 dumpInfo.append("The window is invalid, you can enter '-a' to get valid window id.");
259 break;
260 default:
261 break;
262 }
263 }
264
ShowHelpInfo(std::string & dumpInfo)265 void WindowDumper::ShowHelpInfo(std::string& dumpInfo)
266 {
267 dumpInfo.append("Usage:\n")
268 .append(" -h ")
269 .append("|help text for the tool\n")
270 .append(" -a ")
271 .append("|dump all window information in the system\n")
272 .append(" -w {window id} [ArkUI Option] ")
273 .append("|dump specified window information\n")
274 .append(" ------------------------------------[ArkUI Option]------------------------------------ \n");
275 ShowAceDumpHelp(dumpInfo);
276 }
277
ShowAceDumpHelp(std::string & dumpInfo)278 void WindowDumper::ShowAceDumpHelp(std::string& dumpInfo)
279 {
280 auto node = windowRoot_->GetWindowForDumpAceHelpInfo();
281 if (node == nullptr) {
282 WLOGFE("invalid window");
283 return;
284 }
285 if (node->GetWindowToken() != nullptr) {
286 std::vector<std::string> params;
287 params.emplace_back(ARG_DUMP_HELP);
288 dumpInfoFuture_.ResetLock({});
289 node->GetWindowToken()->DumpInfo(params);
290 auto infos = dumpInfoFuture_.GetResult(2000); // 2000: wait for 2000ms
291 for (auto& info: infos) {
292 dumpInfo.append(info).append("\n");
293 }
294 }
295 }
296 }
297 }