1 /*
2  * Copyright (c) 2021-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 #include "manager/dump_implement.h"
16 #include <ipc_skeleton.h>
17 #include "iservice_registry.h"
18 #include "hilog_wrapper.h"
19 #include "util/config_utils.h"
20 #include "factory/cpu_dumper_factory.h"
21 #include "factory/file_dumper_factory.h"
22 #include "factory/env_param_dumper_factory.h"
23 #include "factory/cmd_dumper_factory.h"
24 #include "factory/api_dumper_factory.h"
25 #include "factory/properties_dumper_factory.h"
26 #include "factory/sa_dumper_factory.h"
27 #include "factory/list_dumper_factory.h"
28 #include "factory/version_dumper_factory.h"
29 #include "factory/column_rows_filter_factory.h"
30 #include "factory/file_format_dump_filter_factory.h"
31 #include "factory/fd_output_factory.h"
32 #include "factory/zip_output_factory.h"
33 #include "factory/dumper_group_factory.h"
34 #include "factory/memory_dumper_factory.h"
35 #include "factory/jsheap_memory_dumper_factory.h"
36 #include "factory/traffic_dumper_factory.h"
37 #include "factory/ipc_stat_dumper_factory.h"
38 #include "dump_utils.h"
39 #include "string_ex.h"
40 #include "file_ex.h"
41 #include "util/string_utils.h"
42 #include "common/dumper_constant.h"
43 #include "securec.h"
44 #include "parameters.h"
45 #include "parameter.h"
46 #ifdef HIDUMPER_HIVIEWDFX_HISYSEVENT_ENABLE
47 #include "hisysevent.h"
48 #endif
49 
50 namespace OHOS {
51 namespace HiviewDFX {
52 const int HIVIEW_UID = 1201;
DumpImplement()53 DumpImplement::DumpImplement()
54 {
55     AddExecutorFactoryToMap();
56 }
57 
~DumpImplement()58 DumpImplement::~DumpImplement()
59 {
60 }
61 
AddExecutorFactoryToMap()62 void DumpImplement::AddExecutorFactoryToMap()
63 {
64     ptrExecutorFactoryMap_ = std::make_shared<ExecutorFactoryMap>();
65 #ifdef HIDUMPER_HIVIEWDFX_HIVIEW_ENABLE
66     ptrExecutorFactoryMap_->insert(std::make_pair(DumperConstant::CPU_DUMPER, std::make_shared<CPUDumperFactory>()));
67 #endif
68     ptrExecutorFactoryMap_->insert(std::make_pair(DumperConstant::FILE_DUMPER, std::make_shared<FileDumperFactory>()));
69     ptrExecutorFactoryMap_->insert(
70         std::make_pair(DumperConstant::ENV_PARAM_DUMPER, std::make_shared<EnvParamDumperFactory>()));
71     ptrExecutorFactoryMap_->insert(std::make_pair(DumperConstant::CMD_DUMPER, std::make_shared<CMDDumperFactory>()));
72     ptrExecutorFactoryMap_->insert(std::make_pair(DumperConstant::API_DUMPER, std::make_shared<APIDumperFactory>()));
73     ptrExecutorFactoryMap_->insert(
74         std::make_pair(DumperConstant::PROPERTIES_DUMPER, std::make_shared<PropertiesDumperFactory>()));
75     ptrExecutorFactoryMap_->insert(std::make_pair(DumperConstant::LIST_DUMPER, std::make_shared<ListDumperFactory>()));
76     ptrExecutorFactoryMap_->insert(
77         std::make_pair(DumperConstant::VERSION_DUMPER, std::make_shared<VersionDumperFactory>()));
78     ptrExecutorFactoryMap_->insert(std::make_pair(DumperConstant::SA_DUMPER, std::make_shared<SADumperFactory>()));
79     ptrExecutorFactoryMap_->insert(
80         std::make_pair(DumperConstant::COLUMN_ROWS_FILTER, std::make_shared<ColumnRowsFilterFactory>()));
81     ptrExecutorFactoryMap_->insert(
82         std::make_pair(DumperConstant::FILE_FORMAT_DUMP_FILTER, std::make_shared<FileFormatDumpFilterFactory>()));
83     ptrExecutorFactoryMap_->insert(std::make_pair(DumperConstant::GROUP, std::make_shared<DumperGroupFactory>()));
84     ptrExecutorFactoryMap_->insert(
85         std::make_pair(DumperConstant::MEMORY_DUMPER, std::make_shared<MemoryDumperFactory>()));
86     ptrExecutorFactoryMap_->insert(
87         std::make_pair(DumperConstant::JSHEAP_MEMORY_DUMPER, std::make_shared<JsHeapMemoryDumperFactory>()));
88     ptrExecutorFactoryMap_->insert(
89         std::make_pair(DumperConstant::TRAFFIC_DUMPER, std::make_shared<TrafficDumperFactory>()));
90     ptrExecutorFactoryMap_->insert(
91         std::make_pair(DumperConstant::IPC_STAT_DUMPER, std::make_shared<IPCStatDumperFactory>()));
92 }
93 
Main(int argc, char *argv[], const std::shared_ptr<RawParam> &reqCtl)94 DumpStatus DumpImplement::Main(int argc, char *argv[], const std::shared_ptr<RawParam> &reqCtl)
95 {
96     std::shared_ptr<DumperParameter> ptrDumperParameter = std::make_shared<DumperParameter>();
97     ptrDumperParameter->setClientCallback(reqCtl);
98     ptrDumperParameter->SetPid(reqCtl->GetPid());
99     ptrDumperParameter->SetUid(reqCtl->GetUid());
100     DumpStatus ret = CmdParse(argc, argv, ptrDumperParameter);
101     if (ret != DumpStatus::DUMP_OK) {
102         DUMPER_HILOGE(MODULE_COMMON, "Parse cmd FAIL!!!");
103         return ret;
104     }
105 
106     ConfigUtils::GetDumperConfigs(ptrDumperParameter);
107     std::vector<std::shared_ptr<DumpCfg>> &configs = ptrDumperParameter->GetExecutorConfigList();
108     DUMPER_HILOGD(MODULE_COMMON, "debug|Main configs size is %{public}zu", configs.size());
109     if (configs.size() == 0) {
110         DUMPER_HILOGE(MODULE_COMMON, "Executor config list is empty, so can not dump.");
111         return DumpStatus::DUMP_FAIL;
112     }
113     bool isZip = ptrDumperParameter->GetOpts().IsDumpZip();
114     std::vector<std::shared_ptr<HidumperExecutor>> hidumperExecutors;
115     setExecutorList(hidumperExecutors, configs, isZip);
116 
117     if (hidumperExecutors.empty()) {
118         DUMPER_HILOGE(MODULE_COMMON, "Executor list is empty, so dump fail.");
119         return DumpStatus::DUMP_FAIL;
120     }
121 
122     reqCtl->SetProgressEnabled(isZip);
123     if (isZip) {
124         reqCtl->SetTitle(",The result is:" + path_);
125     } else {
126         reqCtl->SetTitle("");
127     }
128     HidumperExecutor::StringMatrix dumpDatas = std::make_shared<std::vector<std::vector<std::string>>>();
129     ret = DumpDatas(hidumperExecutors, ptrDumperParameter, dumpDatas);
130     if (ret != DumpStatus::DUMP_OK) {
131         DUMPER_HILOGE(MODULE_COMMON, "DUMP FAIL!!!");
132         return ret;
133     }
134     return DumpStatus::DUMP_OK;
135 }
136 
ProcessDumpOptions(int clientPid, std::shared_ptr<DumperParameter> &dumpParameter, DumperOpts &opts)137 void DumpImplement::ProcessDumpOptions(int clientPid, std::shared_ptr<DumperParameter> &dumpParameter, DumperOpts &opts)
138 {
139     if (IsHidumperClientProcess(clientPid)) {
140         opts.AddSelectAll();
141         opts.isAppendix_ = true;
142     } else {
143         opts.isDumpCpuFreq_ = true;
144 #ifdef HIDUMPER_HIVIEWDFX_HIVIEW_ENABLE
145         opts.isDumpCpuUsage_ = true;
146         opts.cpuUsagePid_ = clientPid;
147 #endif
148         opts.isDumpMem_ = true;
149         opts.memPid_ = clientPid;
150     }
151     dumpParameter->SetPid(clientPid);
152 }
153 
CmdParse(int argc, char *argv[], std::shared_ptr<DumperParameter> &dumpParameter)154 DumpStatus DumpImplement::CmdParse(int argc, char *argv[], std::shared_ptr<DumperParameter> &dumpParameter)
155 {
156 #ifdef HIDUMPER_HIVIEWDFX_HISYSEVENT_ENABLE
157     std::stringstream dumpCmdSs;
158 #endif
159     if (argc > ARG_MAX_COUNT) {
160         LOG_ERR("too many arguments(%d), limit size %d.\n", argc, ARG_MAX_COUNT);
161         return DumpStatus::DUMP_FAIL;
162     }
163     for (int i = 0; i < argc; i++) {
164         if (argv[i] == nullptr) {
165             LOG_ERR("argument(%d) is null.\n", i);
166             return DumpStatus::DUMP_FAIL;
167         }
168         size_t len = strlen(argv[i]);
169         if (len == 0) {
170             LOG_ERR("argument(%d) is empty.\n", i);
171             return DumpStatus::DUMP_FAIL;
172         }
173         if (len > SINGLE_ARG_MAXLEN) {
174             LOG_ERR("too long argument(%d), limit size %d.\n", i, SINGLE_ARG_MAXLEN);
175             return DumpStatus::DUMP_FAIL;
176         }
177 #ifdef HIDUMPER_HIVIEWDFX_HISYSEVENT_ENABLE
178         dumpCmdSs << argv[i] << " ";
179 #endif
180     }
181     DumperOpts opts;
182     DumpStatus status = CmdParseWithParameter(dumpParameter, argc, argv, opts);
183     if (status != DumpStatus::DUMP_OK)
184         return status;
185     if (!opts.IsSelectAny()) { // 注:hidumper不添加任何参数时,dump全部内容;IPC方式dump时,仅dump 当前进程的CPU和memory情况
186         int clientPid = dumpParameter->GetPid(); // to be set value
187         ProcessDumpOptions(clientPid, dumpParameter, opts);
188     }
189 #ifdef HIDUMPER_HIVIEWDFX_HISYSEVENT_ENABLE
190     if (dumpCmdSs.str().length() > 0) {
191         ReportCmdUsage(opts, dumpCmdSs.str().substr(0, dumpCmdSs.str().length() - 1));
192     }
193 #endif
194     dumpParameter->SetOpts(opts);
195     return DumpStatus::DUMP_OK;
196 }
197 
IsHidumperClientProcess(int pid)198 bool DumpImplement::IsHidumperClientProcess(int pid)
199 {
200     bool ret = false;
201     std::string procName;
202     if (DumpCommonUtils::GetProcessNameByPid(pid, procName)) {
203         ret = (procName.find("hidumper") != std::string::npos);
204     }
205     DUMPER_HILOGD(
206         MODULE_COMMON, "debug|ret=%{public}d, pid=%{public}d, procName=%{public}s", ret, pid, procName.c_str());
207     return ret;
208 }
209 
CmdParseWithParameter(int argc, char *argv[], DumperOpts &opts_)210 DumpStatus DumpImplement::CmdParseWithParameter(int argc, char *argv[], DumperOpts &opts_)
211 {
212     optind = 0; // reset getopt_long
213     opterr = 0; // getopt not show error info
214     const char optStr[] = "-hlcsa:epvT:";
215     bool loop = true;
216     while (loop) {
217         int optionIndex = 0;
218         static struct option longOptions[] = {{"cpufreq", no_argument, 0, 0},
219 #ifdef HIDUMPER_HIVIEWDFX_HIVIEW_ENABLE
220                                               {"cpuusage", optional_argument, 0, 0},
221 #endif
222                                               {"mem", optional_argument, 0, 0},
223                                               {"net", no_argument, 0, 0},
224                                               {"storage", no_argument, 0, 0},
225                                               {"zip", no_argument, 0, 0},
226                                               {"mem-smaps", required_argument, 0, 0},
227                                               {"mem-jsheap", required_argument, 0, 0},
228                                               {"gc", no_argument, 0, 0},
229                                               {"leakobj", no_argument, 0, 0},
230                                               {"ipc", optional_argument, 0, 0},
231                                               {"start-stat", no_argument, 0, 0},
232                                               {"stop-stat", no_argument, 0, 0},
233                                               {"stat", no_argument, 0, 0},
234                                               {0, 0, 0, 0}};
235 
236         int c = getopt_long(argc, argv, optStr, longOptions, &optionIndex);
237         if (c == -1) {
238             break;
239         } else if (c == 0) {
240             DumpStatus status = ParseLongCmdOption(argc, opts_, longOptions, optionIndex, argv);
241             if (status != DumpStatus::DUMP_OK) {
242                 return status;
243             }
244         } else if (c == 'h') {
245             CmdHelp();
246             return DumpStatus::DUMP_HELP;
247         } else if (c == '?') {
248             CheckIncorrectCmdOption(optStr, argv);
249             return DumpStatus::DUMP_INVALID_ARG;
250         } else {
251             DumpStatus status = ParseShortCmdOption(c, opts_, argc, argv);
252             if (status != DumpStatus::DUMP_OK) {
253                 return status;
254             }
255         }
256     }
257     DumpStatus status = CheckProcessAlive(opts_);
258     if (status != DumpStatus::DUMP_OK) {
259         return status;
260     }
261     if (!CheckDumpPermission(opts_)) {
262         CmdHelp();
263         return DumpStatus::DUMP_HELP;
264     }
265     RemoveDuplicateString(opts_);
266     return DumpStatus::DUMP_OK;
267 }
268 
CmdParseWithParameter(std::shared_ptr<DumperParameter> &dumpParameter, int argc, char *argv[], DumperOpts &opts)269 DumpStatus DumpImplement::CmdParseWithParameter(std::shared_ptr<DumperParameter> &dumpParameter, int argc, char *argv[],
270                                                 DumperOpts &opts)
271 {
272     DUMPER_HILOGD(MODULE_COMMON, "enter|");
273     std::lock_guard<std::mutex> lock(mutexCmdLock_); // lock for optind value safe
274     ptrReqCtl_ = dumpParameter->getClientCallback();
275     DumpStatus ret = CmdParseWithParameter(argc, argv, opts);
276     if (ret == DumpStatus::DUMP_OK) {
277         std::string errorStr;
278         if (!opts.CheckOptions(errorStr)) {
279             SendErrorMessage(invalidError_ + errorStr);
280             ret = DumpStatus::DUMP_INVALID_ARG;
281         }
282     }
283     ptrReqCtl_ = nullptr;
284     DUMPER_HILOGD(MODULE_COMMON, "leave|ret=%{public}d", ret);
285     return ret;
286 }
287 
SetCmdParameter(int argc, char *argv[], DumperOpts &opts_)288 DumpStatus DumpImplement::SetCmdParameter(int argc, char *argv[], DumperOpts &opts_)
289 {
290     DumpStatus status = DumpStatus::DUMP_OK;
291     DUMPER_HILOGD(MODULE_COMMON,
292                   "debug|SetCmdParameter optind is %{public}d"
293                   " argc is  %{public}d",
294                   optind,
295                   argc);
296     if (optind > 1 && optind <= argc) {
297         bool hiviewEnable = false;
298 #ifdef HIDUMPER_HIVIEWDFX_HIVIEW_ENABLE
299         hiviewEnable = true;
300 #endif
301         if (hiviewEnable &&
302             StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "--cpuusage")) {
303             status = SetCmdIntegerParameter(argv[optind - 1], opts_.cpuUsagePid_);
304         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "--log")) {
305             opts_.logArgs_.push_back(argv[optind - 1]);
306         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "--mem")) {
307             status = SetCmdIntegerParameter(argv[optind - 1], opts_.memPid_);
308         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "--net")) {
309             status = SetCmdIntegerParameter(argv[optind - 1], opts_.netPid_);
310         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "--storage")) {
311             status = SetCmdIntegerParameter(argv[optind - 1], opts_.storagePid_);
312         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "-c")) {
313             opts_.systemArgs_.push_back(argv[optind - 1]);
314         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "-p")) {
315             status = SetCmdIntegerParameter(argv[optind - 1], opts_.processPid_);
316         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "-T")) {
317             status = SetCmdIntegerParameter(argv[optind - 1], opts_.threadId_);
318         } else if (IsSADumperOption(argv)) {
319             opts_.abilitieNames_.push_back(argv[optind - 1]);
320         } else if (StringUtils::GetInstance().IsSameStr(argv[optind - ARG_INDEX_OFFSET_LAST_OPTION], "--ipc")) {
321             status = SetCmdIntegerParameter(argv[optind - 1], opts_.ipcStatPid_);
322         } else {
323             std::string optionName = RemoveCharacterFromStr(argv[optind - 1], '-');
324             std::string errorStr = unrecognizedError_ + optionName;
325             SendErrorMessage(errorStr);
326             return DumpStatus::DUMP_FAIL;
327         }
328     }
329     return status;
330 }
331 
GetTime()332 std::string DumpImplement::GetTime()
333 {
334     struct timeval curTime;
335     gettimeofday(&curTime, nullptr);
336     int milli = curTime.tv_usec / 1000;
337 
338     char buffer[80] = {0};
339     struct tm nowTime;
340     localtime_r(&curTime.tv_sec, &nowTime);
341     (void)strftime(buffer, sizeof(buffer), "%Y%m%d-%H%M%S", &nowTime);
342 
343     char currentTime[84] = {0};
344     if (sprintf_s(currentTime, sizeof(currentTime), "%s-%03d", buffer, milli) < 0) {
345         return "";
346     };
347 
348     return currentTime;
349 }
350 
ParseSubLongCmdOption(int argc, DumperOpts &opts_, const struct option longOptions[], const int &optionIndex, char *argv[])351 bool DumpImplement::ParseSubLongCmdOption(int argc, DumperOpts &opts_, const struct option longOptions[],
352                                           const int &optionIndex, char *argv[])
353 {
354     bool hiviewEnable = false;
355 #ifdef HIDUMPER_HIVIEWDFX_HIVIEW_ENABLE
356     hiviewEnable = true;
357 #endif
358     if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "cpufreq")) {
359         opts_.isDumpCpuFreq_ = true;
360     } else if (hiviewEnable && StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "cpuusage")) {
361         opts_.isDumpCpuUsage_ = true;
362     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "log")) {
363         opts_.isDumpLog_ = true;
364     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "mem")) {
365         opts_.isDumpMem_ = true;
366     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "net")) {
367         opts_.isDumpNet_ = true;
368     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "storage")) {
369         opts_.isDumpStorage_ = true;
370     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "zip")) {
371         path_ = ZIP_FOLDER + GetTime() + ".zip";
372         opts_.path_ = path_;
373     } else {
374         return false;
375     }
376 
377     return true;
378 }
379 
ParseLongCmdOption(int argc, DumperOpts &opts_, const struct option longOptions[], const int &optionIndex, char *argv[])380 DumpStatus DumpImplement::ParseLongCmdOption(int argc, DumperOpts &opts_, const struct option longOptions[],
381                                              const int &optionIndex, char *argv[])
382 {
383     if (ParseSubLongCmdOption(argc, opts_, longOptions, optionIndex, argv)) {
384         return DumpStatus::DUMP_OK;
385     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "mem-smaps")) {
386         opts_.isShowSmaps_ = true;
387         DumpStatus status;
388         if (ARG_INDEX_OFFSET_LAST_OPTION < 0 || ARG_INDEX_OFFSET_LAST_OPTION >= argc) {
389             status = DumpStatus::DUMP_FAIL;
390         } else {
391             status = SetCmdIntegerParameter(argv[ARG_INDEX_OFFSET_LAST_OPTION], opts_.memPid_);
392         }
393         if (status != DumpStatus::DUMP_OK) {
394             return status;
395         }
396     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "mem-jsheap")) {
397         opts_.isDumpJsHeapMem_ = true;
398         if (optarg != nullptr) {
399             return SetCmdIntegerParameter(optarg, opts_.dumpJsHeapMemPid_);
400         } else {
401             DUMPER_HILOGE(MODULE_COMMON, "mem-jsheap nullptr");
402             return DumpStatus::DUMP_FAIL;
403         }
404     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "gc")) {
405         opts_.isDumpJsHeapMemGC_ = true;
406     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "leakobj")) {
407         opts_.isDumpJsHeapLeakobj_ = true;
408     } else if (StringUtils::GetInstance().IsSameStr(longOptions[optionIndex].name, "ipc")) {
409         opts_.isDumpIpc_ = true;
410         if (IPC_STAT_ARG_NUMS != argc) {
411             DUMPER_HILOGE(MODULE_COMMON, "ipc stat cmd args invalid");
412             SendErrorMessage("ipc stat cmd args invalid\n");
413             CmdHelp();
414             return DumpStatus::DUMP_HELP;
415         }
416     } else if (SetIpcStatParam(opts_, longOptions[optionIndex].name)) {
417         if (!opts_.isDumpIpc_) {
418             DUMPER_HILOGE(MODULE_COMMON, "ipc stat param invalid");
419             SendErrorMessage("ipc stat cmd args invalid\n");
420             CmdHelp();
421             return DumpStatus::DUMP_HELP;
422         }
423     } else {
424         DUMPER_HILOGE(MODULE_COMMON, "ParseLongCmdOption %{public}s", longOptions[optionIndex].name);
425     }
426     return DumpStatus::DUMP_OK;
427 }
428 
SetIpcStatParam(DumperOpts &opts_, const std::string& param)429 bool DumpImplement::SetIpcStatParam(DumperOpts &opts_, const std::string& param)
430 {
431     if (StringUtils::GetInstance().IsSameStr(param, "start-stat")) {
432         opts_.isDumpIpcStartStat_ = true;
433     } else if (StringUtils::GetInstance().IsSameStr(param, "stop-stat")) {
434         opts_.isDumpIpcStopStat_ = true;
435     } else if (StringUtils::GetInstance().IsSameStr(param, "stat")) {
436         opts_.isDumpIpcStat_ = true;
437     } else {
438         return false;
439     }
440     return true;
441 }
442 
ParseCmdOptionForA(DumperOpts &opts_, char *argv[])443 DumpStatus DumpImplement::ParseCmdOptionForA(DumperOpts &opts_, char *argv[])
444 {
445     if (opts_.isDumpSystemAbility_) {
446         SplitStr(optarg, " ", opts_.abilitieArgs_);
447     } else if (opts_.isDumpIpc_) {
448         opts_.isDumpAllIpc_ = true;
449         if (optarg != nullptr) {
450             std::vector<std::string> ipcStatParams;
451             SplitStr(optarg, "--", ipcStatParams);
452             if (ipcStatParams.empty()) {
453                 SendErrorMessage(invalidError_);
454                 return DumpStatus::DUMP_INVALID_ARG;
455             }
456             if (!SetIpcStatParam(opts_, ipcStatParams[0])) {
457                 SendErrorMessage(invalidError_ + ":" + ipcStatParams[0]);
458                 return DumpStatus::DUMP_INVALID_ARG;
459             }
460         }
461     } else {
462         std::string optionName = RemoveCharacterFromStr(argv[optind - 1], '-');
463         std::string errorStr = unrecognizedError_ + optionName;
464         SendErrorMessage(errorStr);
465         return DumpStatus::DUMP_INVALID_ARG;
466     }
467     return DumpStatus::DUMP_OK;
468 }
469 
ParseShortCmdOption(int c, DumperOpts &opts_, int argc, char *argv[])470 DumpStatus DumpImplement::ParseShortCmdOption(int c, DumperOpts &opts_, int argc, char *argv[])
471 {
472     switch (c) {
473         case 'a': {
474             DumpStatus status = ParseCmdOptionForA(opts_, argv);
475             if (status != DumpStatus::DUMP_OK) {
476                 return status;
477             }
478             break;
479         }
480         case 'c':
481             opts_.isDumpSystem_ = true;
482             break;
483         case 'e':
484             opts_.isFaultLog_ = true;
485             break;
486         case 'l':
487             opts_.isDumpList_ = true;
488             break;
489         case 's':
490             opts_.isDumpSystemAbility_ = true;
491             break;
492         case 'p':
493             opts_.isDumpProcesses_ = true;
494             break;
495         case 'v':
496             opts_.isShowSmapsInfo_ = true;
497             break;
498         default: {
499             DumpStatus status = SetCmdParameter(argc, argv, opts_);
500             if (status != DumpStatus::DUMP_OK) {
501                 return status;
502             }
503             break;
504         }
505     }
506     return DumpStatus::DUMP_OK;
507 }
508 
SetCmdIntegerParameter(const std::string &str, int &value)509 DumpStatus DumpImplement::SetCmdIntegerParameter(const std::string &str, int &value)
510 {
511     if (!IsNumericStr(str)) {
512         DUMPER_HILOGE(MODULE_COMMON, "Invalid string arg %{public}s", str.c_str());
513         std::string errorStr = invalidError_ + str;
514         SendErrorMessage(errorStr);
515         return DumpStatus::DUMP_INVALID_ARG;
516     }
517     return StrToInt(str, value) ? DumpStatus::DUMP_OK : DumpStatus::DUMP_FAIL;
518 }
519 
CmdHelp()520 void DumpImplement::CmdHelp()
521 {
522     const std::string commonUsageStr =
523         "usage:\n"
524         "  -h                          |help text for the tool\n"
525         "  -lc                         |a list of system information clusters\n"
526         "  -ls                         |a list of system abilities\n"
527         "  -c                          |all system information clusters\n"
528         "  -c [base system]            |system information clusters labeled \"base\" and \"system\"\n"
529         "  -s                          |all system abilities\n"
530         "  -s [SA0 SA1]                |system abilities labeled \"SA0\" and \"SA1\"\n"
531         "  -s [SA] -a ['-h']           |system ability labeled \"SA\" with arguments \"-h\" specified\n"
532         "  -e                          |faultlogs of crash history\n"
533         "  --net [pid]                 |dump network information; if pid is specified,"
534         " dump traffic usage of specified pid\n"
535         "  --storage [pid]             |dump storage information; if pid is specified, dump /proc/pid/io\n"
536         "  -p                          |processes information, include list and infromation of processes"
537         " and threads\n"
538         "  -p [pid]                    |dump threads under pid, includes smap, block channel,"
539         " execute time, mountinfo\n"
540         "  --cpufreq                   |dump real CPU frequency of each core\n"
541         "  --mem [pid]                 |dump memory usage of total; dump memory usage of specified"
542         " pid if pid was specified\n"
543         "  --zip                       |compress output to /data/log/hidumper\n"
544         "  --mem-smaps pid [-v]        |display statistic in /proc/pid/smaps, use -v specify more details\n"
545         "  --mem-jsheap pid [-T tid] [--gc] [--leakobj]  |triggerGC, dumpHeapSnapshot and dumpLeakList"
546         " under pid and tid\n"
547         "  --ipc pid ARG               |ipc load statistic; pid must be specified or set to -a dump all"
548         " processes. ARG must be one of --start-stat | --stop-stat | --stat\n";
549 
550 #ifdef HIDUMPER_HIVIEWDFX_HIVIEW_ENABLE
551     const std::string extendedUsageStr =
552         "  --cpuusage [pid]            |dump cpu usage by processes and category; if PID is specified,"
553         " dump category usage of specified pid\n";
554 
555     std::string str = commonUsageStr + extendedUsageStr;
556 #else
557     std::string str = commonUsageStr;
558 #endif
559 
560     if (ptrReqCtl_ == nullptr) {
561         return;
562     }
563     int rawParamFd = ptrReqCtl_->GetOutputFd();
564     if (rawParamFd < 0) {
565         return;
566     }
567     SaveStringToFd(rawParamFd, str.c_str());
568 }
569 
setExecutorList(std::vector<std::shared_ptr<HidumperExecutor>> &executors, const std::vector<std::shared_ptr<DumpCfg>> &configs, bool isZip)570 void DumpImplement::setExecutorList(std::vector<std::shared_ptr<HidumperExecutor>> &executors,
571                                     const std::vector<std::shared_ptr<DumpCfg>> &configs, bool isZip)
572 {
573     std::shared_ptr<HidumperExecutor> ptrOutput;
574 
575     for (size_t i = 0; i < configs.size(); i++) {
576         std::shared_ptr<ExecutorFactory> ptrExecutorFactory;
577         if ((configs[i]->class_) == DumperConstant::FD_OUTPUT) {
578             if (isZip) {
579                 ptrExecutorFactory = std::make_shared<ZipOutputFactory>();
580             } else {
581                 ptrExecutorFactory = std::make_shared<FDOutputFactory>();
582             }
583 
584             if (ptrOutput.get() == nullptr) {
585                 ptrOutput = ptrExecutorFactory->CreateExecutor();
586             }
587             ptrOutput->SetDumpConfig(configs[i]);
588             executors.push_back(ptrOutput);
589             continue;
590         } else {
591             ExecutorFactoryMap::iterator it = ptrExecutorFactoryMap_->find(configs[i]->class_);
592             if (it != ptrExecutorFactoryMap_->end()) {
593                 ptrExecutorFactory = it->second;
594             }
595         }
596 
597         if (ptrExecutorFactory.get() == nullptr) {
598             DUMPER_HILOGE(MODULE_COMMON, "configs[%{public}zu].class_ is %{public}d", i, configs[i]->class_);
599             continue;
600         }
601         std::shared_ptr<HidumperExecutor> ptrExecutor = ptrExecutorFactory->CreateExecutor();
602         if (ptrExecutor != nullptr) {
603             configs[i]->executor_ = ptrExecutor;
604             ptrExecutor->SetDumpConfig(configs[i]);
605         }
606         executors.push_back(ptrExecutor);
607     }
608 
609     // must clear.
610     for (auto cfg : configs) {
611         cfg->executor_ = nullptr;
612     }
613 }
614 
DumpDatas(const std::vector<std::shared_ptr<HidumperExecutor>> &executors, const std::shared_ptr<DumperParameter> &dumpParameter, HidumperExecutor::StringMatrix dumpDatas)615 DumpStatus DumpImplement::DumpDatas(const std::vector<std::shared_ptr<HidumperExecutor>> &executors,
616                                     const std::shared_ptr<DumperParameter> &dumpParameter,
617                                     HidumperExecutor::StringMatrix dumpDatas)
618 {
619     auto callback = dumpParameter->getClientCallback();
620 
621     std::string groupName = "";
622     std::vector<size_t> loopStack;
623     const size_t executorSum = executors.size();
624     for (size_t index = 0; index < executorSum; index++) {
625         callback->UpdateProgress(executors.size(), index);
626         if (callback->IsCanceled()) {
627             break;
628         }
629 
630         auto dumpCfg = executors[index]->GetDumpConfig();
631         if (dumpCfg->IsDumper() && CheckGroupName(groupName, dumpCfg->section_)) {
632             AddGroupTitle(groupName, dumpDatas, dumpParameter);
633         }
634 
635         DumpStatus ret = DumpStatus::DUMP_FAIL;
636         ret = executors[index]->DoPreExecute(dumpParameter, dumpDatas);
637         if (ret != DumpStatus::DUMP_OK) {
638             continue;
639         }
640 
641         ret = executors[index]->DoExecute();
642         if ((ret != DumpStatus::DUMP_OK) && (ret != DumpStatus::DUMP_MORE_DATA)) {
643             continue;
644         }
645 
646         ret = executors[index]->DoAfterExecute();
647         if (dumpCfg->IsDumper() && dumpCfg->CanLoop() && (ret == DumpStatus::DUMP_MORE_DATA)) {
648             loopStack.push_back(index);
649         }
650 
651         if (dumpCfg->IsOutput() || dumpCfg->IsGroup()) {
652             if (!loopStack.empty()) {
653                 index = loopStack.back() - 1; // the 1 will add back by end for.
654             }
655             loopStack.clear(); // clear now.
656         }
657     }
658     for (auto executor : executors) {
659         executor->Reset();
660     }
661     callback->UpdateProgress(executors.size(), executors.size());
662     return DumpStatus::DUMP_OK;
663 }
664 
AddGroupTitle(const std::string &groupName, HidumperExecutor::StringMatrix dumpDatas, const std::shared_ptr<DumperParameter>& dumpParameter)665 void DumpImplement::AddGroupTitle(const std::string &groupName, HidumperExecutor::StringMatrix dumpDatas,
666     const std::shared_ptr<DumperParameter>& dumpParameter)
667 {
668     /**
669      * @brief The group title is followed
670      * '
671      * -------------------------------[groupName]-------------------------------
672      * '
673      */
674     if (StringUtils::GetInstance().IsSameStr(groupName, "ipc")) {
675         DUMPER_HILOGI(MODULE_COMMON, "ipc statistic cmd, do not need title.");
676         return;
677     }
678     if (StringUtils::GetInstance().IsSameStr(groupName, "memory") && dumpParameter->GetOpts().memPid_ <= 0) {
679         DUMPER_HILOGI(MODULE_COMMON, "hidumper --mem cmd, do not need title.");
680         return;
681     }
682     if (StringUtils::GetInstance().IsSameStr(groupName, "ability")) {
683         return;
684     }
685     std::vector<std::string> lineData;
686     lineData.push_back("");
687     dumpDatas->push_back(lineData);
688     std::vector<std::string>().swap(lineData);
689     lineData.push_back("-------------------------------[");
690     lineData.push_back(groupName);
691     lineData.push_back("]-------------------------------");
692     dumpDatas->push_back(lineData);
693     std::vector<std::string>().swap(lineData);
694     lineData.push_back("");
695     dumpDatas->push_back(lineData);
696     std::vector<std::string>().swap(lineData);
697 }
698 
CheckGroupName(std::string &lastName, const std::string &curName)699 bool DumpImplement::CheckGroupName(std::string &lastName, const std::string &curName)
700 {
701     if (curName.compare("") == 0) {
702         return false;
703     }
704 
705     if (lastName.compare(curName) == 0) {
706         return false;
707     }
708 
709     lastName.assign(curName);
710     return true;
711 }
712 
GetSystemAbilityManager()713 const sptr<ISystemAbilityManager> DumpImplement::GetSystemAbilityManager()
714 {
715     sam_ = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
716     if (sam_ == nullptr) {
717         DUMPER_HILOGE(MODULE_COMMON, "SystemAbilityManager not found.");
718     }
719     return sam_;
720 }
721 
CheckIncorrectCmdOption(const char *optStr, char *argv[])722 void DumpImplement::CheckIncorrectCmdOption(const char *optStr, char *argv[])
723 {
724     if (optopt == 0) {
725         SendErrorMessage(unrecognizedError_ + RemoveCharacterFromStr(argv[optind - 1], '-'));
726     } else if (!IsShortOptionReqArg(optStr)) {
727         std::string errorStr = unrecognizedError_;
728         errorStr += optopt;
729         SendErrorMessage(errorStr);
730     }
731 }
732 
IsShortOptionReqArg(const char *optStr)733 bool DumpImplement::IsShortOptionReqArg(const char *optStr)
734 {
735     int len = strlen(optStr);
736     for (int i = 0; i < len; i++) {
737         if (optStr[i] == optopt) {
738             SendErrorMessage(requireError_ + optStr[i]);
739             return true;
740         }
741     }
742     return false;
743 }
744 
SendErrorMessage(const std::string &errorStr)745 void DumpImplement::SendErrorMessage(const std::string &errorStr)
746 {
747     if (ptrReqCtl_ == nullptr) {
748         return;
749     }
750     int rawParamFd = ptrReqCtl_->GetOutputFd();
751     if (rawParamFd < 0) {
752         return;
753     }
754     SaveStringToFd(rawParamFd, errorStr + "\n");
755 }
756 
SendPidErrorMessage(int pid)757 void DumpImplement::SendPidErrorMessage(int pid)
758 {
759     if (ptrReqCtl_ == nullptr) {
760         return;
761     }
762     int rawParamFd = ptrReqCtl_->GetOutputFd();
763     if (rawParamFd < 0) {
764         return;
765     }
766     dprintf(rawParamFd, pidError_.c_str(), pid);
767 }
768 
RemoveCharacterFromStr(const std::string &str, const char character)769 std::string DumpImplement::RemoveCharacterFromStr(const std::string &str, const char character)
770 {
771     std::string strTmp = str;
772     while (strTmp.find(character) != std::string::npos) {
773         strTmp.erase(strTmp.find(character), 1);
774     }
775     return strTmp;
776 }
777 
IsSADumperOption(char *argv[])778 bool DumpImplement::IsSADumperOption(char *argv[])
779 {
780     for (int i = optind - 2; i > 0; i--) {
781         if (IsSubStr(argv[i], "-")) {
782             return StringUtils::GetInstance().IsSameStr(argv[i], "-s")
783                    || StringUtils::GetInstance().IsSameStr(argv[i], "-a");
784         }
785     }
786     return false;
787 }
788 
CheckProcessAlive(const DumperOpts &opts_)789 DumpStatus DumpImplement::CheckProcessAlive(const DumperOpts &opts_)
790 {
791     if ((opts_.cpuUsagePid_ > -1) && !DumpUtils::CheckProcessAlive(opts_.cpuUsagePid_)) {
792         SendPidErrorMessage(opts_.cpuUsagePid_);
793         return DumpStatus::DUMP_FAIL;
794     }
795     if ((opts_.memPid_ > -1) && !DumpUtils::CheckProcessAlive(opts_.memPid_)) {
796         SendPidErrorMessage(opts_.memPid_);
797         return DumpStatus::DUMP_FAIL;
798     }
799     if ((opts_.processPid_ > -1) && !DumpUtils::CheckProcessAlive(opts_.processPid_)) {
800         SendPidErrorMessage(opts_.processPid_);
801         return DumpStatus::DUMP_FAIL;
802     }
803     if ((opts_.storagePid_ > -1) && !DumpUtils::CheckProcessAlive(opts_.storagePid_)) {
804         SendPidErrorMessage(opts_.storagePid_);
805         return DumpStatus::DUMP_FAIL;
806     }
807     if ((opts_.netPid_ > -1) && !DumpUtils::CheckProcessAlive(opts_.netPid_)) {
808         SendPidErrorMessage(opts_.netPid_);
809         return DumpStatus::DUMP_FAIL;
810     }
811     if ((opts_.dumpJsHeapMemPid_ > 0) && !DumpUtils::CheckProcessAlive(opts_.dumpJsHeapMemPid_)) {
812         SendPidErrorMessage(opts_.dumpJsHeapMemPid_);
813         return DumpStatus::DUMP_FAIL;
814     }
815     if ((opts_.ipcStatPid_ > 0) && !DumpUtils::CheckProcessAlive(opts_.ipcStatPid_)) {
816         SendPidErrorMessage(opts_.ipcStatPid_);
817         return DumpStatus::DUMP_FAIL;
818     }
819     return DumpStatus::DUMP_OK;
820 }
821 
RemoveDuplicateString(DumperOpts &opts_)822 void DumpImplement::RemoveDuplicateString(DumperOpts &opts_)
823 {
824     DumpUtils::RemoveDuplicateString(opts_.logArgs_);       // remove duplicate log names
825     DumpUtils::RemoveDuplicateString(opts_.systemArgs_);    // remove duplicate system names
826     DumpUtils::RemoveDuplicateString(opts_.abilitieNames_); // remove duplicate ability names
827 }
828 
829 #ifdef HIDUMPER_HIVIEWDFX_HISYSEVENT_ENABLE
TransferVectorToString(const std::vector<std::string>& vs)830 std::string DumpImplement::TransferVectorToString(const std::vector<std::string>& vs)
831 {
832     std::string outputStr;
833     std::stringstream ss;
834 
835     for (const auto& i : vs) {
836         ss << i << " ";
837     }
838     outputStr = ss.str();
839     if (outputStr.empty()) {
840         return "";
841     }
842     return outputStr.substr(0, outputStr.length() - 1);
843 }
844 
ReportCmdUsage(const DumperOpts &opts_, const std::string &cmdStr)845 void DumpImplement::ReportCmdUsage(const DumperOpts &opts_, const std::string &cmdStr)
846 {
847     int ret = HiSysEventWrite(HiSysEvent::Domain::HIDUMPER, "CMD_USAGE",
848         OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC,
849         "IS_DUMP_CPU_FREQ", opts_.isDumpCpuFreq_,
850         "IS_DUMP_CPU_USAGE", opts_.isDumpCpuUsage_,
851         "CPU_USAGE_PID", opts_.cpuUsagePid_,
852         "IS_DUMP_LOG", opts_.isDumpLog_,
853         "LOG_ARGS", opts_.logArgs_,
854         "IS_DUMP_MEM", opts_.isDumpMem_,
855         "MEM_PID", opts_.memPid_,
856         "IS_DUMP_STORAGE", opts_.isDumpStorage_,
857         "STORAGE_PID", opts_.storagePid_,
858         "IS_DUMP_NET", opts_.isDumpNet_,
859         "NET_PID", opts_.netPid_,
860         "IS_DUMP_LIST", opts_.isDumpList_,
861         "IS_DUMP_SERVICE", opts_.isDumpService_,
862         "IS_DUMP_SYSTEM_ABILITY", opts_.isDumpSystemAbility_,
863         "ABILITIE_NAMES", TransferVectorToString(opts_.abilitieNames_),
864         "ABILITIE_ARGS", TransferVectorToString(opts_.abilitieArgs_),
865         "IS_DUMP_SYSTEM", opts_.isDumpSystem_,
866         "SYSTEM_ARGS", TransferVectorToString(opts_.systemArgs_),
867         "IS_DUMP_PROCESSES", opts_.isDumpProcesses_,
868         "PROCESS_PID", opts_.processPid_,
869         "IS_FAULT_LOG", opts_.isFaultLog_,
870         "PATH", opts_.path_,
871         "IS_APPENDIX", opts_.isAppendix_,
872         "IS_SHOW_SMAPS", opts_.isShowSmaps_,
873         "IS_SHOW_SMAPS_INFO", opts_.isShowSmapsInfo_,
874         "CMD_USER_INPUT", cmdStr);
875     if (ret != 0) {
876         DUMPER_HILOGE(MODULE_COMMON, "hisysevent report hidumper usage failed! ret %{public}d.", ret);
877     }
878     if (opts_.isDumpJsHeapMem_) {
879         int memJsheapRet = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::FRAMEWORK,
880             "ARK_STATS_DUMP",
881             OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
882             "PID", std::to_string(opts_.dumpJsHeapMemPid_),
883             "TYPE", "hidumper");
884         if (memJsheapRet != 0) {
885             DUMPER_HILOGE(MODULE_COMMON, "hisysevent report mem jsheap failed! ret %{public}d.", memJsheapRet);
886         }
887     }
888 }
889 #endif
890 
CheckDumpPermission(DumperOpts& opt)891 bool DumpImplement::CheckDumpPermission(DumperOpts& opt)
892 {
893     bool isUserMode = DumpUtils::IsUserMode();
894     DUMPER_HILOGD(MODULE_COMMON, "debug|isUserMode %{public}d", isUserMode);
895     if (!isUserMode) {
896         return true;
897     }
898     // mem-smaps -v
899     if (opt.isShowSmapsInfo_) {
900         DUMPER_HILOGE(MODULE_COMMON, "ShowSmaps -v false isUserMode:%{public}d", isUserMode);
901         return false;
902     }
903     // mem-smaps + !hiview
904     int32_t calllingUid = IPCSkeleton::GetCallingUid();
905     if (opt.isShowSmaps_ && calllingUid != HIVIEW_UID) {
906         DUMPER_HILOGE(MODULE_COMMON, "ShowSmaps false isUserMode %{public}d uid %{public}d", isUserMode, calllingUid);
907         return false;
908     }
909     // mem-jsheap + releaseApp
910     if (opt.isDumpJsHeapMem_ && !DumpUtils::CheckAppDebugVersion(opt.dumpJsHeapMemPid_)) {
911         DUMPER_HILOGE(MODULE_COMMON, "DumpJsHeapMem false isUserMode %{public}d", isUserMode);
912         return false;
913     }
914     return true;
915 }
916 } // namespace HiviewDFX
917 } // namespace OHOS
918