1 /*
2 * Copyright (c) 2023 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 #define LOG_TAG "DumpHelper"
16 #include "dump_helper.h"
17
18 #include <securec.h>
19
20 #include "log_print.h"
21 #include "rdb_types.h"
22 #include "runtime_config.h"
23 #include "string_ex.h"
24
25 namespace OHOS::DistributedData {
DumpHelper()26 DumpHelper::DumpHelper()
27 {
28 Handler handlerErrorInfo =
29 std::bind(&DumpHelper::DumpErrorInfo, this, std::placeholders::_1, std::placeholders::_2);
30 Handler handlerHelpInfo = std::bind(&DumpHelper::DumpHelpInfo, this, std::placeholders::_1, std::placeholders::_2);
31 Handler handlerAllInfo = std::bind(&DumpHelper::DumpAllInfo, this, std::placeholders::_1, std::placeholders::_2);
32 RegisterErrorInfo();
33 DumpManager::GetInstance().AddHandler("ERROR_INFO", uintptr_t(this), handlerErrorInfo);
34 RegisterHelpInfo();
35 DumpManager::GetInstance().AddHandler("HELP_INFO", uintptr_t(this), handlerHelpInfo);
36 RegisterAllInfo();
37 DumpManager::GetInstance().AddHandler("ALL_INFO", uintptr_t(this), handlerAllInfo);
38 }
39
GetInstance()40 DumpHelper& DumpHelper::GetInstance()
41 {
42 static DumpHelper instance;
43 return instance;
44 }
45
Dump(int fd,const std::vector<std::string> & args)46 bool DumpHelper::Dump(int fd, const std::vector<std::string> &args)
47 {
48 std::vector<std::shared_ptr<CommandNode>> commands;
49 ParseCommand(args, commands);
50 GetCommandNodes(fd, commands);
51 if (commands.empty()) {
52 return true;
53 }
54 std::shared_ptr<CommandNode> tmpCommandNode;
55 for (auto const& command : commands) {
56 std::map<std::string, std::vector<std::string>> params;
57 tmpCommandNode = command;
58 while (tmpCommandNode != nullptr) {
59 params.emplace(tmpCommandNode->dumpName, tmpCommandNode->param);
60 if (tmpCommandNode->nextNode == nullptr) {
61 for (auto const& handler : tmpCommandNode->handlers) {
62 handler(fd, params);
63 }
64 }
65 tmpCommandNode = tmpCommandNode->nextNode;
66 }
67 }
68 return true;
69 }
70
ParseCommand(const std::vector<std::string> & args,std::vector<std::shared_ptr<CommandNode>> & commands)71 void DumpHelper::ParseCommand(const std::vector<std::string> &args, std::vector<std::shared_ptr<CommandNode>> &commands)
72 {
73 std::shared_ptr<CommandNode> command;
74 std::vector<std::string> tmpDumpNames;
75 if (args.size() == 0) {
76 command = std::make_shared<CommandNode>(GetCommand("ALL_INFO"));
77 commands.emplace_back(command);
78 return;
79 }
80 for (size_t i = 0; i < args.size(); i++) {
81 std::vector<std::string> param;
82 command = std::make_shared<CommandNode>(GetCommand(args[i]));
83 if (!command->IsVoid()) {
84 auto it = find(tmpDumpNames.begin(), tmpDumpNames.end(), command->dumpName);
85 if (it != tmpDumpNames.end()) {
86 ZLOGE("The same command is not allowed");
87 return;
88 }
89 commands.emplace_back(command);
90 tmpDumpNames.emplace_back(command->dumpName);
91 } else {
92 if (commands.empty()) {
93 ZLOGE("Invalid Format");
94 return;
95 }
96 commands.back()->param.emplace_back(args[i]);
97 if (commands.back()->param.size() < commands.back()->minParamsNum ||
98 commands.back()->param.size() > commands.back()->maxParamsNum) {
99 ZLOGE("The number of param criteria is not legal");
100 return;
101 }
102 }
103 }
104 if (commands.size() == 0) {
105 ZLOGE("No command is entered or the command is invalid");
106 return;
107 }
108 }
109
GetCommand(const std::string & name)110 DumpHelper::CommandNode DumpHelper::GetCommand(const std::string &name)
111 {
112 auto config = DumpManager::GetInstance().GetConfig(name);
113 CommandNode command;
114 if (config.IsVoid()) {
115 return command;
116 }
117 command.dumpName = config.dumpName;
118 command.parentNode = config.parentNode;
119 command.childNode = config.childNode;
120 command.minParamsNum = config.minParamsNum;
121 command.maxParamsNum = config.maxParamsNum;
122 command.handlers = DumpManager::GetInstance().GetHandler(name);
123 command.nextNode = nullptr;
124 return command;
125 }
126
GetCommandNodes(int fd,std::vector<std::shared_ptr<CommandNode>> & commands)127 void DumpHelper::GetCommandNodes(int fd, std::vector<std::shared_ptr<CommandNode>> &commands)
128 {
129 for (uint32_t i = 1; i < commands.size();) {
130 bool isAdded = false;
131 if (commands[i]->parentNode.empty()) {
132 for (uint32_t j = 0; j < i; j++) {
133 AddHeadNode(commands[i], commands[j], isAdded);
134 }
135 } else {
136 for (uint32_t j = 0; j < i; j++) {
137 AddNode(commands[i], commands[j], isAdded);
138 }
139 }
140 if (!isAdded) {
141 i++;
142 } else {
143 commands.erase(commands.begin() + i);
144 }
145 }
146 }
147
AddHeadNode(std::shared_ptr<CommandNode> & command,std::shared_ptr<CommandNode> & realHeadNode,bool & isAdded)148 void DumpHelper::AddHeadNode(std::shared_ptr<CommandNode> &command, std::shared_ptr<CommandNode> &realHeadNode,
149 bool &isAdded)
150 {
151 auto tmpCommandNode = command;
152 while (!(tmpCommandNode->childNode.empty())) {
153 if (tmpCommandNode->childNode == realHeadNode->dumpName) {
154 command->nextNode = realHeadNode;
155 realHeadNode = command;
156 isAdded = true;
157 }
158 tmpCommandNode = std::make_shared<CommandNode>(GetCommand(tmpCommandNode->childNode));
159 }
160 }
161
AddNode(std::shared_ptr<CommandNode> & command,std::shared_ptr<CommandNode> & realHeadNode,bool & isAdded)162 void DumpHelper::AddNode(std::shared_ptr<CommandNode> &command, std::shared_ptr<CommandNode> &realHeadNode,
163 bool &isAdded)
164 {
165 auto tmpCommandNode = command;
166 while (!(tmpCommandNode->parentNode.empty())) {
167 auto tmpRealHeadNode = realHeadNode;
168 while (tmpRealHeadNode != nullptr) {
169 if (tmpCommandNode->parentNode == tmpRealHeadNode->dumpName) {
170 command->nextNode = realHeadNode->nextNode;
171 realHeadNode->nextNode = command;
172 isAdded = true;
173 }
174 tmpRealHeadNode = tmpRealHeadNode->nextNode;
175 }
176 tmpCommandNode = std::make_shared<CommandNode>(GetCommand(tmpCommandNode->parentNode));
177 }
178 }
179
RegisterErrorInfo()180 void DumpHelper::RegisterErrorInfo()
181 {
182 DumpManager::Config errorInfoConfig;
183 errorInfoConfig.fullCmd = "--error-info";
184 errorInfoConfig.abbrCmd = "-e";
185 errorInfoConfig.dumpName = "ERROR_INFO";
186 errorInfoConfig.dumpCaption = { "| Display the recent error messages" };
187 DumpManager::GetInstance().AddConfig(errorInfoConfig.dumpName, errorInfoConfig);
188 }
189
DumpErrorInfo(int fd,std::map<std::string,std::vector<std::string>> & params)190 void DumpHelper::DumpErrorInfo(int fd, std::map<std::string, std::vector<std::string>> ¶ms)
191 {
192 std::string info;
193 for (const auto &it : errorInfo_) {
194 std::string errorCode = std::to_string(it.errorCode);
195 errorCode.resize(FORMAT_BLANK_SIZE, FORMAT_BLANK_SPACE);
196 info.append(it.errorTime).append(errorCode).append(it.errorInfo).append("\n");
197 }
198 dprintf(fd,
199 "-------------------------------------RecentError------------------------------------\nDate "
200 " ErrorCode ErrorMessage\n%s\n",
201 info.c_str());
202 }
203
FormatHelpInfo(const std::string & cmd,const std::string & cmdAbbr,const std::string & paraExt,const std::string & info,uint32_t & formatMaxSize)204 std::string DumpHelper::FormatHelpInfo(const std::string &cmd, const std::string &cmdAbbr, const std::string ¶Ext,
205 const std::string &info, uint32_t &formatMaxSize)
206 {
207 std::string formatInfo;
208 formatInfo.append(" ").append(cmdAbbr).append(paraExt).append(", ").append(cmd).append(paraExt);
209 formatInfo.resize(formatMaxSize + FORMAT_FILL_SIZE, FORMAT_BLANK_SPACE);
210 formatInfo.append(info);
211 return formatInfo;
212 }
213
GetFormatMaxSize()214 uint32_t DumpHelper::GetFormatMaxSize()
215 {
216 uint32_t formatMaxSize = 0;
217 auto dumpFactory = DumpManager::GetInstance().LoadConfig();
218 dumpFactory.ForEach([&formatMaxSize](const auto &key, auto &value) {
219 if (key == "ALL_INFO") {
220 return false;
221 }
222 std::string helpInfo;
223 helpInfo.append(" ").append(value.fullCmd).append(", ").append(value.abbrCmd);
224 formatMaxSize = helpInfo.size() > formatMaxSize ? helpInfo.size() : formatMaxSize;
225 std::string helpInfoAdd;
226 if (value.countPrintf == PRINTF_COUNT_2) {
227 helpInfoAdd.append(" ")
228 .append(value.fullCmd)
229 .append(", ")
230 .append(value.abbrCmd)
231 .append(value.infoName)
232 .append(value.infoName);
233 formatMaxSize = helpInfoAdd.size() > formatMaxSize ? helpInfoAdd.size() : formatMaxSize;
234 }
235 return false;
236 });
237 return formatMaxSize;
238 }
239
RegisterHelpInfo()240 void DumpHelper::RegisterHelpInfo()
241 {
242 DumpManager::Config helpInfoConfig;
243 helpInfoConfig.fullCmd = "--help-info";
244 helpInfoConfig.abbrCmd = "-h";
245 helpInfoConfig.dumpName = "HELP_INFO";
246 helpInfoConfig.dumpCaption = { "| Display this help message" };
247 DumpManager::GetInstance().AddConfig(helpInfoConfig.dumpName, helpInfoConfig);
248 }
249
DumpHelpInfo(int fd,std::map<std::string,std::vector<std::string>> & params)250 void DumpHelper::DumpHelpInfo(int fd, std::map<std::string, std::vector<std::string>> ¶ms)
251 {
252 std::string info;
253 uint32_t formatMaxSize = GetFormatMaxSize();
254 auto dumpFactory = DumpManager::GetInstance().LoadConfig();
255 dumpFactory.ForEach([this, &info, &formatMaxSize](const auto &key, auto &value) {
256 if (key == "ALL_INFO") {
257 return false;
258 }
259 info.append(FormatHelpInfo(value.fullCmd, value.abbrCmd, "", value.dumpCaption[0], formatMaxSize)).append("\n");
260 if (value.countPrintf == PRINTF_COUNT_2) {
261 info.append(
262 FormatHelpInfo(value.fullCmd, value.abbrCmd, value.infoName, value.dumpCaption[1], formatMaxSize))
263 .append("\n");
264 }
265 return false;
266 });
267 dprintf(fd,
268 "Usage: hidumper -s 1301 -a <option(s)>\nwhere possible options include:\n%s\nWhen -u/-u <UserId>, -b/-b "
269 "<BundleName> or -s/-s <StoreID> is simultaneously selected,\nwe display the lowest level statistics where -u "
270 "> -b > -s\nand the statistics is filterd by the upper level options\n",
271 info.c_str());
272 }
273
RegisterAllInfo()274 void DumpHelper::RegisterAllInfo()
275 {
276 DumpManager::Config allInfoConfig;
277 allInfoConfig.fullCmd = "--all-info";
278 allInfoConfig.abbrCmd = "-a";
279 allInfoConfig.dumpName = "ALL_INFO";
280 DumpManager::GetInstance().AddConfig(allInfoConfig.dumpName, allInfoConfig);
281 }
282
DumpAllInfo(int fd,std::map<std::string,std::vector<std::string>> & params)283 void DumpHelper::DumpAllInfo(int fd, std::map<std::string, std::vector<std::string>> ¶ms)
284 {
285 auto dumpFactory = DumpManager::GetInstance().LoadConfig();
286 dumpFactory.ForEach([&fd, ¶ms](const auto &key, auto &value) {
287 if (key == "ALL_INFO" || key == "HELP_INFO") {
288 return false;
289 }
290 std::vector<Handler> handlers = DumpManager::GetInstance().GetHandler(key);
291 if (!(handlers.empty())) {
292 for (auto handlerEach : handlers) {
293 handlerEach(fd, params);
294 }
295 }
296 return false;
297 });
298 }
299
AddErrorInfo(int32_t errorCode,const std::string & errorInfo)300 void DumpHelper::AddErrorInfo(int32_t errorCode, const std::string &errorInfo)
301 {
302 ErrorInfo error;
303 error.errorCode = errorCode;
304 error.errorInfo = errorInfo;
305 auto now = std::chrono::system_clock::now();
306 int64_t millSeconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() -
307 (std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000);
308 time_t tt = std::chrono::system_clock::to_time_t(now);
309 auto ptm = localtime(&tt);
310 if (ptm != nullptr) {
311 char date[FORMAT_BLANK_SIZE] = { 0 };
312 auto flag = sprintf_s(date, sizeof(date), "%04d-%02d-%02d %02d:%02d:%02d %03d",
313 (int)ptm->tm_year + DUMP_SYSTEM_START_YEAR, (int)ptm->tm_mon + 1, (int)ptm->tm_mday, (int)ptm->tm_hour,
314 (int)ptm->tm_min, (int)ptm->tm_sec, (int)millSeconds);
315 if (flag < 0) {
316 ZLOGE("get date failed");
317 return;
318 }
319 std::string errorTime = date;
320 errorTime.resize(FORMAT_BLANK_SIZE, FORMAT_BLANK_SPACE);
321 error.errorTime = errorTime;
322 }
323 std::lock_guard<std::mutex> lock(hidumperMutex_);
324 if (errorInfo_.size() + 1 > MAX_RECORED_ERROR) {
325 errorInfo_.pop_front();
326 errorInfo_.push_back(error);
327 } else {
328 errorInfo_.push_back(error);
329 }
330 }
331 } // namespace OHOS::DistributedData
332