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