Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 1 | /* |
| 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 17 | #include "src/perfetto_cmd/perfetto_cmd.h" |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 18 | |
Sami Kyostila | 26d5cdd | 2018-01-15 16:42:06 +0000 | [diff] [blame] | 19 | #include <fcntl.h> |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 20 | #include <getopt.h> |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 21 | #include <signal.h> |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 22 | #include <stdio.h> |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 23 | #include <sys/stat.h> |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 24 | #include <time.h> |
Primiano Tucci | f3837d5 | 2018-01-10 21:12:41 +0000 | [diff] [blame] | 25 | #include <unistd.h> |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 26 | |
| 27 | #include <fstream> |
| 28 | #include <iostream> |
| 29 | #include <iterator> |
Sami Kyostila | 26d5cdd | 2018-01-15 16:42:06 +0000 | [diff] [blame] | 30 | #include <sstream> |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 31 | |
Florian Mayer | 74b73a9 | 2018-03-09 17:37:13 +0000 | [diff] [blame] | 32 | #include "perfetto/base/file_utils.h" |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 33 | #include "perfetto/base/logging.h" |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 34 | #include "perfetto/base/time.h" |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 35 | #include "perfetto/base/utils.h" |
Hector Dearman | 20b3c1c | 2018-01-15 15:34:03 +0000 | [diff] [blame] | 36 | #include "perfetto/protozero/proto_utils.h" |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 37 | #include "perfetto/traced/traced.h" |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 38 | #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 Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 42 | |
Primiano Tucci | 20b760c | 2018-01-19 12:36:12 +0000 | [diff] [blame] | 43 | #include "perfetto/config/trace_config.pb.h" |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 44 | |
Florian Mayer | c29e0d3 | 2018-04-04 15:55:46 +0100 | [diff] [blame] | 45 | #include "src/tracing/ipc/default_socket.h" |
| 46 | |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 47 | #include "google/protobuf/io/zero_copy_stream_impl_lite.h" |
Primiano Tucci | edf099c | 2018-01-08 18:27:56 +0000 | [diff] [blame] | 48 | |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 49 | #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 50 | #include <android/os/DropBoxManager.h> |
Primiano Tucci | edf099c | 2018-01-08 18:27:56 +0000 | [diff] [blame] | 51 | #include <utils/Looper.h> |
| 52 | #include <utils/StrongPointer.h> |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 53 | #endif // PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) |
Primiano Tucci | edf099c | 2018-01-08 18:27:56 +0000 | [diff] [blame] | 54 | |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 55 | // TODO(primiano): add the ability to pass the file descriptor directly to the |
Primiano Tucci | 16d1d63 | 2018-02-22 10:16:22 +0000 | [diff] [blame] | 56 | // traced service instead of receiving a copy of the slices and writing them |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 57 | // from this process. |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 58 | namespace perfetto { |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 59 | namespace { |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 60 | |
Florian Mayer | dbd0878 | 2018-03-21 14:07:51 +0000 | [diff] [blame] | 61 | constexpr char kDefaultDropBoxTag[] = "perfetto"; |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 62 | |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 63 | perfetto::PerfettoCmd* g_consumer_cmd; |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 64 | |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 65 | } // namespace |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 66 | |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 67 | // Temporary directory for DropBox traces. Note that this is automatically |
| 68 | // created by the system by setting setprop persist.traced.enable=1. |
| 69 | const char* kTempDropBoxTraceDir = "/data/misc/perfetto-traces"; |
| 70 | |
Hector Dearman | 20b3c1c | 2018-01-15 15:34:03 +0000 | [diff] [blame] | 71 | using protozero::proto_utils::WriteVarInt; |
| 72 | using protozero::proto_utils::MakeTagLengthDelimited; |
| 73 | |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 74 | int PerfettoCmd::PrintUsage(const char* argv0) { |
Primiano Tucci | 7e2b67a | 2018-01-16 16:38:49 +0000 | [diff] [blame] | 75 | PERFETTO_ELOG(R"( |
| 76 | Usage: %s |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 77 | --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 Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 83 | |
| 84 | statsd-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 Tucci | 7e2b67a | 2018-01-16 16:38:49 +0000 | [diff] [blame] | 88 | )", |
| 89 | argv0, kDefaultDropBoxTag); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 90 | return 1; |
| 91 | } |
| 92 | |
| 93 | int PerfettoCmd::Main(int argc, char** argv) { |
Sami Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 94 | enum LongOption { |
| 95 | OPT_ALERT_ID = 1000, |
| 96 | OPT_CONFIG_ID, |
| 97 | OPT_CONFIG_UID, |
| 98 | }; |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 99 | static const struct option long_options[] = { |
| 100 | // |option_index| relies on the order of options, don't reshuffle them. |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 101 | {"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 Tucci | f3837d5 | 2018-01-10 21:12:41 +0000 | [diff] [blame] | 110 | {nullptr, 0, nullptr, 0}}; |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 111 | |
| 112 | int option_index = 0; |
| 113 | std::string trace_config_raw; |
Primiano Tucci | f3837d5 | 2018-01-10 21:12:41 +0000 | [diff] [blame] | 114 | bool background = false; |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 115 | bool ignore_guardrails = false; |
Sami Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 116 | perfetto::protos::TraceConfig::StatsdMetadata statsd_metadata; |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 117 | for (;;) { |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 118 | int option = |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 119 | getopt_long(argc, argv, "c:o:bd::n", long_options, &option_index); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 120 | |
| 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 Tucci | 0c45fa3 | 2018-01-30 15:52:30 +0000 | [diff] [blame] | 131 | test_config.add_buffers()->set_size_kb(4096); |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 132 | test_config.set_duration_ms(2000); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 133 | auto* ds_config = test_config.add_data_sources()->mutable_config(); |
Primiano Tucci | 578d784 | 2018-03-29 15:27:05 +0100 | [diff] [blame] | 134 | ds_config->set_name("linux.ftrace"); |
Hector Dearman | d410c82 | 2018-02-23 15:46:18 +0000 | [diff] [blame] | 135 | 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 Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 138 | ds_config->set_target_buffer(0); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 139 | test_config.SerializeToString(&trace_config_raw); |
| 140 | } else { |
Florian Mayer | 74b73a9 | 2018-03-09 17:37:13 +0000 | [diff] [blame] | 141 | if (!base::ReadFile(optarg, &trace_config_raw)) { |
Florian Mayer | 8ede4ac | 2018-03-27 13:13:56 +0100 | [diff] [blame] | 142 | PERFETTO_PLOG("Could not open %s", optarg); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 143 | return 1; |
| 144 | } |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 145 | } |
| 146 | continue; |
| 147 | } |
| 148 | |
| 149 | if (option == 'o') { |
| 150 | trace_out_path_ = optarg; |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 151 | continue; |
| 152 | } |
| 153 | |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 154 | if (option == 'd') { |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 155 | #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 156 | 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 Tucci | f3837d5 | 2018-01-10 21:12:41 +0000 | [diff] [blame] | 164 | if (option == 'b') { |
| 165 | background = true; |
| 166 | continue; |
| 167 | } |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 168 | |
| 169 | if (option == 'n') { |
| 170 | ignore_guardrails = true; |
| 171 | continue; |
| 172 | } |
| 173 | |
Sami Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 174 | 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 185 | statsd_metadata.set_triggering_config_uid(atoi(optarg)); |
Sami Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 186 | continue; |
| 187 | } |
| 188 | |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 189 | return PrintUsage(argv[0]); |
| 190 | } |
| 191 | |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 192 | 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 Tucci | 21bf7f8 | 2018-02-20 13:36:59 +0000 | [diff] [blame] | 199 | if (trace_out_path_.empty() && dropbox_tag_.empty()) { |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 200 | return PrintUsage(argv[0]); |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 201 | } |
| 202 | |
Primiano Tucci | 21bf7f8 | 2018-02-20 13:36:59 +0000 | [diff] [blame] | 203 | if (trace_config_raw.empty()) { |
| 204 | PERFETTO_ELOG("The TraceConfig is empty"); |
| 205 | return 1; |
| 206 | } |
| 207 | |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 208 | 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 Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 215 | *trace_config_proto.mutable_statsd_metadata() = std::move(statsd_metadata); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 216 | trace_config_.reset(new TraceConfig()); |
| 217 | trace_config_->FromProto(trace_config_proto); |
| 218 | trace_config_raw.clear(); |
| 219 | |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 220 | if (!OpenOutputFile()) |
| 221 | return 1; |
| 222 | |
Primiano Tucci | f3837d5 | 2018-01-10 21:12:41 +0000 | [diff] [blame] | 223 | if (background) { |
| 224 | PERFETTO_CHECK(daemon(0 /*nochdir*/, 0 /*noclose*/) == 0); |
| 225 | PERFETTO_DLOG("Continuing in background"); |
| 226 | } |
| 227 | |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 228 | 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 Maganti | 41844ed | 2018-05-23 14:41:43 +0100 | [diff] [blame] | 233 | #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 Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 237 | if (!limiter.ShouldTrace(args)) |
| 238 | return 1; |
| 239 | |
Florian Mayer | c29e0d3 | 2018-04-04 15:55:46 +0100 | [diff] [blame] | 240 | consumer_endpoint_ = |
| 241 | ConsumerIPCClient::Connect(GetConsumerSocket(), this, &task_runner_); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 242 | SetupCtrlCSignalHandler(); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 243 | task_runner_.Run(); |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 244 | |
| 245 | return limiter.OnTraceDone(args, did_process_full_trace_, |
| 246 | bytes_uploaded_to_dropbox_) |
| 247 | ? 0 |
| 248 | : 1; |
| 249 | } |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 250 | |
| 251 | void 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 Mayer | 80b388e | 2018-02-22 15:51:24 +0000 | [diff] [blame] | 256 | trace_config_->set_enable_extra_guardrails(!dropbox_tag_.empty()); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 257 | |
| 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 Tucci | 0c45fa3 | 2018-01-30 15:52:30 +0000 | [diff] [blame] | 263 | |
| 264 | // Failsafe mechanism to avoid waiting indefinitely if the service hangs. |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 265 | if (trace_config_->duration_ms()) { |
| 266 | task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnTimeout, this), |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 267 | trace_config_->duration_ms() + 10000); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 268 | } |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 269 | } |
| 270 | |
| 271 | void PerfettoCmd::OnDisconnect() { |
| 272 | PERFETTO_LOG("Disconnected from the Perfetto traced service"); |
| 273 | task_runner_.Quit(); |
| 274 | } |
| 275 | |
Primiano Tucci | 0c45fa3 | 2018-01-30 15:52:30 +0000 | [diff] [blame] | 276 | void PerfettoCmd::OnTimeout() { |
| 277 | PERFETTO_ELOG("Timed out while waiting for trace from the service, aborting"); |
| 278 | task_runner_.Quit(); |
| 279 | } |
| 280 | |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 281 | void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) { |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 282 | for (TracePacket& packet : packets) { |
Primiano Tucci | d61b85f | 2018-03-29 02:56:10 +0100 | [diff] [blame] | 283 | uint8_t preamble[16]; |
| 284 | uint8_t* pos = preamble; |
Primiano Tucci | 07e104d | 2018-04-03 20:45:35 +0200 | [diff] [blame] | 285 | // 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 Tucci | d61b85f | 2018-03-29 02:56:10 +0100 | [diff] [blame] | 289 | pos = WriteVarInt(static_cast<uint32_t>(packet.size()), pos); |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 290 | fwrite(reinterpret_cast<const char*>(preamble), |
| 291 | static_cast<size_t>(pos - preamble), 1, trace_out_stream_.get()); |
Primiano Tucci | 09db827 | 2018-03-08 17:47:47 +0000 | [diff] [blame] | 292 | for (const Slice& slice : packet.slices()) { |
Primiano Tucci | 16d1d63 | 2018-02-22 10:16:22 +0000 | [diff] [blame] | 293 | fwrite(reinterpret_cast<const char*>(slice.start), slice.size, 1, |
Sami Kyostila | 26d5cdd | 2018-01-15 16:42:06 +0000 | [diff] [blame] | 294 | trace_out_stream_.get()); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 295 | } |
| 296 | } |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 297 | |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 298 | if (!has_more) |
| 299 | FinalizeTraceAndExit(); // Reached end of trace. |
| 300 | } |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 301 | |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 302 | void PerfettoCmd::OnTracingDisabled() { |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 303 | 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 | |
| 313 | void PerfettoCmd::FinalizeTraceAndExit() { |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 314 | fflush(*trace_out_stream_); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 315 | fseek(*trace_out_stream_, 0, SEEK_END); |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 316 | long bytes_written = ftell(*trace_out_stream_); |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 317 | if (dropbox_tag_.empty()) { |
| 318 | trace_out_stream_.reset(); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 319 | did_process_full_trace_ = true; |
Hector Dearman | 86cfbe1 | 2018-03-22 11:58:42 +0000 | [diff] [blame] | 320 | PERFETTO_ILOG("Wrote %ld bytes into %s", bytes_written, |
| 321 | trace_out_path_.c_str()); |
| 322 | } else { |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 323 | #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 324 | android::sp<android::os::DropBoxManager> dropbox = |
| 325 | new android::os::DropBoxManager(); |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 326 | fseek(*trace_out_stream_, 0, SEEK_SET); |
| 327 | // DropBox takes ownership of the file descriptor, so give it a duplicate. |
Primiano Tucci | 121bf24 | 2018-01-31 11:59:08 +0000 | [diff] [blame] | 328 | // 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 338 | 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 Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 345 | PERFETTO_ELOG("DropBox upload failed: %s", status.toString8().c_str()); |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 346 | } |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 347 | #endif // PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) |
Sami Kyostila | b5b7169 | 2018-01-12 12:16:44 +0000 | [diff] [blame] | 348 | } |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 349 | task_runner_.Quit(); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 350 | } |
| 351 | |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 352 | bool PerfettoCmd::OpenOutputFile() { |
| 353 | base::ScopedFile fd; |
| 354 | if (!dropbox_tag_.empty()) { |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 355 | #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 356 | // If we are tracing to DropBox, there's no need to make a |
| 357 | // filesystem-visible temporary file. |
Primiano Tucci | 941b221 | 2018-03-14 22:46:31 +0000 | [diff] [blame] | 358 | // TODO(skyostil): Fall back to base::TempFile for older devices. |
Adrian DC | 2142099 | 2018-03-09 07:59:58 +0100 | [diff] [blame] | 359 | fd.reset(open(kTempDropBoxTraceDir, O_CREAT | O_TMPFILE | O_RDWR, 0600)); |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 360 | if (!fd) { |
| 361 | PERFETTO_ELOG("Could not create a temporary trace file in %s", |
| 362 | kTempDropBoxTraceDir); |
| 363 | return false; |
| 364 | } |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 365 | #else |
Hector Dearman | f4bc1d1 | 2018-03-26 15:40:13 +0100 | [diff] [blame] | 366 | PERFETTO_FATAL("Tracing to Dropbox requires the Android build."); |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 367 | #endif |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 368 | } else { |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 369 | fd.reset(open(trace_out_path_.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600)); |
Sami Kyostila | 0b99a3b | 2018-01-30 18:05:59 +0000 | [diff] [blame] | 370 | } |
| 371 | trace_out_stream_.reset(fdopen(fd.release(), "wb")); |
| 372 | PERFETTO_CHECK(trace_out_stream_); |
| 373 | return true; |
Sami Kyostila | 26d5cdd | 2018-01-15 16:42:06 +0000 | [diff] [blame] | 374 | } |
| 375 | |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 376 | void 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 397 | sa.sa_flags = static_cast<decltype(sa.sa_flags)>(SA_RESETHAND | SA_RESTART); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 398 | #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 Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 405 | int __attribute__((visibility("default"))) |
| 406 | PerfettoCmdMain(int argc, char** argv) { |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 407 | g_consumer_cmd = new perfetto::PerfettoCmd(); |
| 408 | return g_consumer_cmd->Main(argc, argv); |
Primiano Tucci | 3b72910 | 2018-01-08 18:16:36 +0000 | [diff] [blame] | 409 | } |
| 410 | |
| 411 | } // namespace perfetto |