• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>> &params)
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 &paraExt,
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>> &params)
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>> &params)
283 {
284     auto dumpFactory = DumpManager::GetInstance().LoadConfig();
285     dumpFactory.ForEach([&fd, &params](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