xref: /aosp_15_r20/system/extras/simpleperf/cmd_api.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include <memory>
20*288bf522SAndroid Build Coastguard Worker #include <string>
21*288bf522SAndroid Build Coastguard Worker #include <thread>
22*288bf522SAndroid Build Coastguard Worker #include <vector>
23*288bf522SAndroid Build Coastguard Worker 
24*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
25*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
26*288bf522SAndroid Build Coastguard Worker #include <android-base/parseint.h>
27*288bf522SAndroid Build Coastguard Worker #include <android-base/properties.h>
28*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
29*288bf522SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
30*288bf522SAndroid Build Coastguard Worker #include <ziparchive/zip_writer.h>
31*288bf522SAndroid Build Coastguard Worker 
32*288bf522SAndroid Build Coastguard Worker #include "RegEx.h"
33*288bf522SAndroid Build Coastguard Worker #include "cmd_api_impl.h"
34*288bf522SAndroid Build Coastguard Worker #include "command.h"
35*288bf522SAndroid Build Coastguard Worker #include "environment.h"
36*288bf522SAndroid Build Coastguard Worker #include "event_type.h"
37*288bf522SAndroid Build Coastguard Worker #include "utils.h"
38*288bf522SAndroid Build Coastguard Worker #include "workload.h"
39*288bf522SAndroid Build Coastguard Worker 
40*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
41*288bf522SAndroid Build Coastguard Worker namespace {
42*288bf522SAndroid Build Coastguard Worker 
43*288bf522SAndroid Build Coastguard Worker const std::string SIMPLEPERF_DATA_DIR = "simpleperf_data";
44*288bf522SAndroid Build Coastguard Worker 
45*288bf522SAndroid Build Coastguard Worker class PrepareCommand : public Command {
46*288bf522SAndroid Build Coastguard Worker  public:
PrepareCommand()47*288bf522SAndroid Build Coastguard Worker   PrepareCommand()
48*288bf522SAndroid Build Coastguard Worker       : Command("api-prepare", "Prepare recording via app api",
49*288bf522SAndroid Build Coastguard Worker                 // clang-format off
50*288bf522SAndroid Build Coastguard Worker "Usage: simpleperf api-prepare [options]\n"
51*288bf522SAndroid Build Coastguard Worker "--app <package_name>    the android application to record via app api\n"
52*288bf522SAndroid Build Coastguard Worker "--days <days>           By default, the recording permission is reset after device reboot.\n"
53*288bf522SAndroid Build Coastguard Worker "                        But on Android >= 13, we can use this option to set how long we want\n"
54*288bf522SAndroid Build Coastguard Worker "                        the permission to last. It can last after device reboot.\n"
55*288bf522SAndroid Build Coastguard Worker                 // clang-format on
56*288bf522SAndroid Build Coastguard Worker         ) {}
57*288bf522SAndroid Build Coastguard Worker   bool Run(const std::vector<std::string>& args);
58*288bf522SAndroid Build Coastguard Worker 
59*288bf522SAndroid Build Coastguard Worker  private:
60*288bf522SAndroid Build Coastguard Worker   bool ParseOptions(const std::vector<std::string>& args);
61*288bf522SAndroid Build Coastguard Worker   std::optional<uint32_t> GetAppUid();
62*288bf522SAndroid Build Coastguard Worker 
63*288bf522SAndroid Build Coastguard Worker   std::string app_name_;
64*288bf522SAndroid Build Coastguard Worker   uint64_t days_ = 0;
65*288bf522SAndroid Build Coastguard Worker };
66*288bf522SAndroid Build Coastguard Worker 
Run(const std::vector<std::string> & args)67*288bf522SAndroid Build Coastguard Worker bool PrepareCommand::Run(const std::vector<std::string>& args) {
68*288bf522SAndroid Build Coastguard Worker   if (!ParseOptions(args)) {
69*288bf522SAndroid Build Coastguard Worker     return false;
70*288bf522SAndroid Build Coastguard Worker   }
71*288bf522SAndroid Build Coastguard Worker   // Enable profiling.
72*288bf522SAndroid Build Coastguard Worker   if (GetAndroidVersion() >= 13 && !app_name_.empty() && days_ != 0) {
73*288bf522SAndroid Build Coastguard Worker     // Enable app recording via persist properties.
74*288bf522SAndroid Build Coastguard Worker     uint64_t duration_in_sec;
75*288bf522SAndroid Build Coastguard Worker     uint64_t expiration_time;
76*288bf522SAndroid Build Coastguard Worker     if (__builtin_mul_overflow(days_, 24 * 3600, &duration_in_sec) ||
77*288bf522SAndroid Build Coastguard Worker         __builtin_add_overflow(time(nullptr), duration_in_sec, &expiration_time)) {
78*288bf522SAndroid Build Coastguard Worker       expiration_time = UINT64_MAX;
79*288bf522SAndroid Build Coastguard Worker     }
80*288bf522SAndroid Build Coastguard Worker     std::optional<uint32_t> uid = GetAppUid();
81*288bf522SAndroid Build Coastguard Worker     if (!uid) {
82*288bf522SAndroid Build Coastguard Worker       return false;
83*288bf522SAndroid Build Coastguard Worker     }
84*288bf522SAndroid Build Coastguard Worker     if (!android::base::SetProperty("persist.simpleperf.profile_app_uid",
85*288bf522SAndroid Build Coastguard Worker                                     std::to_string(uid.value())) ||
86*288bf522SAndroid Build Coastguard Worker         !android::base::SetProperty("persist.simpleperf.profile_app_expiration_time",
87*288bf522SAndroid Build Coastguard Worker                                     std::to_string(expiration_time))) {
88*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "failed to set system properties";
89*288bf522SAndroid Build Coastguard Worker       return false;
90*288bf522SAndroid Build Coastguard Worker     }
91*288bf522SAndroid Build Coastguard Worker   } else {
92*288bf522SAndroid Build Coastguard Worker     // Enable app recording via security.perf_harden.
93*288bf522SAndroid Build Coastguard Worker     if (!CheckPerfEventLimit()) {
94*288bf522SAndroid Build Coastguard Worker       return false;
95*288bf522SAndroid Build Coastguard Worker     }
96*288bf522SAndroid Build Coastguard Worker   }
97*288bf522SAndroid Build Coastguard Worker 
98*288bf522SAndroid Build Coastguard Worker   // Create tracepoint_events file.
99*288bf522SAndroid Build Coastguard Worker   return EventTypeManager::Instance().WriteTracepointsToFile("/data/local/tmp/tracepoint_events");
100*288bf522SAndroid Build Coastguard Worker }
101*288bf522SAndroid Build Coastguard Worker 
ParseOptions(const std::vector<std::string> & args)102*288bf522SAndroid Build Coastguard Worker bool PrepareCommand::ParseOptions(const std::vector<std::string>& args) {
103*288bf522SAndroid Build Coastguard Worker   OptionValueMap options;
104*288bf522SAndroid Build Coastguard Worker   std::vector<std::pair<OptionName, OptionValue>> ordered_options;
105*288bf522SAndroid Build Coastguard Worker   static const OptionFormatMap option_formats = {
106*288bf522SAndroid Build Coastguard Worker       {"--app", {OptionValueType::STRING, OptionType::SINGLE, AppRunnerType::NOT_ALLOWED}},
107*288bf522SAndroid Build Coastguard Worker       {"--days", {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::NOT_ALLOWED}},
108*288bf522SAndroid Build Coastguard Worker   };
109*288bf522SAndroid Build Coastguard Worker   if (!PreprocessOptions(args, option_formats, &options, &ordered_options, nullptr)) {
110*288bf522SAndroid Build Coastguard Worker     return false;
111*288bf522SAndroid Build Coastguard Worker   }
112*288bf522SAndroid Build Coastguard Worker 
113*288bf522SAndroid Build Coastguard Worker   if (auto value = options.PullValue("--app"); value) {
114*288bf522SAndroid Build Coastguard Worker     app_name_ = value->str_value;
115*288bf522SAndroid Build Coastguard Worker   }
116*288bf522SAndroid Build Coastguard Worker   if (!options.PullUintValue("--days", &days_)) {
117*288bf522SAndroid Build Coastguard Worker     return false;
118*288bf522SAndroid Build Coastguard Worker   }
119*288bf522SAndroid Build Coastguard Worker   return true;
120*288bf522SAndroid Build Coastguard Worker }
121*288bf522SAndroid Build Coastguard Worker 
GetAppUid()122*288bf522SAndroid Build Coastguard Worker std::optional<uint32_t> PrepareCommand::GetAppUid() {
123*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<FILE, decltype(&pclose)> fp(popen("pm list packages -U", "re"), pclose);
124*288bf522SAndroid Build Coastguard Worker   std::string content;
125*288bf522SAndroid Build Coastguard Worker   if (!fp || !android::base::ReadFdToString(fileno(fp.get()), &content)) {
126*288bf522SAndroid Build Coastguard Worker     PLOG(ERROR) << "failed to run `pm list packages -U`";
127*288bf522SAndroid Build Coastguard Worker     return std::nullopt;
128*288bf522SAndroid Build Coastguard Worker   }
129*288bf522SAndroid Build Coastguard Worker   auto re = RegEx::Create(R"(package:([\w\.]+)\s+uid:(\d+))");
130*288bf522SAndroid Build Coastguard Worker   auto match = re->SearchAll(content);
131*288bf522SAndroid Build Coastguard Worker   while (match->IsValid()) {
132*288bf522SAndroid Build Coastguard Worker     std::string name = match->GetField(1);
133*288bf522SAndroid Build Coastguard Worker     uint32_t uid;
134*288bf522SAndroid Build Coastguard Worker     if (name == app_name_ && android::base::ParseUint(match->GetField(2), &uid)) {
135*288bf522SAndroid Build Coastguard Worker       return uid;
136*288bf522SAndroid Build Coastguard Worker     }
137*288bf522SAndroid Build Coastguard Worker     match->MoveToNextMatch();
138*288bf522SAndroid Build Coastguard Worker   }
139*288bf522SAndroid Build Coastguard Worker   LOG(ERROR) << "failed to find package " << app_name_;
140*288bf522SAndroid Build Coastguard Worker   return std::nullopt;
141*288bf522SAndroid Build Coastguard Worker }
142*288bf522SAndroid Build Coastguard Worker 
143*288bf522SAndroid Build Coastguard Worker class CollectCommand : public Command {
144*288bf522SAndroid Build Coastguard Worker  public:
CollectCommand()145*288bf522SAndroid Build Coastguard Worker   CollectCommand()
146*288bf522SAndroid Build Coastguard Worker       : Command("api-collect", "Collect recording data generated by app api",
147*288bf522SAndroid Build Coastguard Worker                 // clang-format off
148*288bf522SAndroid Build Coastguard Worker "Usage: simpleperf api-collect [options]\n"
149*288bf522SAndroid Build Coastguard Worker "--app <package_name>    the android application having recording data\n"
150*288bf522SAndroid Build Coastguard Worker "-o record_zipfile_path  the path to store recording data\n"
151*288bf522SAndroid Build Coastguard Worker "                        Default is simpleperf_data.zip.\n"
152*288bf522SAndroid Build Coastguard Worker #if 0
153*288bf522SAndroid Build Coastguard Worker // Below options are only used internally and shouldn't be visible to the public.
154*288bf522SAndroid Build Coastguard Worker "--in-app               We are already running in the app's context.\n"
155*288bf522SAndroid Build Coastguard Worker "--out-fd <fd>          Write output to a file descriptor.\n"
156*288bf522SAndroid Build Coastguard Worker "--stop-signal-fd <fd>  Stop recording when fd is readable.\n"
157*288bf522SAndroid Build Coastguard Worker #endif
158*288bf522SAndroid Build Coastguard Worker                 // clang-format on
159*288bf522SAndroid Build Coastguard Worker         ) {
160*288bf522SAndroid Build Coastguard Worker   }
161*288bf522SAndroid Build Coastguard Worker   bool Run(const std::vector<std::string>& args);
162*288bf522SAndroid Build Coastguard Worker 
163*288bf522SAndroid Build Coastguard Worker  private:
164*288bf522SAndroid Build Coastguard Worker   bool ParseOptions(const std::vector<std::string>& args);
165*288bf522SAndroid Build Coastguard Worker   void HandleStopSignal();
166*288bf522SAndroid Build Coastguard Worker   bool CollectRecordingData();
167*288bf522SAndroid Build Coastguard Worker   bool RemoveRecordingData();
168*288bf522SAndroid Build Coastguard Worker 
169*288bf522SAndroid Build Coastguard Worker   std::string app_name_;
170*288bf522SAndroid Build Coastguard Worker   std::string output_filepath_ = "simpleperf_data.zip";
171*288bf522SAndroid Build Coastguard Worker   bool in_app_context_ = false;
172*288bf522SAndroid Build Coastguard Worker   android::base::unique_fd out_fd_;
173*288bf522SAndroid Build Coastguard Worker   android::base::unique_fd stop_signal_fd_;
174*288bf522SAndroid Build Coastguard Worker };
175*288bf522SAndroid Build Coastguard Worker 
Run(const std::vector<std::string> & args)176*288bf522SAndroid Build Coastguard Worker bool CollectCommand::Run(const std::vector<std::string>& args) {
177*288bf522SAndroid Build Coastguard Worker   if (!ParseOptions(args)) {
178*288bf522SAndroid Build Coastguard Worker     return false;
179*288bf522SAndroid Build Coastguard Worker   }
180*288bf522SAndroid Build Coastguard Worker   if (in_app_context_) {
181*288bf522SAndroid Build Coastguard Worker     HandleStopSignal();
182*288bf522SAndroid Build Coastguard Worker     return CollectRecordingData() && RemoveRecordingData();
183*288bf522SAndroid Build Coastguard Worker   }
184*288bf522SAndroid Build Coastguard Worker   return RunInAppContext(app_name_, Name(), args, 0, output_filepath_, false);
185*288bf522SAndroid Build Coastguard Worker }
186*288bf522SAndroid Build Coastguard Worker 
ParseOptions(const std::vector<std::string> & args)187*288bf522SAndroid Build Coastguard Worker bool CollectCommand::ParseOptions(const std::vector<std::string>& args) {
188*288bf522SAndroid Build Coastguard Worker   OptionValueMap options;
189*288bf522SAndroid Build Coastguard Worker   std::vector<std::pair<OptionName, OptionValue>> ordered_options;
190*288bf522SAndroid Build Coastguard Worker   if (!PreprocessOptions(args, GetApiCollectCmdOptionFormats(), &options, &ordered_options,
191*288bf522SAndroid Build Coastguard Worker                          nullptr)) {
192*288bf522SAndroid Build Coastguard Worker     return false;
193*288bf522SAndroid Build Coastguard Worker   }
194*288bf522SAndroid Build Coastguard Worker 
195*288bf522SAndroid Build Coastguard Worker   if (auto value = options.PullValue("--app"); value) {
196*288bf522SAndroid Build Coastguard Worker     app_name_ = value->str_value;
197*288bf522SAndroid Build Coastguard Worker   }
198*288bf522SAndroid Build Coastguard Worker   in_app_context_ = options.PullBoolValue("--in-app");
199*288bf522SAndroid Build Coastguard Worker 
200*288bf522SAndroid Build Coastguard Worker   if (auto value = options.PullValue("-o"); value) {
201*288bf522SAndroid Build Coastguard Worker     output_filepath_ = value->str_value;
202*288bf522SAndroid Build Coastguard Worker   }
203*288bf522SAndroid Build Coastguard Worker   if (auto value = options.PullValue("--out-fd"); value) {
204*288bf522SAndroid Build Coastguard Worker     out_fd_.reset(static_cast<int>(value->uint_value));
205*288bf522SAndroid Build Coastguard Worker   }
206*288bf522SAndroid Build Coastguard Worker   if (auto value = options.PullValue("--stop-signal-fd"); value) {
207*288bf522SAndroid Build Coastguard Worker     stop_signal_fd_.reset(static_cast<int>(value->uint_value));
208*288bf522SAndroid Build Coastguard Worker   }
209*288bf522SAndroid Build Coastguard Worker 
210*288bf522SAndroid Build Coastguard Worker   CHECK(options.values.empty());
211*288bf522SAndroid Build Coastguard Worker   CHECK(ordered_options.empty());
212*288bf522SAndroid Build Coastguard Worker   if (!in_app_context_) {
213*288bf522SAndroid Build Coastguard Worker     if (app_name_.empty()) {
214*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "--app is missing";
215*288bf522SAndroid Build Coastguard Worker       return false;
216*288bf522SAndroid Build Coastguard Worker     }
217*288bf522SAndroid Build Coastguard Worker   }
218*288bf522SAndroid Build Coastguard Worker   return true;
219*288bf522SAndroid Build Coastguard Worker }
220*288bf522SAndroid Build Coastguard Worker 
HandleStopSignal()221*288bf522SAndroid Build Coastguard Worker void CollectCommand::HandleStopSignal() {
222*288bf522SAndroid Build Coastguard Worker   int fd = stop_signal_fd_.release();
223*288bf522SAndroid Build Coastguard Worker   std::thread thread([fd]() {
224*288bf522SAndroid Build Coastguard Worker     char c;
225*288bf522SAndroid Build Coastguard Worker     static_cast<void>(read(fd, &c, 1));
226*288bf522SAndroid Build Coastguard Worker     exit(1);
227*288bf522SAndroid Build Coastguard Worker   });
228*288bf522SAndroid Build Coastguard Worker   thread.detach();
229*288bf522SAndroid Build Coastguard Worker }
230*288bf522SAndroid Build Coastguard Worker 
CollectRecordingData()231*288bf522SAndroid Build Coastguard Worker bool CollectCommand::CollectRecordingData() {
232*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<FILE, decltype(&fclose)> fp(android::base::Fdopen(std::move(out_fd_), "w"),
233*288bf522SAndroid Build Coastguard Worker                                               fclose);
234*288bf522SAndroid Build Coastguard Worker   if (fp == nullptr) {
235*288bf522SAndroid Build Coastguard Worker     PLOG(ERROR) << "failed to call fdopen";
236*288bf522SAndroid Build Coastguard Worker     return false;
237*288bf522SAndroid Build Coastguard Worker   }
238*288bf522SAndroid Build Coastguard Worker   std::vector<char> buffer(64 * 1024);
239*288bf522SAndroid Build Coastguard Worker   ZipWriter zip_writer(fp.get());
240*288bf522SAndroid Build Coastguard Worker   for (const auto& name : GetEntriesInDir(SIMPLEPERF_DATA_DIR)) {
241*288bf522SAndroid Build Coastguard Worker     // No need to collect temporary files.
242*288bf522SAndroid Build Coastguard Worker     const std::string path = SIMPLEPERF_DATA_DIR + "/" + name;
243*288bf522SAndroid Build Coastguard Worker     if (android::base::StartsWith(name, "TemporaryFile-") || !IsRegularFile(path)) {
244*288bf522SAndroid Build Coastguard Worker       continue;
245*288bf522SAndroid Build Coastguard Worker     }
246*288bf522SAndroid Build Coastguard Worker     int result = zip_writer.StartEntry(name.c_str(), ZipWriter::kCompress);
247*288bf522SAndroid Build Coastguard Worker     if (result != 0) {
248*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "failed to start zip entry " << name << ": "
249*288bf522SAndroid Build Coastguard Worker                  << zip_writer.ErrorCodeString(result);
250*288bf522SAndroid Build Coastguard Worker       return false;
251*288bf522SAndroid Build Coastguard Worker     }
252*288bf522SAndroid Build Coastguard Worker     android::base::unique_fd in_fd(FileHelper::OpenReadOnly(path));
253*288bf522SAndroid Build Coastguard Worker     if (in_fd == -1) {
254*288bf522SAndroid Build Coastguard Worker       PLOG(ERROR) << "failed to open " << path;
255*288bf522SAndroid Build Coastguard Worker       return false;
256*288bf522SAndroid Build Coastguard Worker     }
257*288bf522SAndroid Build Coastguard Worker     while (true) {
258*288bf522SAndroid Build Coastguard Worker       ssize_t nread = TEMP_FAILURE_RETRY(read(in_fd, buffer.data(), buffer.size()));
259*288bf522SAndroid Build Coastguard Worker       if (nread < 0) {
260*288bf522SAndroid Build Coastguard Worker         PLOG(ERROR) << "failed to read " << path;
261*288bf522SAndroid Build Coastguard Worker         return false;
262*288bf522SAndroid Build Coastguard Worker       }
263*288bf522SAndroid Build Coastguard Worker       if (nread == 0) {
264*288bf522SAndroid Build Coastguard Worker         break;
265*288bf522SAndroid Build Coastguard Worker       }
266*288bf522SAndroid Build Coastguard Worker       result = zip_writer.WriteBytes(buffer.data(), nread);
267*288bf522SAndroid Build Coastguard Worker       if (result != 0) {
268*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "failed to write zip entry " << name << ": "
269*288bf522SAndroid Build Coastguard Worker                    << zip_writer.ErrorCodeString(result);
270*288bf522SAndroid Build Coastguard Worker         return false;
271*288bf522SAndroid Build Coastguard Worker       }
272*288bf522SAndroid Build Coastguard Worker     }
273*288bf522SAndroid Build Coastguard Worker     result = zip_writer.FinishEntry();
274*288bf522SAndroid Build Coastguard Worker     if (result != 0) {
275*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "failed to finish zip entry " << name << ": "
276*288bf522SAndroid Build Coastguard Worker                  << zip_writer.ErrorCodeString(result);
277*288bf522SAndroid Build Coastguard Worker       return false;
278*288bf522SAndroid Build Coastguard Worker     }
279*288bf522SAndroid Build Coastguard Worker   }
280*288bf522SAndroid Build Coastguard Worker   int result = zip_writer.Finish();
281*288bf522SAndroid Build Coastguard Worker   if (result != 0) {
282*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "failed to finish zip writer: " << zip_writer.ErrorCodeString(result);
283*288bf522SAndroid Build Coastguard Worker     return false;
284*288bf522SAndroid Build Coastguard Worker   }
285*288bf522SAndroid Build Coastguard Worker   return true;
286*288bf522SAndroid Build Coastguard Worker }
287*288bf522SAndroid Build Coastguard Worker 
RemoveRecordingData()288*288bf522SAndroid Build Coastguard Worker bool CollectCommand::RemoveRecordingData() {
289*288bf522SAndroid Build Coastguard Worker   return Workload::RunCmd({"rm", "-rf", SIMPLEPERF_DATA_DIR});
290*288bf522SAndroid Build Coastguard Worker }
291*288bf522SAndroid Build Coastguard Worker }  // namespace
292*288bf522SAndroid Build Coastguard Worker 
RegisterAPICommands()293*288bf522SAndroid Build Coastguard Worker void RegisterAPICommands() {
294*288bf522SAndroid Build Coastguard Worker   RegisterCommand("api-prepare", [] { return std::unique_ptr<Command>(new PrepareCommand()); });
295*288bf522SAndroid Build Coastguard Worker   RegisterCommand("api-collect", [] { return std::unique_ptr<Command>(new CollectCommand()); });
296*288bf522SAndroid Build Coastguard Worker }
297*288bf522SAndroid Build Coastguard Worker 
298*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
299