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