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
50namespace OHOS {
51namespace HiviewDFX {
52const int HIVIEW_UID = 1201;
53DumpImplement::DumpImplement()
54{
55    AddExecutorFactoryToMap();
56}
57
58DumpImplement::~DumpImplement()
59{
60}
61
62void 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
94DumpStatus 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
137void 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
154DumpStatus 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
198bool 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
210DumpStatus 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
269DumpStatus 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
288DumpStatus 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
332std::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
351bool 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
380DumpStatus 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
429bool 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
443DumpStatus 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
470DumpStatus 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
509DumpStatus 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
520void 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
570void 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
615DumpStatus 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
665void 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
699bool 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
713const 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
722void 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
733bool 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
745void 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
757void 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
769std::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
778bool 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
789DumpStatus 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
822void 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
830std::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
845void 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
891bool 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