blob: 3727a7f051669ca8f9534cfa4d1d1857e63ef8b3 [file] [log] [blame]
Primiano Tucci3b729102018-01-08 18:16:36 +00001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Primiano Tucci3cbb10a2018-04-10 17:52:40 +010017#include "src/perfetto_cmd/perfetto_cmd.h"
Hector Dearman86cfbe12018-03-22 11:58:42 +000018
Sami Kyostila26d5cdd2018-01-15 16:42:06 +000019#include <fcntl.h>
Primiano Tucci3b729102018-01-08 18:16:36 +000020#include <getopt.h>
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010021#include <signal.h>
Hector Dearman86cfbe12018-03-22 11:58:42 +000022#include <stdio.h>
Sami Kyostilab5b71692018-01-12 12:16:44 +000023#include <sys/stat.h>
Ryan Savitski26f1dcd2019-05-30 12:23:16 +010024#include <sys/types.h>
Hector Dearman86cfbe12018-03-22 11:58:42 +000025#include <time.h>
Primiano Tuccif3837d52018-01-10 21:12:41 +000026#include <unistd.h>
Primiano Tucci3b729102018-01-08 18:16:36 +000027
28#include <fstream>
29#include <iostream>
30#include <iterator>
Sami Kyostila26d5cdd2018-01-15 16:42:06 +000031#include <sstream>
Primiano Tucci3b729102018-01-08 18:16:36 +000032
Hector Dearmana5b90822019-11-18 13:00:16 +000033#include "perfetto/base/compiler.h"
Primiano Tucci3b729102018-01-08 18:16:36 +000034#include "perfetto/base/logging.h"
Eric Seckler83dcc8c2019-08-21 12:18:43 +010035#include "perfetto/base/time.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010036#include "perfetto/ext/base/file_utils.h"
37#include "perfetto/ext/base/string_view.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010038#include "perfetto/ext/base/utils.h"
Hector Dearmana5b90822019-11-18 13:00:16 +000039#include "perfetto/ext/base/uuid.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010040#include "perfetto/ext/traced/traced.h"
41#include "perfetto/ext/tracing/core/basic_types.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010042#include "perfetto/ext/tracing/core/trace_packet.h"
Stephen Nuskoac0c1972019-06-25 13:57:13 +010043#include "perfetto/ext/tracing/ipc/default_socket.h"
Hector Dearman20b3c1c2018-01-15 15:34:03 +000044#include "perfetto/protozero/proto_utils.h"
Primiano Tucci0f9e0222019-06-05 09:36:41 +010045#include "perfetto/tracing/core/data_source_config.h"
46#include "perfetto/tracing/core/data_source_descriptor.h"
47#include "perfetto/tracing/core/trace_config.h"
48#include "perfetto/tracing/core/tracing_service_state.h"
Hector Dearman5edeafc2018-11-29 13:27:33 +000049#include "src/perfetto_cmd/config.h"
Hector Dearman554627f2019-06-04 17:58:22 +010050#include "src/perfetto_cmd/packet_writer.h"
Hector Dearmanb7fa5442018-11-08 18:39:32 +000051#include "src/perfetto_cmd/pbtxt_to_pb.h"
Stephen Nuskoe8238112019-04-09 18:37:00 +010052#include "src/perfetto_cmd/trigger_producer.h"
Florian Mayerc29e0d32018-04-04 15:55:46 +010053
Primiano Tucci355b8c82019-08-29 08:37:51 +020054#include "protos/perfetto/common/tracing_service_state.pb.h"
55#include "protos/perfetto/config/trace_config.pb.h"
Primiano Tucciedf099c2018-01-08 18:27:56 +000056
Primiano Tucci3b729102018-01-08 18:16:36 +000057namespace perfetto {
Sami Kyostilab5b71692018-01-12 12:16:44 +000058namespace {
Sami Kyostila0b99a3b2018-01-30 18:05:59 +000059
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010060perfetto::PerfettoCmd* g_consumer_cmd;
Sami Kyostila0b99a3b2018-01-30 18:05:59 +000061
Hector Dearmaneb5c71e2019-07-30 14:00:23 +010062uint32_t kOnTraceDataTimeoutMs = 3000;
63
Hector Dearmanb7fa5442018-11-08 18:39:32 +000064class LoggingErrorReporter : public ErrorReporter {
65 public:
66 LoggingErrorReporter(std::string file_name, const char* config)
67 : file_name_(file_name), config_(config) {}
68
69 void AddError(size_t row,
70 size_t column,
71 size_t length,
72 const std::string& message) override {
73 parsed_successfully_ = false;
74 std::string line = ExtractLine(row - 1).ToStdString();
75 if (!line.empty() && line[line.length() - 1] == '\n') {
76 line.erase(line.length() - 1);
77 }
78
79 std::string guide(column + length, ' ');
80 for (size_t i = column; i < column + length; i++) {
81 guide[i - 1] = i == column ? '^' : '~';
82 }
83 fprintf(stderr, "%s:%zu:%zu error: %s\n", file_name_.c_str(), row, column,
84 message.c_str());
85 fprintf(stderr, "%s\n", line.c_str());
86 fprintf(stderr, "%s\n", guide.c_str());
87 }
88
89 bool Success() const { return parsed_successfully_; }
90
91 private:
92 base::StringView ExtractLine(size_t line) {
93 const char* start = config_;
94 const char* end = config_;
95
96 for (size_t i = 0; i < line + 1; i++) {
97 start = end;
98 char c;
99 while ((c = *end++) && c != '\n')
100 ;
101 }
102 return base::StringView(start, static_cast<size_t>(end - start));
103 }
104
105 bool parsed_successfully_ = true;
106 std::string file_name_;
107 const char* config_;
108};
109
110bool ParseTraceConfigPbtxt(const std::string& file_name,
111 const std::string& pbtxt,
112 protos::TraceConfig* config) {
113 LoggingErrorReporter reporter(file_name, pbtxt.c_str());
114 std::vector<uint8_t> buf = PbtxtToPb(pbtxt, &reporter);
115 if (!reporter.Success())
116 return false;
117 if (!config->ParseFromArray(buf.data(), static_cast<int>(buf.size())))
118 return false;
119 return true;
120}
121
Sami Kyostilab5b71692018-01-12 12:16:44 +0000122} // namespace
Primiano Tucci3b729102018-01-08 18:16:36 +0000123
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100124const char* kStateDir = "/data/misc/perfetto-traces";
Ryan Savitski53ca60b2019-06-03 13:04:40 +0100125
Hector Dearman20b3c1c2018-01-15 15:34:03 +0000126using protozero::proto_utils::MakeTagLengthDelimited;
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100127using protozero::proto_utils::WriteVarInt;
Hector Dearman20b3c1c2018-01-15 15:34:03 +0000128
Primiano Tucci3b729102018-01-08 18:16:36 +0000129int PerfettoCmd::PrintUsage(const char* argv0) {
Primiano Tucci7e2b67a2018-01-16 16:38:49 +0000130 PERFETTO_ELOG(R"(
131Usage: %s
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100132 --background -d : Exits immediately and continues tracing in
133 background
Stephen Nuskoe8238112019-04-09 18:37:00 +0100134 --config -c : /path/to/trace/config/file or - for stdin
135 --out -o : /path/to/out/trace/file or - for stdout
136 --dropbox TAG : Upload trace into DropBox using tag TAG
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100137 --no-guardrails : Ignore guardrails triggered when using --dropbox
138 (for testing).
139 --txt : Parse config as pbtxt. Not for production use.
140 Not a stable API.
141 --reset-guardrails : Resets the state of the guardails and exits
142 (for testing).
143 --query : Queries the service state and prints it as
144 human-readable text.
145 --query-raw : Like --query, but prints raw proto-encoded bytes
146 of tracing_service_state.proto.
Hector Dearman86cfbe12018-03-22 11:58:42 +0000147 --help -h
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100148
Hector Dearman5edeafc2018-11-29 13:27:33 +0000149
150light configuration flags: (only when NOT using -c/--config)
151 --time -t : Trace duration N[s,m,h] (default: 10s)
152 --buffer -b : Ring buffer size N[mb,gb] (default: 32mb)
Primiano Tucciaaf562c2018-12-04 21:21:36 +0000153 --size -s : Max file size N[mb,gb] (default: in-memory ring-buffer only)
Hector Dearman5edeafc2018-11-29 13:27:33 +0000154 ATRACE_CAT : Record ATRACE_CAT (e.g. wm)
155 FTRACE_GROUP/FTRACE_NAME : Record ftrace event (e.g. sched/sched_switch)
156 FTRACE_GROUP/* : Record all events in group (e.g. sched/*)
157
158
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100159statsd-specific flags:
160 --alert-id : ID of the alert that triggered this trace.
161 --config-id : ID of the triggering config.
162 --config-uid : UID of app which registered the config.
Lalit Magantid9930082019-01-14 14:33:26 +0000163 --subscription-id : ID of the subscription that triggered this trace.
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100164
165Detach mode. DISCOURAGED, read https://docs.perfetto.dev/#/detached-mode :
166 --detach=key : Detach from the tracing session with the given key.
167 --attach=key [--stop] : Re-attach to the session (optionally stop tracing once reattached).
Primiano Tucciacefff72019-01-06 21:02:20 +0000168 --is_detached=key : Check if the session can be re-attached (0:Yes, 2:No, 1:Error).
Primiano Tucci7e2b67a2018-01-16 16:38:49 +0000169)",
Hector Dearman93b5d902018-12-05 19:43:32 +0000170 argv0);
Primiano Tucci3b729102018-01-08 18:16:36 +0000171 return 1;
172}
173
174int PerfettoCmd::Main(int argc, char** argv) {
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100175 umask(0000); // make sure that file creation is not affected by umask.
Ryan Savitski26f1dcd2019-05-30 12:23:16 +0100176
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100177 enum LongOption {
178 OPT_ALERT_ID = 1000,
179 OPT_CONFIG_ID,
180 OPT_CONFIG_UID,
Lalit Magantid9930082019-01-14 14:33:26 +0000181 OPT_SUBSCRIPTION_ID,
Primiano Tucci8a11cf72018-07-18 16:52:29 +0100182 OPT_RESET_GUARDRAILS,
Hector Dearman5edeafc2018-11-29 13:27:33 +0000183 OPT_PBTXT_CONFIG,
184 OPT_DROPBOX,
185 OPT_ATRACE_APP,
186 OPT_IGNORE_GUARDRAILS,
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100187 OPT_DETACH,
188 OPT_ATTACH,
Primiano Tucciacefff72019-01-06 21:02:20 +0000189 OPT_IS_DETACHED,
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100190 OPT_STOP,
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100191 OPT_QUERY,
192 OPT_QUERY_RAW,
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100193 };
Primiano Tucci3b729102018-01-08 18:16:36 +0000194 static const struct option long_options[] = {
Florian Mayer7bf6b812019-04-04 20:32:37 +0100195 {"help", no_argument, nullptr, 'h'},
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100196 {"config", required_argument, nullptr, 'c'},
197 {"out", required_argument, nullptr, 'o'},
Hector Dearman5edeafc2018-11-29 13:27:33 +0000198 {"background", no_argument, nullptr, 'd'},
199 {"time", required_argument, nullptr, 't'},
200 {"buffer", required_argument, nullptr, 'b'},
201 {"size", required_argument, nullptr, 's'},
Hector Dearman93b5d902018-12-05 19:43:32 +0000202 {"no-guardrails", no_argument, nullptr, OPT_IGNORE_GUARDRAILS},
203 {"txt", no_argument, nullptr, OPT_PBTXT_CONFIG},
204 {"dropbox", required_argument, nullptr, OPT_DROPBOX},
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100205 {"alert-id", required_argument, nullptr, OPT_ALERT_ID},
206 {"config-id", required_argument, nullptr, OPT_CONFIG_ID},
207 {"config-uid", required_argument, nullptr, OPT_CONFIG_UID},
Lalit Magantid9930082019-01-14 14:33:26 +0000208 {"subscription-id", required_argument, nullptr, OPT_SUBSCRIPTION_ID},
Primiano Tucci8a11cf72018-07-18 16:52:29 +0100209 {"reset-guardrails", no_argument, nullptr, OPT_RESET_GUARDRAILS},
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100210 {"detach", required_argument, nullptr, OPT_DETACH},
211 {"attach", required_argument, nullptr, OPT_ATTACH},
Primiano Tucciacefff72019-01-06 21:02:20 +0000212 {"is_detached", required_argument, nullptr, OPT_IS_DETACHED},
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100213 {"stop", no_argument, nullptr, OPT_STOP},
Hector Dearman5edeafc2018-11-29 13:27:33 +0000214 {"app", required_argument, nullptr, OPT_ATRACE_APP},
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100215 {"query", no_argument, nullptr, OPT_QUERY},
216 {"query-raw", no_argument, nullptr, OPT_QUERY_RAW},
Primiano Tuccif3837d52018-01-10 21:12:41 +0000217 {nullptr, 0, nullptr, 0}};
Primiano Tucci3b729102018-01-08 18:16:36 +0000218
219 int option_index = 0;
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000220 std::string config_file_name;
Primiano Tucci3b729102018-01-08 18:16:36 +0000221 std::string trace_config_raw;
Primiano Tuccif3837d52018-01-10 21:12:41 +0000222 bool background = false;
Hector Dearman86cfbe12018-03-22 11:58:42 +0000223 bool ignore_guardrails = false;
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000224 bool parse_as_pbtxt = false;
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100225 perfetto::protos::TraceConfig::StatsdMetadata statsd_metadata;
Primiano Tucci8a11cf72018-07-18 16:52:29 +0100226 RateLimiter limiter;
227
Hector Dearman5edeafc2018-11-29 13:27:33 +0000228 ConfigOptions config_options;
229 bool has_config_options = false;
230
Primiano Tucci3b729102018-01-08 18:16:36 +0000231 for (;;) {
Sami Kyostilab5b71692018-01-12 12:16:44 +0000232 int option =
Florian Mayer7bf6b812019-04-04 20:32:37 +0100233 getopt_long(argc, argv, "hc:o:dt:b:s:", long_options, &option_index);
Primiano Tucci3b729102018-01-08 18:16:36 +0000234
235 if (option == -1)
236 break; // EOF.
237
238 if (option == 'c') {
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000239 config_file_name = std::string(optarg);
Primiano Tucci3b729102018-01-08 18:16:36 +0000240 if (strcmp(optarg, "-") == 0) {
241 std::istreambuf_iterator<char> begin(std::cin), end;
242 trace_config_raw.assign(begin, end);
243 } else if (strcmp(optarg, ":test") == 0) {
244 // TODO(primiano): temporary for testing only.
245 perfetto::protos::TraceConfig test_config;
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000246 test_config.add_buffers()->set_size_kb(4096);
Hector Dearman86cfbe12018-03-22 11:58:42 +0000247 test_config.set_duration_ms(2000);
Primiano Tucci3b729102018-01-08 18:16:36 +0000248 auto* ds_config = test_config.add_data_sources()->mutable_config();
Primiano Tucci578d7842018-03-29 15:27:05 +0100249 ds_config->set_name("linux.ftrace");
Hector Dearmand410c822018-02-23 15:46:18 +0000250 ds_config->mutable_ftrace_config()->add_ftrace_events("sched_switch");
251 ds_config->mutable_ftrace_config()->add_ftrace_events("cpu_idle");
252 ds_config->mutable_ftrace_config()->add_ftrace_events("cpu_frequency");
Sidath Senanayake1f5f93a2019-06-06 22:24:15 +0100253 ds_config->mutable_ftrace_config()->add_ftrace_events("gpu_frequency");
Primiano Tucci20d441d2018-01-16 09:25:51 +0000254 ds_config->set_target_buffer(0);
Primiano Tucci3b729102018-01-08 18:16:36 +0000255 test_config.SerializeToString(&trace_config_raw);
256 } else {
Florian Mayer74b73a92018-03-09 17:37:13 +0000257 if (!base::ReadFile(optarg, &trace_config_raw)) {
Florian Mayer8ede4ac2018-03-27 13:13:56 +0100258 PERFETTO_PLOG("Could not open %s", optarg);
Primiano Tucci3b729102018-01-08 18:16:36 +0000259 return 1;
260 }
Primiano Tucci3b729102018-01-08 18:16:36 +0000261 }
262 continue;
263 }
264
265 if (option == 'o') {
266 trace_out_path_ = optarg;
Primiano Tucci3b729102018-01-08 18:16:36 +0000267 continue;
268 }
269
Sami Kyostilab5b71692018-01-12 12:16:44 +0000270 if (option == 'd') {
Hector Dearman5edeafc2018-11-29 13:27:33 +0000271 background = true;
272 continue;
273 }
274 if (option == 't') {
275 has_config_options = true;
276 config_options.time = std::string(optarg);
277 continue;
278 }
279
280 if (option == 'b') {
281 has_config_options = true;
282 config_options.buffer_size = std::string(optarg);
283 continue;
284 }
285
286 if (option == 's') {
287 has_config_options = true;
288 config_options.max_file_size = std::string(optarg);
289 continue;
290 }
291
292 if (option == OPT_DROPBOX) {
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100293#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
294 PERFETTO_CHECK(optarg);
Hector Dearman93b5d902018-12-05 19:43:32 +0000295 dropbox_tag_ = optarg;
Sami Kyostilab5b71692018-01-12 12:16:44 +0000296 continue;
297#else
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100298 PERFETTO_ELOG("--dropbox is supported only on Android");
Sami Kyostilab5b71692018-01-12 12:16:44 +0000299 return 1;
300#endif
301 }
302
Hector Dearman5edeafc2018-11-29 13:27:33 +0000303 if (option == OPT_PBTXT_CONFIG) {
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000304 parse_as_pbtxt = true;
305 continue;
306 }
307
Hector Dearman5edeafc2018-11-29 13:27:33 +0000308 if (option == OPT_IGNORE_GUARDRAILS) {
309 ignore_guardrails = true;
310 continue;
311 }
312
Primiano Tucci8a11cf72018-07-18 16:52:29 +0100313 if (option == OPT_RESET_GUARDRAILS) {
314 PERFETTO_CHECK(limiter.ClearState());
315 PERFETTO_ILOG("Guardrail state cleared");
316 return 0;
317 }
318
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100319 if (option == OPT_ALERT_ID) {
320 statsd_metadata.set_triggering_alert_id(atoll(optarg));
321 continue;
322 }
323
324 if (option == OPT_CONFIG_ID) {
325 statsd_metadata.set_triggering_config_id(atoll(optarg));
326 continue;
327 }
328
329 if (option == OPT_CONFIG_UID) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100330 statsd_metadata.set_triggering_config_uid(atoi(optarg));
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100331 continue;
332 }
333
Lalit Magantid9930082019-01-14 14:33:26 +0000334 if (option == OPT_SUBSCRIPTION_ID) {
335 statsd_metadata.set_triggering_subscription_id(atoll(optarg));
336 continue;
337 }
338
Hector Dearman5edeafc2018-11-29 13:27:33 +0000339 if (option == OPT_ATRACE_APP) {
340 config_options.atrace_apps.push_back(std::string(optarg));
341 has_config_options = true;
342 continue;
343 }
344
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100345 if (option == OPT_DETACH) {
346 detach_key_ = std::string(optarg);
347 PERFETTO_CHECK(!detach_key_.empty());
348 continue;
349 }
350
351 if (option == OPT_ATTACH) {
352 attach_key_ = std::string(optarg);
353 PERFETTO_CHECK(!attach_key_.empty());
354 continue;
355 }
356
Primiano Tucciacefff72019-01-06 21:02:20 +0000357 if (option == OPT_IS_DETACHED) {
358 attach_key_ = std::string(optarg);
359 redetach_once_attached_ = true;
360 PERFETTO_CHECK(!attach_key_.empty());
361 continue;
362 }
363
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100364 if (option == OPT_STOP) {
365 stop_trace_once_attached_ = true;
366 continue;
367 }
368
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100369 if (option == OPT_QUERY) {
370 query_service_ = true;
371 continue;
372 }
373
374 if (option == OPT_QUERY_RAW) {
375 query_service_ = true;
376 query_service_output_raw_ = true;
377 continue;
378 }
379
Primiano Tucci3b729102018-01-08 18:16:36 +0000380 return PrintUsage(argv[0]);
381 }
382
Hector Dearman5edeafc2018-11-29 13:27:33 +0000383 for (ssize_t i = optind; i < argc; i++) {
384 has_config_options = true;
385 config_options.categories.push_back(argv[i]);
386 }
387
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100388 if (query_service_ && (is_detach() || is_attach() || background)) {
389 PERFETTO_ELOG("--query cannot be combined with any other argument");
390 return 1;
391 }
392
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100393 if (is_detach() && is_attach()) {
394 PERFETTO_ELOG("--attach and --detach are mutually exclusive");
Sami Kyostilab5b71692018-01-12 12:16:44 +0000395 return 1;
396 }
397
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100398 if (is_detach() && background) {
399 PERFETTO_ELOG("--detach and --background are mutually exclusive");
400 return 1;
Sami Kyostilab5b71692018-01-12 12:16:44 +0000401 }
402
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100403 if (stop_trace_once_attached_ && !is_attach()) {
404 PERFETTO_ELOG("--stop is supported only in combination with --attach");
405 return 1;
406 }
Hector Dearman5edeafc2018-11-29 13:27:33 +0000407
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100408 // Parse the trace config. It can be either:
409 // 1) A proto-encoded file/stdin (-c ...).
410 // 2) A proto-text file/stdin (-c ... --txt).
411 // 3) A set of option arguments (-t 10s -s 10m).
Hector Dearman696ff772019-04-23 18:38:53 +0100412 // The only cases in which a trace config is not expected is --attach.
413 // For this we are just acting on already existing sessions.
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100414 perfetto::protos::TraceConfig trace_config_proto;
Hector Dearman696ff772019-04-23 18:38:53 +0100415 std::vector<std::string> triggers_to_activate;
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100416 bool parsed = false;
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100417 const bool will_trace = !is_attach() && !query_service_;
418 if (!will_trace) {
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100419 if ((!trace_config_raw.empty() || has_config_options)) {
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100420 PERFETTO_ELOG("Cannot specify a trace config with this option");
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100421 return 1;
422 }
423 } else if (has_config_options) {
Hector Dearman5edeafc2018-11-29 13:27:33 +0000424 if (!trace_config_raw.empty()) {
425 PERFETTO_ELOG(
426 "Cannot specify both -c/--config and any of --time, --size, "
427 "--buffer, --app, ATRACE_CAT, FTRACE_EVENT");
428 return 1;
429 }
430 parsed = CreateConfigFromOptions(config_options, &trace_config_proto);
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000431 } else {
Hector Dearman5edeafc2018-11-29 13:27:33 +0000432 if (trace_config_raw.empty()) {
433 PERFETTO_ELOG("The TraceConfig is empty");
434 return 1;
435 }
Hector Dearman5edeafc2018-11-29 13:27:33 +0000436 PERFETTO_DLOG("Parsing TraceConfig, %zu bytes", trace_config_raw.size());
437 if (parse_as_pbtxt) {
438 parsed = ParseTraceConfigPbtxt(config_file_name, trace_config_raw,
439 &trace_config_proto);
440 } else {
441 parsed = trace_config_proto.ParseFromString(trace_config_raw);
442 }
Primiano Tucciaaf562c2018-12-04 21:21:36 +0000443 }
Hector Dearman5edeafc2018-11-29 13:27:33 +0000444
Primiano Tuccie65fc292019-01-08 00:45:25 +0000445 trace_config_.reset(new TraceConfig());
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100446 if (parsed) {
447 *trace_config_proto.mutable_statsd_metadata() = std::move(statsd_metadata);
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100448 trace_config_->FromProto(trace_config_proto);
449 trace_config_raw.clear();
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100450 } else if (will_trace) {
Primiano Tucciaaf562c2018-12-04 21:21:36 +0000451 PERFETTO_ELOG("The trace config is invalid, bailing out.");
452 return 1;
Hector Dearmanb7fa5442018-11-08 18:39:32 +0000453 }
454
Hector Dearman9dded812019-11-15 11:59:46 +0000455 if (trace_config_->trace_uuid_lsb() == 0 &&
456 trace_config_->trace_uuid_msb() == 0) {
457 base::Uuid uuid = base::Uuidv4();
Hector Dearman5e88eef2019-11-18 12:57:47 +0000458 uuid_ = uuid.ToString();
459 trace_config_->set_trace_uuid_msb(uuid.msb());
460 trace_config_->set_trace_uuid_lsb(uuid.lsb());
Hector Dearman9dded812019-11-15 11:59:46 +0000461 } else {
Hector Dearman5e88eef2019-11-18 12:57:47 +0000462 base::Uuid uuid(trace_config_->trace_uuid_lsb(),
463 trace_config_->trace_uuid_msb());
464 uuid_ = uuid.ToString();
Hector Dearman2bdd2be2019-08-07 14:50:37 +0100465 }
466
Ryan Savitski53ca60b2019-06-03 13:04:40 +0100467 if (!trace_config_->incident_report_config().destination_package().empty()) {
468 if (dropbox_tag_.empty()) {
469 PERFETTO_ELOG("Unexpected IncidentReportConfig without --dropbox.");
470 return 1;
471 }
472 }
473
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100474 // Set up the output file. Either --out or --dropbox are expected, with the
475 // only exception of --attach. In this case the output file is passed when
476 // detaching.
477 if (!trace_out_path_.empty() && !dropbox_tag_.empty()) {
478 PERFETTO_ELOG(
479 "Can't log to a file (--out) and DropBox (--dropbox) at the same "
480 "time");
481 return 1;
482 }
Primiano Tucci3b729102018-01-08 18:16:36 +0000483
Hector Dearman696ff772019-04-23 18:38:53 +0100484 // |activate_triggers| in the trace config is shorthand for trigger_perfetto.
485 // In this case we don't intend to send any trace config to the service,
486 // rather use that as a signal to the cmdline client to connect as a producer
487 // and activate triggers.
Stephen Nusko9fa59cb2019-04-15 04:19:16 +0100488 if (!trace_config_->activate_triggers().empty()) {
489 for (const auto& trigger : trace_config_->activate_triggers()) {
490 triggers_to_activate.push_back(trigger);
491 }
492 trace_config_.reset(new TraceConfig());
493 }
494
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100495 bool open_out_file = true;
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100496 if (!will_trace) {
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100497 open_out_file = false;
498 if (!trace_out_path_.empty() || !dropbox_tag_.empty()) {
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100499 PERFETTO_ELOG("Can't pass an --out file (or --dropbox) with this option");
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100500 return 1;
501 }
Stephen Nuskoe8238112019-04-09 18:37:00 +0100502 } else if (!triggers_to_activate.empty()) {
503 open_out_file = false;
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100504 } else if (trace_out_path_.empty() && dropbox_tag_.empty()) {
505 PERFETTO_ELOG("Either --out or --dropbox is required");
506 return 1;
507 } else if (is_detach() && !trace_config_->write_into_file()) {
508 // In detached mode we must pass the file descriptor to the service and
509 // let that one write the trace. We cannot use the IPC readback code path
510 // because the client process is about to exit soon after detaching.
511 PERFETTO_ELOG(
512 "TraceConfig's write_into_file must be true when using --detach");
513 return 1;
514 }
Hector Dearman554627f2019-06-04 17:58:22 +0100515 if (open_out_file) {
516 if (!OpenOutputFile())
517 return 1;
518 if (!trace_config_->write_into_file())
519 packet_writer_ = CreateFilePacketWriter(trace_out_stream_.get());
520 }
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000521
Primiano Tuccif3837d52018-01-10 21:12:41 +0000522 if (background) {
Florian Mayerdb1b6f42018-11-21 18:36:08 +0000523 pid_t pid;
524 switch (pid = fork()) {
525 case -1:
526 PERFETTO_FATAL("fork");
527 case 0: {
528 PERFETTO_CHECK(setsid() != -1);
Primiano Tucci2b7b6742018-11-23 08:35:12 +0000529 base::ignore_result(chdir("/"));
Florian Mayerdb1b6f42018-11-21 18:36:08 +0000530 base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
531 PERFETTO_CHECK(null);
532 PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
533 PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
534 PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
535 // Do not accidentally close stdin/stdout/stderr.
536 if (*null <= 2)
537 null.release();
538 break;
539 }
540 default:
541 printf("%d\n", pid);
542 exit(0);
543 }
Primiano Tuccif3837d52018-01-10 21:12:41 +0000544 }
545
Stephen Nuskoe8238112019-04-09 18:37:00 +0100546 // If we are just activating triggers then we don't need to rate limit,
547 // connect as a consumer or run the trace. So bail out after processing all
548 // the options.
549 if (!triggers_to_activate.empty()) {
Hector Dearmana5b90822019-11-18 13:00:16 +0000550 LogUploadEvent(PerfettoStatsdAtom::kTriggerBegin);
Stephen Nuskoe8238112019-04-09 18:37:00 +0100551 bool finished_with_success = false;
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100552 TriggerProducer producer(
553 &task_runner_,
554 [this, &finished_with_success](bool success) {
555 finished_with_success = success;
556 task_runner_.Quit();
557 },
558 &triggers_to_activate);
Stephen Nuskoe8238112019-04-09 18:37:00 +0100559 task_runner_.Run();
Hector Dearmana5b90822019-11-18 13:00:16 +0000560 if (finished_with_success) {
561 LogUploadEvent(PerfettoStatsdAtom::kTriggerSuccess);
562 } else {
563 LogUploadEvent(PerfettoStatsdAtom::kTriggerFailure);
564 }
Stephen Nuskoe8238112019-04-09 18:37:00 +0100565 return finished_with_success ? 0 : 1;
566 }
567
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100568 if (query_service_) {
569 consumer_endpoint_ =
570 ConsumerIPCClient::Connect(GetConsumerSocket(), this, &task_runner_);
571 task_runner_.Run();
572 return 1; // We can legitimately get here if the service disconnects.
573 }
574
Hector Dearman554627f2019-06-04 17:58:22 +0100575 if (trace_config_->compression_type() ==
576 perfetto::TraceConfig::COMPRESSION_TYPE_DEFLATE) {
577 if (packet_writer_) {
578 packet_writer_ = CreateZipPacketWriter(std::move(packet_writer_));
579 } else {
580 PERFETTO_ELOG("Cannot compress when tracing directly to file.");
581 }
582 }
583
Hector Dearman86cfbe12018-03-22 11:58:42 +0000584 RateLimiter::Args args{};
585 args.is_dropbox = !dropbox_tag_.empty();
586 args.current_time = base::GetWallTimeS();
587 args.ignore_guardrails = ignore_guardrails;
Hector Dearman085dc3c2019-04-23 11:48:10 +0100588 args.allow_user_build_tracing = trace_config_->allow_user_build_tracing();
Primiano Tuccie65fc292019-01-08 00:45:25 +0000589#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_USERDEBUG_BUILD) || \
590 PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD)
Lalit Magantid8b1a1d2018-05-23 14:41:43 +0100591 args.max_upload_bytes_override =
592 trace_config_->guardrail_overrides().max_upload_per_day_bytes();
593#endif
Hector Dearmana868a072019-05-10 15:53:00 +0100594
Ryan Savitski23a22dd2019-05-29 20:37:21 +0100595 if (args.is_dropbox && !args.ignore_guardrails &&
596 (trace_config_->duration_ms() == 0 &&
597 trace_config_->trigger_config().trigger_timeout_ms() == 0)) {
598 PERFETTO_ELOG("Can't trace indefinitely when tracing to Dropbox.");
Hector Dearmana868a072019-05-10 15:53:00 +0100599 return 1;
600 }
601
Hector Dearmaneb5c71e2019-07-30 14:00:23 +0100602 expected_duration_ms_ = trace_config_->duration_ms();
603 if (!expected_duration_ms_) {
604 uint32_t timeout_ms = trace_config_->trigger_config().trigger_timeout_ms();
605 uint32_t max_stop_delay_ms = 0;
606 for (const auto& trigger : trace_config_->trigger_config().triggers()) {
607 max_stop_delay_ms = std::max(max_stop_delay_ms, trigger.stop_delay_ms());
608 }
609 expected_duration_ms_ = timeout_ms + max_stop_delay_ms;
610 }
611
Hector Dearmana5b90822019-11-18 13:00:16 +0000612 if (trace_config_->trigger_config().trigger_timeout_ms() == 0) {
613 LogUploadEvent(PerfettoStatsdAtom::kTraceBegin);
614 } else {
615 LogUploadEvent(PerfettoStatsdAtom::kBackgroundTraceBegin);
616 }
617
618 if (!limiter.ShouldTrace(args)) {
619 LogUploadEvent(PerfettoStatsdAtom::kHitGuardrails);
Hector Dearman86cfbe12018-03-22 11:58:42 +0000620 return 1;
Hector Dearmana5b90822019-11-18 13:00:16 +0000621 }
Hector Dearman86cfbe12018-03-22 11:58:42 +0000622
Florian Mayerc29e0d32018-04-04 15:55:46 +0100623 consumer_endpoint_ =
624 ConsumerIPCClient::Connect(GetConsumerSocket(), this, &task_runner_);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100625 SetupCtrlCSignalHandler();
Primiano Tucci3b729102018-01-08 18:16:36 +0000626 task_runner_.Run();
Hector Dearman86cfbe12018-03-22 11:58:42 +0000627
Primiano Tuccifed05fc2018-08-24 19:57:52 +0200628 return limiter.OnTraceDone(args, did_process_full_trace_, bytes_written_) ? 0
629 : 1;
Hector Dearman86cfbe12018-03-22 11:58:42 +0000630}
Primiano Tucci3b729102018-01-08 18:16:36 +0000631
632void PerfettoCmd::OnConnect() {
Hector Dearmana5b90822019-11-18 13:00:16 +0000633 LogUploadEvent(PerfettoStatsdAtom::kOnConnect);
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100634 if (query_service_) {
635 consumer_endpoint_->QueryServiceState(
636 [this](bool success, const TracingServiceState& svc_state) {
637 PrintServiceState(success, svc_state);
638 fflush(stdout);
639 exit(success ? 0 : 1);
640 });
641 return;
642 }
643
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100644 if (is_attach()) {
645 consumer_endpoint_->Attach(attach_key_);
646 return;
647 }
648
Hector Dearmaneb5c71e2019-07-30 14:00:23 +0100649 if (expected_duration_ms_) {
650 PERFETTO_LOG("Connected to the Perfetto traced service, TTL: %ds",
651 (expected_duration_ms_ + 999) / 1000);
652 } else {
653 PERFETTO_LOG("Connected to the Perfetto traced service, starting tracing");
654 }
655
Primiano Tucci3b729102018-01-08 18:16:36 +0000656 PERFETTO_DCHECK(trace_config_);
Florian Mayer80b388e2018-02-22 15:51:24 +0000657 trace_config_->set_enable_extra_guardrails(!dropbox_tag_.empty());
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100658
659 base::ScopedFile optional_fd;
660 if (trace_config_->write_into_file())
661 optional_fd.reset(dup(fileno(*trace_out_stream_)));
662
663 consumer_endpoint_->EnableTracing(*trace_config_, std::move(optional_fd));
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000664
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100665 if (is_detach()) {
666 consumer_endpoint_->Detach(detach_key_); // Will invoke OnDetach() soon.
667 return;
668 }
669
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000670 // Failsafe mechanism to avoid waiting indefinitely if the service hangs.
Hector Dearmaneb5c71e2019-07-30 14:00:23 +0100671 if (expected_duration_ms_) {
672 uint32_t trace_timeout =
673 expected_duration_ms_ + 60000 + trace_config_->flush_timeout_ms();
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100674 task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnTimeout, this),
Florian Mayere563f662019-01-09 11:04:50 +0000675 trace_timeout);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100676 }
Primiano Tucci3b729102018-01-08 18:16:36 +0000677}
678
679void PerfettoCmd::OnDisconnect() {
680 PERFETTO_LOG("Disconnected from the Perfetto traced service");
681 task_runner_.Quit();
682}
683
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000684void PerfettoCmd::OnTimeout() {
685 PERFETTO_ELOG("Timed out while waiting for trace from the service, aborting");
Hector Dearmana5b90822019-11-18 13:00:16 +0000686 LogUploadEvent(PerfettoStatsdAtom::kOnTimeout);
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000687 task_runner_.Quit();
688}
689
Hector Dearmaneb5c71e2019-07-30 14:00:23 +0100690void PerfettoCmd::CheckTraceDataTimeout() {
691 if (trace_data_timeout_armed_) {
692 PERFETTO_ELOG("Timed out while waiting for OnTraceData, aborting");
693 FinalizeTraceAndExit();
694 }
695 trace_data_timeout_armed_ = true;
696 task_runner_.PostDelayedTask(
697 std::bind(&PerfettoCmd::CheckTraceDataTimeout, this),
698 kOnTraceDataTimeoutMs);
699}
700
Primiano Tucci3b729102018-01-08 18:16:36 +0000701void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
Hector Dearmaneb5c71e2019-07-30 14:00:23 +0100702 trace_data_timeout_armed_ = false;
703
Hector Dearman554627f2019-06-04 17:58:22 +0100704 if (!packet_writer_->WritePackets(packets)) {
705 PERFETTO_ELOG("Failed to write packets");
706 FinalizeTraceAndExit();
Primiano Tucci3b729102018-01-08 18:16:36 +0000707 }
Primiano Tucci3b729102018-01-08 18:16:36 +0000708
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100709 if (!has_more)
710 FinalizeTraceAndExit(); // Reached end of trace.
711}
Sami Kyostilab5b71692018-01-12 12:16:44 +0000712
Primiano Tuccidca727d2018-04-04 11:31:55 +0200713void PerfettoCmd::OnTracingDisabled() {
Hector Dearmana5b90822019-11-18 13:00:16 +0000714 LogUploadEvent(PerfettoStatsdAtom::kOnTracingDisabled);
715
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100716 if (trace_config_->write_into_file()) {
717 // If write_into_file == true, at this point the passed file contains
718 // already all the packets.
719 return FinalizeTraceAndExit();
720 }
Hector Dearmaneb5c71e2019-07-30 14:00:23 +0100721
722 trace_data_timeout_armed_ = false;
723 CheckTraceDataTimeout();
724
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100725 // This will cause a bunch of OnTraceData callbacks. The last one will
726 // save the file and exit.
727 consumer_endpoint_->ReadBuffers();
728}
729
730void PerfettoCmd::FinalizeTraceAndExit() {
Hector Dearmana5b90822019-11-18 13:00:16 +0000731 LogUploadEvent(PerfettoStatsdAtom::kFinalizeTraceAndExit);
Hector Dearman554627f2019-06-04 17:58:22 +0100732 packet_writer_.reset();
733
734 if (trace_out_stream_) {
735 fseek(*trace_out_stream_, 0, SEEK_END);
736 off_t sz = ftell(*trace_out_stream_);
737 if (sz > 0)
738 bytes_written_ = static_cast<size_t>(sz);
739 }
740
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100741 if (!dropbox_tag_.empty()) {
742#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
743 SaveTraceIntoDropboxAndIncidentOrCrash();
744#endif
745 } else {
Hector Dearman86cfbe12018-03-22 11:58:42 +0000746 trace_out_stream_.reset();
Hector Dearman974fd852018-11-08 15:07:46 +0000747 if (trace_config_->write_into_file()) {
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100748 // trace_out_path_ might be empty in the case of --attach.
Ryan Savitski53ca60b2019-06-03 13:04:40 +0100749 PERFETTO_LOG("Trace written into the output file");
Hector Dearman974fd852018-11-08 15:07:46 +0000750 } else {
Ryan Savitski53ca60b2019-06-03 13:04:40 +0100751 PERFETTO_LOG("Wrote %" PRIu64 " bytes into %s", bytes_written_,
752 trace_out_path_ == "-" ? "stdout" : trace_out_path_.c_str());
Hector Dearman974fd852018-11-08 15:07:46 +0000753 }
Ryan Savitski53ca60b2019-06-03 13:04:40 +0100754 }
755
756 did_process_full_trace_ = true;
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100757 task_runner_.Quit();
Primiano Tucci3b729102018-01-08 18:16:36 +0000758}
759
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000760bool PerfettoCmd::OpenOutputFile() {
761 base::ScopedFile fd;
762 if (!dropbox_tag_.empty()) {
Primiano Tucciec62e3e2019-07-26 22:18:31 +0100763#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
764 fd = OpenDropboxTmpFile();
Primiano Tuccife922332018-03-22 16:15:04 -0700765#endif
Primiano Tuccifed05fc2018-08-24 19:57:52 +0200766 } else if (trace_out_path_ == "-") {
767 fd.reset(dup(STDOUT_FILENO));
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000768 } else {
Florian Mayerb03fd282018-10-03 16:05:16 +0100769 fd = base::OpenFile(trace_out_path_, O_RDWR | O_CREAT | O_TRUNC, 0600);
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000770 }
Florian Mayer1ac45502019-04-16 10:15:25 +0100771 if (!fd) {
772 PERFETTO_PLOG(
773 "Failed to open %s. If you get permission denied in "
774 "/data/misc/perfetto-traces, the file might have been "
775 "created by another user, try deleting it first.",
776 trace_out_path_.c_str());
777 return false;
778 }
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000779 trace_out_stream_.reset(fdopen(fd.release(), "wb"));
780 PERFETTO_CHECK(trace_out_stream_);
781 return true;
Sami Kyostila26d5cdd2018-01-15 16:42:06 +0000782}
783
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100784void PerfettoCmd::SetupCtrlCSignalHandler() {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100785 // Setup signal handler.
786 struct sigaction sa {};
787
788// Glibc headers for sa_sigaction trigger this.
789#pragma GCC diagnostic push
790#if defined(__clang__)
791#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
792#endif
Florian Mayeredf738f2018-11-30 12:26:06 +0000793 sa.sa_handler = [](int) { g_consumer_cmd->SignalCtrlC(); };
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100794 sa.sa_flags = static_cast<decltype(sa.sa_flags)>(SA_RESETHAND | SA_RESTART);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100795#pragma GCC diagnostic pop
796 sigaction(SIGINT, &sa, nullptr);
Primiano Tucci3ff096b2018-12-21 19:12:54 +0100797 sigaction(SIGTERM, &sa, nullptr);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100798
Florian Mayeredf738f2018-11-30 12:26:06 +0000799 task_runner_.AddFileDescriptorWatch(ctrl_c_evt_.fd(), [this] {
Florian Mayere563f662019-01-09 11:04:50 +0000800 PERFETTO_LOG("SIGINT/SIGTERM received: disabling tracing.");
Florian Mayeredf738f2018-11-30 12:26:06 +0000801 ctrl_c_evt_.Clear();
Florian Mayere563f662019-01-09 11:04:50 +0000802 consumer_endpoint_->Flush(0, [this](bool flush_success) {
Florian Mayer7a128572019-01-08 17:15:40 +0000803 if (!flush_success)
804 PERFETTO_ELOG("Final flush unsuccessful.");
Florian Mayerf8d4e7e2018-11-29 14:54:15 +0000805 consumer_endpoint_->DisableTracing();
806 });
807 });
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100808}
809
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100810void PerfettoCmd::OnDetach(bool success) {
811 if (!success) {
812 PERFETTO_ELOG("Session detach failed");
813 exit(1);
814 }
815 exit(0);
816}
817
818void PerfettoCmd::OnAttach(bool success, const TraceConfig& trace_config) {
819 if (!success) {
Primiano Tucciacefff72019-01-06 21:02:20 +0000820 if (!redetach_once_attached_) {
821 // Print an error message if attach fails, with the exception of the
822 // --is_detached case, where we want to silently return.
823 PERFETTO_ELOG("Session re-attach failed. Check service logs for details");
824 }
825 // Keep this exit code distinguishable from the general error code so
826 // --is_detached can tell the difference between a general error and the
827 // not-detached case.
828 exit(2);
829 }
830
831 if (redetach_once_attached_) {
832 consumer_endpoint_->Detach(attach_key_); // Will invoke OnDetach() soon.
833 return;
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100834 }
835
836 trace_config_.reset(new TraceConfig(trace_config));
837 PERFETTO_DCHECK(trace_config_->write_into_file());
838
839 if (stop_trace_once_attached_) {
Florian Mayere563f662019-01-09 11:04:50 +0000840 consumer_endpoint_->Flush(0, [this](bool flush_success) {
Florian Mayer7a128572019-01-08 17:15:40 +0000841 if (!flush_success)
842 PERFETTO_ELOG("Final flush unsuccessful.");
Primiano Tucci9ba1d842018-12-20 17:31:04 +0100843 consumer_endpoint_->DisableTracing();
844 });
845 }
846}
847
Eric Secklereaf29ed2019-01-23 09:53:55 +0000848void PerfettoCmd::OnTraceStats(bool /*success*/,
849 const TraceStats& /*trace_config*/) {
850 // TODO(eseckler): Support GetTraceStats().
851}
852
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100853void PerfettoCmd::PrintServiceState(bool success,
854 const TracingServiceState& svc_state) {
855 if (!success) {
856 PERFETTO_ELOG("Failed to query the service state");
857 return;
858 }
859
860 if (query_service_output_raw_) {
861 protos::TracingServiceState proto;
862 svc_state.ToProto(&proto);
863 std::string str = proto.SerializeAsString();
864 fwrite(str.data(), 1, str.size(), stdout);
865 return;
866 }
867
868 printf("Not meant for machine consumption. Use --query-raw for scripts.\n");
869
870 for (const auto& producer : svc_state.producers()) {
871 printf("producers: {\n");
872 printf(" id: %d\n", producer.id());
873 printf(" name: \"%s\" \n", producer.name().c_str());
874 printf(" uid: %d \n", producer.uid());
875 printf("}\n");
876 }
877
878 for (const auto& ds : svc_state.data_sources()) {
879 printf("data_sources: {\n");
880 printf(" producer_id: %d\n", ds.producer_id());
881 printf(" descriptor: {\n");
Lalit Magantidcc359d2019-06-17 16:28:40 +0100882 printf(" name: \"%s\"\n", ds.ds_descriptor().name().c_str());
Primiano Tucci2854a0a2019-06-03 14:51:18 +0100883 printf(" }\n");
884 printf("}\n");
885 }
886 printf("num_sessions: %d\n", svc_state.num_sessions());
887 printf("num_sessions_started: %d\n", svc_state.num_sessions_started());
888}
889
Eric Seckler7b0c9452019-03-18 13:14:36 +0000890void PerfettoCmd::OnObservableEvents(
891 const ObservableEvents& /*observable_events*/) {}
892
Hector Dearmana5b90822019-11-18 13:00:16 +0000893void PerfettoCmd::LogUploadEvent(PerfettoStatsdAtom atom) {
894#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
895 LogUploadEventAndroid(atom);
896#else
897 base::ignore_result(atom);
898#endif
899}
900
Primiano Tucci3b729102018-01-08 18:16:36 +0000901int __attribute__((visibility("default")))
902PerfettoCmdMain(int argc, char** argv) {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100903 g_consumer_cmd = new perfetto::PerfettoCmd();
904 return g_consumer_cmd->Main(argc, argv);
Primiano Tucci3b729102018-01-08 18:16:36 +0000905}
906
907} // namespace perfetto