blob: ebdd740bf992a619b4c32b98deb2eaa540bf8879 [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>
Hector Dearman86cfbe12018-03-22 11:58:42 +000024#include <time.h>
Primiano Tuccif3837d52018-01-10 21:12:41 +000025#include <unistd.h>
Primiano Tucci3b729102018-01-08 18:16:36 +000026
27#include <fstream>
28#include <iostream>
29#include <iterator>
Sami Kyostila26d5cdd2018-01-15 16:42:06 +000030#include <sstream>
Primiano Tucci3b729102018-01-08 18:16:36 +000031
Florian Mayer74b73a92018-03-09 17:37:13 +000032#include "perfetto/base/file_utils.h"
Primiano Tucci3b729102018-01-08 18:16:36 +000033#include "perfetto/base/logging.h"
Hector Dearman86cfbe12018-03-22 11:58:42 +000034#include "perfetto/base/time.h"
Primiano Tucci3b729102018-01-08 18:16:36 +000035#include "perfetto/base/utils.h"
Hector Dearman20b3c1c2018-01-15 15:34:03 +000036#include "perfetto/protozero/proto_utils.h"
Primiano Tucci3b729102018-01-08 18:16:36 +000037#include "perfetto/traced/traced.h"
Primiano Tucci3b729102018-01-08 18:16:36 +000038#include "perfetto/tracing/core/data_source_config.h"
39#include "perfetto/tracing/core/data_source_descriptor.h"
40#include "perfetto/tracing/core/trace_config.h"
41#include "perfetto/tracing/core/trace_packet.h"
Primiano Tucci3b729102018-01-08 18:16:36 +000042
Primiano Tucci20b760c2018-01-19 12:36:12 +000043#include "perfetto/config/trace_config.pb.h"
Primiano Tucci3b729102018-01-08 18:16:36 +000044
Florian Mayerc29e0d32018-04-04 15:55:46 +010045#include "src/tracing/ipc/default_socket.h"
46
Hector Dearman86cfbe12018-03-22 11:58:42 +000047#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
Primiano Tucciedf099c2018-01-08 18:27:56 +000048
Primiano Tuccife922332018-03-22 16:15:04 -070049#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
Sami Kyostilab5b71692018-01-12 12:16:44 +000050#include <android/os/DropBoxManager.h>
Primiano Tucciedf099c2018-01-08 18:27:56 +000051#include <utils/Looper.h>
52#include <utils/StrongPointer.h>
Primiano Tuccife922332018-03-22 16:15:04 -070053#endif // PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
Primiano Tucciedf099c2018-01-08 18:27:56 +000054
Primiano Tucci3b729102018-01-08 18:16:36 +000055// TODO(primiano): add the ability to pass the file descriptor directly to the
Primiano Tucci16d1d632018-02-22 10:16:22 +000056// traced service instead of receiving a copy of the slices and writing them
Primiano Tucci3b729102018-01-08 18:16:36 +000057// from this process.
Primiano Tucci3b729102018-01-08 18:16:36 +000058namespace perfetto {
Sami Kyostilab5b71692018-01-12 12:16:44 +000059namespace {
Sami Kyostila0b99a3b2018-01-30 18:05:59 +000060
Florian Mayerdbd08782018-03-21 14:07:51 +000061constexpr char kDefaultDropBoxTag[] = "perfetto";
Sami Kyostila0b99a3b2018-01-30 18:05:59 +000062
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010063perfetto::PerfettoCmd* g_consumer_cmd;
Sami Kyostila0b99a3b2018-01-30 18:05:59 +000064
Sami Kyostilab5b71692018-01-12 12:16:44 +000065} // namespace
Primiano Tucci3b729102018-01-08 18:16:36 +000066
Hector Dearman86cfbe12018-03-22 11:58:42 +000067// Temporary directory for DropBox traces. Note that this is automatically
68// created by the system by setting setprop persist.traced.enable=1.
69const char* kTempDropBoxTraceDir = "/data/misc/perfetto-traces";
70
Hector Dearman20b3c1c2018-01-15 15:34:03 +000071using protozero::proto_utils::WriteVarInt;
72using protozero::proto_utils::MakeTagLengthDelimited;
73
Primiano Tucci3b729102018-01-08 18:16:36 +000074int PerfettoCmd::PrintUsage(const char* argv0) {
Primiano Tucci7e2b67a2018-01-16 16:38:49 +000075 PERFETTO_ELOG(R"(
76Usage: %s
Hector Dearman86cfbe12018-03-22 11:58:42 +000077 --background -b : Exits immediately and continues tracing in background
78 --config -c : /path/to/trace/config/file or - for stdin
79 --out -o : /path/to/out/trace/file
80 --dropbox -d TAG : Upload trace into DropBox using tag TAG (default: %s)
81 --no-guardrails -n : Ignore guardrails triggered when using --dropbox (for testing).
82 --help -h
Sami Kyostila200bd2e2018-03-26 12:24:10 +010083
84statsd-specific flags:
85 --alert-id : ID of the alert that triggered this trace.
86 --config-id : ID of the triggering config.
87 --config-uid : UID of app which registered the config.
Primiano Tucci7e2b67a2018-01-16 16:38:49 +000088)",
89 argv0, kDefaultDropBoxTag);
Primiano Tucci3b729102018-01-08 18:16:36 +000090 return 1;
91}
92
93int PerfettoCmd::Main(int argc, char** argv) {
Sami Kyostila200bd2e2018-03-26 12:24:10 +010094 enum LongOption {
95 OPT_ALERT_ID = 1000,
96 OPT_CONFIG_ID,
97 OPT_CONFIG_UID,
98 };
Primiano Tucci3b729102018-01-08 18:16:36 +000099 static const struct option long_options[] = {
100 // |option_index| relies on the order of options, don't reshuffle them.
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100101 {"help", required_argument, nullptr, 'h'},
102 {"config", required_argument, nullptr, 'c'},
103 {"out", required_argument, nullptr, 'o'},
104 {"background", no_argument, nullptr, 'b'},
105 {"dropbox", optional_argument, nullptr, 'd'},
106 {"no-guardrails", optional_argument, nullptr, 'n'},
107 {"alert-id", required_argument, nullptr, OPT_ALERT_ID},
108 {"config-id", required_argument, nullptr, OPT_CONFIG_ID},
109 {"config-uid", required_argument, nullptr, OPT_CONFIG_UID},
Primiano Tuccif3837d52018-01-10 21:12:41 +0000110 {nullptr, 0, nullptr, 0}};
Primiano Tucci3b729102018-01-08 18:16:36 +0000111
112 int option_index = 0;
113 std::string trace_config_raw;
Primiano Tuccif3837d52018-01-10 21:12:41 +0000114 bool background = false;
Hector Dearman86cfbe12018-03-22 11:58:42 +0000115 bool ignore_guardrails = false;
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100116 perfetto::protos::TraceConfig::StatsdMetadata statsd_metadata;
Primiano Tucci3b729102018-01-08 18:16:36 +0000117 for (;;) {
Sami Kyostilab5b71692018-01-12 12:16:44 +0000118 int option =
Hector Dearman86cfbe12018-03-22 11:58:42 +0000119 getopt_long(argc, argv, "c:o:bd::n", long_options, &option_index);
Primiano Tucci3b729102018-01-08 18:16:36 +0000120
121 if (option == -1)
122 break; // EOF.
123
124 if (option == 'c') {
125 if (strcmp(optarg, "-") == 0) {
126 std::istreambuf_iterator<char> begin(std::cin), end;
127 trace_config_raw.assign(begin, end);
128 } else if (strcmp(optarg, ":test") == 0) {
129 // TODO(primiano): temporary for testing only.
130 perfetto::protos::TraceConfig test_config;
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000131 test_config.add_buffers()->set_size_kb(4096);
Hector Dearman86cfbe12018-03-22 11:58:42 +0000132 test_config.set_duration_ms(2000);
Primiano Tucci3b729102018-01-08 18:16:36 +0000133 auto* ds_config = test_config.add_data_sources()->mutable_config();
Primiano Tucci578d7842018-03-29 15:27:05 +0100134 ds_config->set_name("linux.ftrace");
Hector Dearmand410c822018-02-23 15:46:18 +0000135 ds_config->mutable_ftrace_config()->add_ftrace_events("sched_switch");
136 ds_config->mutable_ftrace_config()->add_ftrace_events("cpu_idle");
137 ds_config->mutable_ftrace_config()->add_ftrace_events("cpu_frequency");
Primiano Tucci20d441d2018-01-16 09:25:51 +0000138 ds_config->set_target_buffer(0);
Primiano Tucci3b729102018-01-08 18:16:36 +0000139 test_config.SerializeToString(&trace_config_raw);
140 } else {
Florian Mayer74b73a92018-03-09 17:37:13 +0000141 if (!base::ReadFile(optarg, &trace_config_raw)) {
Florian Mayer8ede4ac2018-03-27 13:13:56 +0100142 PERFETTO_PLOG("Could not open %s", optarg);
Primiano Tucci3b729102018-01-08 18:16:36 +0000143 return 1;
144 }
Primiano Tucci3b729102018-01-08 18:16:36 +0000145 }
146 continue;
147 }
148
149 if (option == 'o') {
150 trace_out_path_ = optarg;
Primiano Tucci3b729102018-01-08 18:16:36 +0000151 continue;
152 }
153
Sami Kyostilab5b71692018-01-12 12:16:44 +0000154 if (option == 'd') {
Primiano Tuccife922332018-03-22 16:15:04 -0700155#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
Sami Kyostilab5b71692018-01-12 12:16:44 +0000156 dropbox_tag_ = optarg ? optarg : kDefaultDropBoxTag;
157 continue;
158#else
159 PERFETTO_ELOG("DropBox is only supported with Android tree builds");
160 return 1;
161#endif
162 }
163
Primiano Tuccif3837d52018-01-10 21:12:41 +0000164 if (option == 'b') {
165 background = true;
166 continue;
167 }
Hector Dearman86cfbe12018-03-22 11:58:42 +0000168
169 if (option == 'n') {
170 ignore_guardrails = true;
171 continue;
172 }
173
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100174 if (option == OPT_ALERT_ID) {
175 statsd_metadata.set_triggering_alert_id(atoll(optarg));
176 continue;
177 }
178
179 if (option == OPT_CONFIG_ID) {
180 statsd_metadata.set_triggering_config_id(atoll(optarg));
181 continue;
182 }
183
184 if (option == OPT_CONFIG_UID) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100185 statsd_metadata.set_triggering_config_uid(atoi(optarg));
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100186 continue;
187 }
188
Primiano Tucci3b729102018-01-08 18:16:36 +0000189 return PrintUsage(argv[0]);
190 }
191
Sami Kyostilab5b71692018-01-12 12:16:44 +0000192 if (!trace_out_path_.empty() && !dropbox_tag_.empty()) {
193 PERFETTO_ELOG(
194 "Can't log to a file (--out) and DropBox (--dropbox) at the same "
195 "time");
196 return 1;
197 }
198
Primiano Tucci21bf7f82018-02-20 13:36:59 +0000199 if (trace_out_path_.empty() && dropbox_tag_.empty()) {
Primiano Tucci3b729102018-01-08 18:16:36 +0000200 return PrintUsage(argv[0]);
Sami Kyostilab5b71692018-01-12 12:16:44 +0000201 }
202
Primiano Tucci21bf7f82018-02-20 13:36:59 +0000203 if (trace_config_raw.empty()) {
204 PERFETTO_ELOG("The TraceConfig is empty");
205 return 1;
206 }
207
Primiano Tucci3b729102018-01-08 18:16:36 +0000208 perfetto::protos::TraceConfig trace_config_proto;
209 PERFETTO_DLOG("Parsing TraceConfig, %zu bytes", trace_config_raw.size());
210 bool parsed = trace_config_proto.ParseFromString(trace_config_raw);
211 if (!parsed) {
212 PERFETTO_ELOG("Could not parse TraceConfig proto from stdin");
213 return 1;
214 }
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100215 *trace_config_proto.mutable_statsd_metadata() = std::move(statsd_metadata);
Primiano Tucci3b729102018-01-08 18:16:36 +0000216 trace_config_.reset(new TraceConfig());
217 trace_config_->FromProto(trace_config_proto);
218 trace_config_raw.clear();
219
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000220 if (!OpenOutputFile())
221 return 1;
222
Primiano Tuccif3837d52018-01-10 21:12:41 +0000223 if (background) {
224 PERFETTO_CHECK(daemon(0 /*nochdir*/, 0 /*noclose*/) == 0);
225 PERFETTO_DLOG("Continuing in background");
226 }
227
Hector Dearman86cfbe12018-03-22 11:58:42 +0000228 RateLimiter limiter;
229 RateLimiter::Args args{};
230 args.is_dropbox = !dropbox_tag_.empty();
231 args.current_time = base::GetWallTimeS();
232 args.ignore_guardrails = ignore_guardrails;
Lalit Maganti41844ed2018-05-23 14:41:43 +0100233#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_USERDEBUG_BUILD)
234 args.max_upload_bytes_override =
235 trace_config_->guardrail_overrides().max_upload_per_day_bytes();
236#endif
Hector Dearman86cfbe12018-03-22 11:58:42 +0000237 if (!limiter.ShouldTrace(args))
238 return 1;
239
Florian Mayerc29e0d32018-04-04 15:55:46 +0100240 consumer_endpoint_ =
241 ConsumerIPCClient::Connect(GetConsumerSocket(), this, &task_runner_);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100242 SetupCtrlCSignalHandler();
Primiano Tucci3b729102018-01-08 18:16:36 +0000243 task_runner_.Run();
Hector Dearman86cfbe12018-03-22 11:58:42 +0000244
245 return limiter.OnTraceDone(args, did_process_full_trace_,
246 bytes_uploaded_to_dropbox_)
247 ? 0
248 : 1;
249}
Primiano Tucci3b729102018-01-08 18:16:36 +0000250
251void PerfettoCmd::OnConnect() {
252 PERFETTO_LOG(
253 "Connected to the Perfetto traced service, starting tracing for %d ms",
254 trace_config_->duration_ms());
255 PERFETTO_DCHECK(trace_config_);
Florian Mayer80b388e2018-02-22 15:51:24 +0000256 trace_config_->set_enable_extra_guardrails(!dropbox_tag_.empty());
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100257
258 base::ScopedFile optional_fd;
259 if (trace_config_->write_into_file())
260 optional_fd.reset(dup(fileno(*trace_out_stream_)));
261
262 consumer_endpoint_->EnableTracing(*trace_config_, std::move(optional_fd));
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000263
264 // Failsafe mechanism to avoid waiting indefinitely if the service hangs.
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100265 if (trace_config_->duration_ms()) {
266 task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnTimeout, this),
Primiano Tuccid52e6272018-04-06 19:06:53 +0200267 trace_config_->duration_ms() + 10000);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100268 }
Primiano Tucci3b729102018-01-08 18:16:36 +0000269}
270
271void PerfettoCmd::OnDisconnect() {
272 PERFETTO_LOG("Disconnected from the Perfetto traced service");
273 task_runner_.Quit();
274}
275
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000276void PerfettoCmd::OnTimeout() {
277 PERFETTO_ELOG("Timed out while waiting for trace from the service, aborting");
278 task_runner_.Quit();
279}
280
Primiano Tucci3b729102018-01-08 18:16:36 +0000281void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
Primiano Tucci3b729102018-01-08 18:16:36 +0000282 for (TracePacket& packet : packets) {
Primiano Tuccid61b85f2018-03-29 02:56:10 +0100283 uint8_t preamble[16];
284 uint8_t* pos = preamble;
Primiano Tucci07e104d2018-04-03 20:45:35 +0200285 // ID of the |packet| field in trace.proto. Hardcoded as this we not depend
286 // on protos/trace:lite for binary size saving reasons.
287 static constexpr uint32_t kPacketFieldNumber = 1;
288 pos = WriteVarInt(MakeTagLengthDelimited(kPacketFieldNumber), pos);
Primiano Tuccid61b85f2018-03-29 02:56:10 +0100289 pos = WriteVarInt(static_cast<uint32_t>(packet.size()), pos);
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100290 fwrite(reinterpret_cast<const char*>(preamble),
291 static_cast<size_t>(pos - preamble), 1, trace_out_stream_.get());
Primiano Tucci09db8272018-03-08 17:47:47 +0000292 for (const Slice& slice : packet.slices()) {
Primiano Tucci16d1d632018-02-22 10:16:22 +0000293 fwrite(reinterpret_cast<const char*>(slice.start), slice.size, 1,
Sami Kyostila26d5cdd2018-01-15 16:42:06 +0000294 trace_out_stream_.get());
Primiano Tucci3b729102018-01-08 18:16:36 +0000295 }
296 }
Primiano Tucci3b729102018-01-08 18:16:36 +0000297
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100298 if (!has_more)
299 FinalizeTraceAndExit(); // Reached end of trace.
300}
Sami Kyostilab5b71692018-01-12 12:16:44 +0000301
Primiano Tuccidca727d2018-04-04 11:31:55 +0200302void PerfettoCmd::OnTracingDisabled() {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100303 if (trace_config_->write_into_file()) {
304 // If write_into_file == true, at this point the passed file contains
305 // already all the packets.
306 return FinalizeTraceAndExit();
307 }
308 // This will cause a bunch of OnTraceData callbacks. The last one will
309 // save the file and exit.
310 consumer_endpoint_->ReadBuffers();
311}
312
313void PerfettoCmd::FinalizeTraceAndExit() {
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000314 fflush(*trace_out_stream_);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100315 fseek(*trace_out_stream_, 0, SEEK_END);
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000316 long bytes_written = ftell(*trace_out_stream_);
Hector Dearman86cfbe12018-03-22 11:58:42 +0000317 if (dropbox_tag_.empty()) {
318 trace_out_stream_.reset();
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100319 did_process_full_trace_ = true;
Hector Dearman86cfbe12018-03-22 11:58:42 +0000320 PERFETTO_ILOG("Wrote %ld bytes into %s", bytes_written,
321 trace_out_path_.c_str());
322 } else {
Primiano Tuccife922332018-03-22 16:15:04 -0700323#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
Sami Kyostilab5b71692018-01-12 12:16:44 +0000324 android::sp<android::os::DropBoxManager> dropbox =
325 new android::os::DropBoxManager();
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000326 fseek(*trace_out_stream_, 0, SEEK_SET);
327 // DropBox takes ownership of the file descriptor, so give it a duplicate.
Primiano Tucci121bf242018-01-31 11:59:08 +0000328 // Also we need to give it a read-only copy of the fd or will hit a SELinux
329 // violation (about system_server ending up with a writable FD to our dir).
330 char fdpath[64];
331 sprintf(fdpath, "/proc/self/fd/%d", fileno(*trace_out_stream_));
332 base::ScopedFile read_only_fd(open(fdpath, O_RDONLY));
333 PERFETTO_CHECK(read_only_fd);
334 trace_out_stream_.reset();
335 android::binder::Status status =
336 dropbox->addFile(android::String16(dropbox_tag_.c_str()),
337 read_only_fd.release(), 0 /* flags */);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100338 if (status.isOk()) {
339 // TODO(hjd): Account for compression.
340 did_process_full_trace_ = true;
341 bytes_uploaded_to_dropbox_ = bytes_written;
342 PERFETTO_ILOG("Uploaded %ld bytes into DropBox with tag %s",
343 bytes_written, dropbox_tag_.c_str());
344 } else {
Sami Kyostilab5b71692018-01-12 12:16:44 +0000345 PERFETTO_ELOG("DropBox upload failed: %s", status.toString8().c_str());
Sami Kyostilab5b71692018-01-12 12:16:44 +0000346 }
Primiano Tuccife922332018-03-22 16:15:04 -0700347#endif // PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
Sami Kyostilab5b71692018-01-12 12:16:44 +0000348 }
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100349 task_runner_.Quit();
Primiano Tucci3b729102018-01-08 18:16:36 +0000350}
351
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000352bool PerfettoCmd::OpenOutputFile() {
353 base::ScopedFile fd;
354 if (!dropbox_tag_.empty()) {
Primiano Tuccife922332018-03-22 16:15:04 -0700355#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000356 // If we are tracing to DropBox, there's no need to make a
357 // filesystem-visible temporary file.
Primiano Tucci941b2212018-03-14 22:46:31 +0000358 // TODO(skyostil): Fall back to base::TempFile for older devices.
Adrian DC21420992018-03-09 07:59:58 +0100359 fd.reset(open(kTempDropBoxTraceDir, O_CREAT | O_TMPFILE | O_RDWR, 0600));
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000360 if (!fd) {
361 PERFETTO_ELOG("Could not create a temporary trace file in %s",
362 kTempDropBoxTraceDir);
363 return false;
364 }
Primiano Tuccife922332018-03-22 16:15:04 -0700365#else
Hector Dearmanf4bc1d12018-03-26 15:40:13 +0100366 PERFETTO_FATAL("Tracing to Dropbox requires the Android build.");
Primiano Tuccife922332018-03-22 16:15:04 -0700367#endif
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000368 } else {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100369 fd.reset(open(trace_out_path_.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600));
Sami Kyostila0b99a3b2018-01-30 18:05:59 +0000370 }
371 trace_out_stream_.reset(fdopen(fd.release(), "wb"));
372 PERFETTO_CHECK(trace_out_stream_);
373 return true;
Sami Kyostila26d5cdd2018-01-15 16:42:06 +0000374}
375
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100376void PerfettoCmd::SetupCtrlCSignalHandler() {
377 // Setup the pipe used to deliver the CTRL-C notification from signal handler.
378 int pipe_fds[2];
379 PERFETTO_CHECK(pipe(pipe_fds) == 0);
380 ctrl_c_pipe_rd_.reset(pipe_fds[0]);
381 ctrl_c_pipe_wr_.reset(pipe_fds[1]);
382
383 // Setup signal handler.
384 struct sigaction sa {};
385
386// Glibc headers for sa_sigaction trigger this.
387#pragma GCC diagnostic push
388#if defined(__clang__)
389#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
390#endif
391 sa.sa_handler = [](int) {
392 PERFETTO_LOG("SIGINT received: disabling tracing");
393 char one = '1';
394 PERFETTO_CHECK(PERFETTO_EINTR(write(g_consumer_cmd->ctrl_c_pipe_wr(), &one,
395 sizeof(one))) == 1);
396 };
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100397 sa.sa_flags = static_cast<decltype(sa.sa_flags)>(SA_RESETHAND | SA_RESTART);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100398#pragma GCC diagnostic pop
399 sigaction(SIGINT, &sa, nullptr);
400
401 task_runner_.AddFileDescriptorWatch(
402 *ctrl_c_pipe_rd_, [this] { consumer_endpoint_->DisableTracing(); });
403}
404
Primiano Tucci3b729102018-01-08 18:16:36 +0000405int __attribute__((visibility("default")))
406PerfettoCmdMain(int argc, char** argv) {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100407 g_consumer_cmd = new perfetto::PerfettoCmd();
408 return g_consumer_cmd->Main(argc, argv);
Primiano Tucci3b729102018-01-08 18:16:36 +0000409}
410
411} // namespace perfetto