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
21 namespace OHOS {
22 namespace Developtools {
23 namespace HiPerf {
24 std::mutex SubCommand::subCommandMutex_;
25 std::map<std::string, std::unique_ptr<SubCommand>> SubCommand::subCommandMap_ = {};
26 std::map<std::string, std::function<SubCommand&()>> SubCommand::subCommandFuncMap_ = {};
27
28 // parse option first
OnSubCommandOptions(std::vector<std::string> args)29 bool 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
CheckRestartOption(const std::string & appPackage,const bool targetSystemWide,const bool restart,std::vector<pid_t> & selectPids)66 bool SubCommand::CheckRestartOption(const std::string &appPackage, const bool targetSystemWide, const 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
HandleSubCommandExclude(const std::vector<pid_t> & excludeTids,const std::vector<std::string> & excludeThreadNames,std::vector<pid_t> & selectTids)87 bool SubCommand::HandleSubCommandExclude(const std::vector<pid_t> &excludeTids,
88 const std::vector<std::string> &excludeThreadNames,
89 std::vector<pid_t> &selectTids)
90 {
91 if (!excludeTids.empty() && !excludeThreadNames.empty()) {
92 printf("option --exclude-thread and --exclude-tid is conflict, please check usage\n");
93 return false;
94 }
95 if (excludeTids.empty() && excludeThreadNames.empty()) {
96 return true;
97 }
98 if (selectTids.empty()) {
99 printf("No thread is Monitored, while attempt to exclude some threads.\n");
100 return true;
101 }
102 if (!excludeTids.empty()) {
103 ExcludeTidsFromSelectTids(excludeTids, selectTids);
104 return true;
105 }
106 ExcludeThreadsFromSelectTids(excludeThreadNames, selectTids);
107 return true;
108 }
109
ExcludeTidsFromSelectTids(const std::vector<pid_t> & excludeTids,std::vector<pid_t> & selectTids)110 void SubCommand::ExcludeTidsFromSelectTids(const std::vector<pid_t> &excludeTids, std::vector<pid_t> &selectTids)
111 {
112 for (auto excludeTid : excludeTids) {
113 bool hasExclude = false;
114 auto pos = selectTids.begin();
115 while (pos != selectTids.end()) {
116 if (excludeTid == *pos) {
117 pos = selectTids.erase(pos);
118 hasExclude = true;
119 continue;
120 }
121 ++pos;
122 }
123 if (!hasExclude) {
124 printf("No thread id %d was found to exclude.\n", excludeTid);
125 }
126 }
127 }
128
ExcludeThreadsFromSelectTids(const std::vector<std::string> & excludeThreadNames,std::vector<pid_t> & selectTids)129 void SubCommand::ExcludeThreadsFromSelectTids(const std::vector<std::string> &excludeThreadNames,
130 std::vector<pid_t> &selectTids)
131 {
132 for (auto excludeName : excludeThreadNames) {
133 bool hasExclude = false;
134 auto pos = selectTids.begin();
135 while (pos != selectTids.end()) {
136 std::string threadName = virtualRuntime_.ReadThreadName(*pos, true);
137 if (excludeName == threadName) {
138 pos = selectTids.erase(pos);
139 hasExclude = true;
140 continue;
141 }
142 ++pos;
143 }
144 if (!hasExclude) {
145 printf("No thread named %s was found to exclude.\n", excludeName.c_str());
146 }
147 }
148 }
149
RegisterSubCommand(const std::string & cmdName,std::function<SubCommand & ()> func)150 bool SubCommand::RegisterSubCommand(const std::string& cmdName, std::function<SubCommand&()> func)
151 {
152 HLOGV("%s", cmdName.c_str());
153 if (cmdName.empty()) {
154 HLOGE("unable to register empty subcommand!");
155 return false;
156 }
157 if (cmdName.front() == '-') {
158 HLOGE("unable use '-' at the begin of subcommand '%s'", cmdName.c_str());
159 return false;
160 }
161
162 if (subCommandFuncMap_.find(cmdName) == subCommandFuncMap_.end()) {
163 std::lock_guard<std::mutex> lock(subCommandMutex_);
164 subCommandFuncMap_.insert(std::make_pair(cmdName, func));
165 return true;
166 } else {
167 HLOGE("subcommand '%s' already registered!", cmdName.c_str());
168 return false;
169 }
170 }
171
RegisterSubCommand(const std::string & cmdName,std::unique_ptr<SubCommand> subCommand)172 bool SubCommand::RegisterSubCommand(const std::string& cmdName, std::unique_ptr<SubCommand> subCommand)
173 {
174 SubCommand* subCommandPtr = subCommand.get();
175 auto func = [subCommandPtr]() -> SubCommand& {
176 return *subCommandPtr;
177 };
178 if (RegisterSubCommand(cmdName, func)) {
179 std::lock_guard<std::mutex> lock(subCommandMutex_);
180 subCommandMap_[cmdName] = std::move(subCommand);
181 return true;
182 }
183 return false;
184 }
185
ClearSubCommands()186 void SubCommand::ClearSubCommands()
187 {
188 std::lock_guard<std::mutex> lock(subCommandMutex_);
189 subCommandFuncMap_.clear();
190 subCommandMap_.clear();
191 }
192
GetSubCommands()193 const std::map<std::string, std::function<SubCommand&()>>& SubCommand::GetSubCommands()
194 {
195 return subCommandFuncMap_;
196 }
197
FindSubCommand(const std::string & cmdName)198 SubCommand *SubCommand::FindSubCommand(const std::string &cmdName)
199 {
200 HLOGV("%s", cmdName.c_str());
201 std::lock_guard<std::mutex> lock(subCommandMutex_);
202 auto found = subCommandFuncMap_.find(cmdName);
203 if (found != subCommandFuncMap_.end()) {
204 return &(found->second());
205 } else {
206 return nullptr;
207 }
208 }
209 } // namespace HiPerf
210 } // namespace Developtools
211 } // namespace OHOS
212