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