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