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 16#include "subcommand.h" 17#include <mutex> 18#include "debug_logger.h" 19#include "option.h" 20 21using namespace std; 22namespace OHOS { 23namespace Developtools { 24namespace HiPerf { 25static std::map<std::string, std::unique_ptr<SubCommand>> g_SubCommandsMap; 26std::mutex g_subCommandMutex; 27 28// parse option first 29bool SubCommand::OnSubCommandOptions(std::vector<std::string> args) 30{ 31 // parse common first 32 if (!Option::GetOptionValue(args, "--dumpoptions", dumpOptions_)) { 33 return false; 34 } 35 if (!Option::GetOptionValue(args, "--help", showHelp_) 36 || !Option::GetOptionValue(args, "-h", showHelp_)) { 37 return false; 38 } 39 40 if (showHelp_) { 41 if (!args.empty()) { 42 printf("unknown option '%s'\n", args.front().c_str()); 43 return false; 44 } 45 if (OnPreSubCommand()) { 46 return false; 47 } 48 } 49 50 if (ParseOption(args)) { 51 if (dumpOptions_) { 52 DumpOptions(); 53 } 54 HLOGD(" args left over: (%zu): %s", args.size(), VectorToString(args).c_str()); 55 if (!args.empty()) { 56 printf("unknown option '%s'\n", args.front().c_str()); 57 return false; 58 } 59 } else { 60 HLOGD("incorrect option(s)\n"); 61 return false; 62 } 63 return true; 64} 65 66bool SubCommand::CheckRestartOption(std::string &appPackage, bool targetSystemWide, bool restart, 67 std::vector<pid_t> &selectPids) 68{ 69 if (!restart) { 70 return true; 71 } 72 if (appPackage.empty()) { 73 printf("to detect the performance of application startup, --app option must be given\n"); 74 return false; 75 } 76 if (targetSystemWide || !selectPids.empty()) { 77 printf("option --restart and -p/-a is conflict, please check usage\n"); 78 return false; 79 } 80 81 if (!appPackage.empty()) { 82 return IsRestarted(appPackage); 83 } 84 return false; 85} 86 87bool SubCommand::HandleSubCommandExclude(const std::vector<pid_t> &excludeTids, const std::vector<std::string> 88 &excludeThreadNames, std::vector<pid_t> &selectTids) 89{ 90 if (!excludeTids.empty() && !excludeThreadNames.empty()) { 91 printf("option --exclude-thread and --exclude-tid is conflict, please check usage\n"); 92 return false; 93 } 94 if (excludeTids.empty() && excludeThreadNames.empty()) { 95 return true; 96 } 97 if (selectTids.empty()) { 98 printf("No thread is Monitored, while attempt to exclude some threads.\n"); 99 return true; 100 } 101 if (!excludeTids.empty()) { 102 ExcludeTidsFromSelectTids(excludeTids, selectTids); 103 return true; 104 } 105 ExcludeThreadsFromSelectTids(excludeThreadNames, selectTids); 106 return true; 107} 108 109void SubCommand::ExcludeTidsFromSelectTids(const std::vector<pid_t> &excludeTids, std::vector<pid_t> &selectTids) 110{ 111 for (auto excludeTid : excludeTids) { 112 bool hasExclude = false; 113 auto pos = selectTids.begin(); 114 while (pos != selectTids.end()) { 115 if (excludeTid == *pos) { 116 pos = selectTids.erase(pos); 117 hasExclude = true; 118 continue; 119 } 120 ++pos; 121 } 122 if (!hasExclude) { 123 printf("No thread id %d was found to exclude.\n", excludeTid); 124 } 125 } 126} 127 128void SubCommand::ExcludeThreadsFromSelectTids(const std::vector<std::string> &excludeThreadNames, 129 std::vector<pid_t> &selectTids) 130{ 131 for (auto excludeName : excludeThreadNames) { 132 bool hasExclude = false; 133 auto pos = selectTids.begin(); 134 while (pos != selectTids.end()) { 135 std::string threadName = virtualRuntime_.ReadThreadName(*pos, true); 136 if (excludeName == threadName) { 137 pos = selectTids.erase(pos); 138 hasExclude = true; 139 continue; 140 } 141 ++pos; 142 } 143 if (!hasExclude) { 144 printf("No thread named %s was found to exclude.\n", excludeName.c_str()); 145 } 146 } 147} 148 149bool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr<SubCommand> subCommand) 150{ 151 HLOGV("%s", cmdName.c_str()); 152 if (cmdName.empty()) { 153 HLOGE("unable to register empty subcommand!"); 154 return false; 155 } 156 if (cmdName.front() == '-') { 157 HLOGE("unable use '-' at the begin of subcommand '%s'", cmdName.c_str()); 158 return false; 159 } 160 161 if (g_SubCommandsMap.count(cmdName) == 0) { 162 std::lock_guard<std::mutex> lock(g_subCommandMutex); 163 g_SubCommandsMap.insert(std::make_pair(cmdName, std::move(subCommand))); 164 return true; 165 } else { 166 HLOGE("subcommand '%s' already registered!", cmdName.c_str()); 167 return false; 168 } 169} 170 171void SubCommand::ClearSubCommands() 172{ 173 std::lock_guard<std::mutex> lock(g_subCommandMutex); 174 g_SubCommandsMap.clear(); 175} 176 177const std::map<std::string, std::unique_ptr<SubCommand>> &SubCommand::GetSubCommands() 178{ 179 return g_SubCommandsMap; 180} 181 182SubCommand *SubCommand::FindSubCommand(std::string &cmdName) 183{ 184 HLOGV("%s", cmdName.c_str()); 185 std::lock_guard<std::mutex> lock(g_subCommandMutex); 186 auto found = g_SubCommandsMap.find(cmdName); 187 if (found != g_SubCommandsMap.end()) { 188 // remove the subcmd itself 189 return found->second.get(); 190 } else { 191 return nullptr; 192 } 193} 194} // namespace HiPerf 195} // namespace Developtools 196} // namespace OHOS 197