blob: 3c3a5328d8a26b943d3cb3cd21965eca32b0cf9c [file] [log] [blame]
Isabelle Taylord404ea12018-02-19 17:28:01 +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
17#include "src/traced/probes/probes_producer.h"
18
19#include <stdio.h>
Anna Zappone4ea73c02018-03-09 16:01:21 +000020#include <sys/stat.h>
Primiano Tucci52526602018-03-29 22:53:10 +010021
22#include <algorithm>
Anna Zappone27ac99c2018-03-06 14:25:35 +000023#include <queue>
Isabelle Taylord404ea12018-02-19 17:28:01 +000024#include <string>
25
26#include "perfetto/base/logging.h"
Hector Dearman0ff07c72018-03-15 09:54:46 +000027#include "perfetto/base/weak_ptr.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000028#include "perfetto/traced/traced.h"
29#include "perfetto/tracing/core/data_source_config.h"
30#include "perfetto/tracing/core/data_source_descriptor.h"
Hector Dearmana89cc572018-02-23 12:02:58 +000031#include "perfetto/tracing/core/ftrace_config.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000032#include "perfetto/tracing/core/trace_config.h"
33#include "perfetto/tracing/core/trace_packet.h"
Anna Zappone2a6f9042018-03-14 13:26:07 +000034#include "src/traced/probes/filesystem/inode_file_data_source.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000035
Anna Zappone27ac99c2018-03-06 14:25:35 +000036#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000037#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000038#include "perfetto/trace/trace_packet.pbzero.h"
39
40namespace perfetto {
41namespace {
42
43uint64_t kInitialConnectionBackoffMs = 100;
44uint64_t kMaxConnectionBackoffMs = 30 * 1000;
Primiano Tucci578d7842018-03-29 15:27:05 +010045constexpr char kFtraceSourceName[] = "linux.ftrace";
46constexpr char kProcessStatsSourceName[] = "linux.process_stats";
47constexpr char kInodeMapSourceName[] = "linux.inode_file_map";
Isabelle Taylord404ea12018-02-19 17:28:01 +000048
49} // namespace.
50
51// State transition diagram:
52// +----------------------------+
53// v +
54// NotStarted -> NotConnected -> Connecting -> Connected
55// ^ +
56// +--------------+
57//
58
Hector Dearmanc8488032018-03-02 13:12:01 +000059ProbesProducer::ProbesProducer() {}
Isabelle Taylord404ea12018-02-19 17:28:01 +000060ProbesProducer::~ProbesProducer() = default;
61
62void ProbesProducer::OnConnect() {
63 PERFETTO_DCHECK(state_ == kConnecting);
64 state_ = kConnected;
65 ResetConnectionBackoff();
66 PERFETTO_LOG("Connected to the service");
67
68 DataSourceDescriptor ftrace_descriptor;
69 ftrace_descriptor.set_name(kFtraceSourceName);
Primiano Tucci9daa4832018-03-28 23:28:17 +010070 endpoint_->RegisterDataSource(ftrace_descriptor);
Isabelle Taylord404ea12018-02-19 17:28:01 +000071
72 DataSourceDescriptor process_stats_descriptor;
73 process_stats_descriptor.set_name(kProcessStatsSourceName);
Primiano Tucci9daa4832018-03-28 23:28:17 +010074 endpoint_->RegisterDataSource(process_stats_descriptor);
Anna Zappone27ac99c2018-03-06 14:25:35 +000075
76 DataSourceDescriptor inode_map_descriptor;
Hector Dearman0ff07c72018-03-15 09:54:46 +000077 inode_map_descriptor.set_name(kInodeMapSourceName);
Primiano Tucci9daa4832018-03-28 23:28:17 +010078 endpoint_->RegisterDataSource(inode_map_descriptor);
Isabelle Taylord404ea12018-02-19 17:28:01 +000079}
80
81void ProbesProducer::OnDisconnect() {
82 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
83 state_ = kNotConnected;
84 PERFETTO_LOG("Disconnected from tracing service");
85 IncreaseConnectionBackoff();
86
87 // TODO(hjd): Erase all sinks and add e2e test for this.
88 task_runner_->PostDelayedTask([this] { this->Connect(); },
89 connection_backoff_ms_);
90}
91
Hector Dearman0ff07c72018-03-15 09:54:46 +000092void ProbesProducer::CreateDataSourceInstance(DataSourceInstanceID instance_id,
93 const DataSourceConfig& config) {
94 // TODO(hjd): This a hack since we don't actually know the session id. For
95 // now we'll assume anything wit hthe same target buffer is in the same
96 // session.
97 TracingSessionID session_id = config.target_buffer();
98
99 if (config.name() == kFtraceSourceName) {
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100100 if (!CreateFtraceDataSourceInstance(session_id, instance_id, config))
101 failed_sources_.insert(instance_id);
Hector Dearman0ff07c72018-03-15 09:54:46 +0000102 } else if (config.name() == kInodeMapSourceName) {
103 CreateInodeFileDataSourceInstance(session_id, instance_id, config);
104 } else if (config.name() == kProcessStatsSourceName) {
105 CreateProcessStatsDataSourceInstance(session_id, instance_id, config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000106 } else {
107 PERFETTO_ELOG("Data source name: %s not recognised.",
Hector Dearman0ff07c72018-03-15 09:54:46 +0000108 config.name().c_str());
109 return;
110 }
111
112 std::map<TracingSessionID, InodeFileDataSource*> file_sources;
113 std::map<TracingSessionID, ProcessStatsDataSource*> ps_sources;
114 for (const auto& pair : file_map_sources_)
115 file_sources[pair.second->session_id()] = pair.second.get();
116 for (const auto& pair : process_stats_sources_)
117 ps_sources[pair.second->session_id()] = pair.second.get();
118
119 for (const auto& id_to_source : delegates_) {
120 const std::unique_ptr<SinkDelegate>& source = id_to_source.second;
121 if (session_id != source->session_id())
122 continue;
123 if (!source->ps_source() && ps_sources.count(session_id))
124 source->set_ps_source(ps_sources[session_id]->GetWeakPtr());
125 if (!source->file_source() && file_sources.count(session_id))
126 source->set_file_source(file_sources[session_id]->GetWeakPtr());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000127 }
128}
129
Anna Zappone27ac99c2018-03-06 14:25:35 +0000130void ProbesProducer::AddWatchdogsTimer(DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000131 const DataSourceConfig& config) {
132 if (config.trace_duration_ms() != 0)
Anna Zappone27ac99c2018-03-06 14:25:35 +0000133 watchdogs_.emplace(id, base::Watchdog::GetInstance()->CreateFatalTimer(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000134 5000 + 2 * config.trace_duration_ms()));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000135}
136
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100137bool ProbesProducer::CreateFtraceDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000138 TracingSessionID session_id,
Isabelle Taylord404ea12018-02-19 17:28:01 +0000139 DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000140 const DataSourceConfig& config) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000141 // Don't retry if FtraceController::Create() failed once.
142 // This can legitimately happen on user builds where we cannot access the
143 // debug paths, e.g., because of SELinux rules.
144 if (ftrace_creation_failed_)
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100145 return false;
Isabelle Taylord404ea12018-02-19 17:28:01 +0000146
147 // Lazily create on the first instance.
148 if (!ftrace_) {
149 ftrace_ = FtraceController::Create(task_runner_);
150
151 if (!ftrace_) {
152 PERFETTO_ELOG("Failed to create FtraceController");
153 ftrace_creation_failed_ = true;
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100154 return false;
Isabelle Taylord404ea12018-02-19 17:28:01 +0000155 }
156
157 ftrace_->DisableAllEvents();
158 ftrace_->ClearTrace();
159 }
160
161 PERFETTO_LOG("Ftrace start (id=%" PRIu64 ", target_buf=%" PRIu32 ")", id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000162 config.target_buffer());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000163
Hector Dearman0ff07c72018-03-15 09:54:46 +0000164 FtraceConfig proto_config = config.ftrace_config();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000165
166 // TODO(hjd): Static cast is bad, target_buffer() should return a BufferID.
167 auto trace_writer = endpoint_->CreateTraceWriter(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000168 static_cast<BufferID>(config.target_buffer()));
Hector Dearmanc8488032018-03-02 13:12:01 +0000169 auto delegate = std::unique_ptr<SinkDelegate>(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000170 new SinkDelegate(session_id, task_runner_, std::move(trace_writer)));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000171 auto sink = ftrace_->CreateSink(std::move(proto_config), delegate.get());
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000172 if (!sink) {
173 PERFETTO_ELOG("Failed to start tracing (maybe someone else is using it?)");
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100174 return false;
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000175 }
Hector Dearman210dc6f2018-03-12 10:51:07 +0000176 delegate->set_sink(std::move(sink));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000177 delegates_.emplace(id, std::move(delegate));
Hector Dearman0ff07c72018-03-15 09:54:46 +0000178 AddWatchdogsTimer(id, config);
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100179 return true;
Anna Zappone27ac99c2018-03-06 14:25:35 +0000180}
181
Anna Zappone2a6f9042018-03-14 13:26:07 +0000182void ProbesProducer::CreateInodeFileDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000183 TracingSessionID session_id,
Anna Zappone27ac99c2018-03-06 14:25:35 +0000184 DataSourceInstanceID id,
Primiano Tuccidae35652018-03-29 18:32:02 +0100185 DataSourceConfig source_config) {
Anna Zappone27ac99c2018-03-06 14:25:35 +0000186 PERFETTO_LOG("Inode file map start (id=%" PRIu64 ", target_buf=%" PRIu32 ")",
187 id, source_config.target_buffer());
188 auto trace_writer = endpoint_->CreateTraceWriter(
189 static_cast<BufferID>(source_config.target_buffer()));
Anna Zappone2a6f9042018-03-14 13:26:07 +0000190 if (system_inodes_.empty())
Hector Dearman7fabd702018-03-28 12:37:15 +0100191 CreateStaticDeviceToInodeMap("/system", &system_inodes_);
Primiano Tuccidae35652018-03-29 18:32:02 +0100192 auto file_map_source =
193 std::unique_ptr<InodeFileDataSource>(new InodeFileDataSource(
194 std::move(source_config), task_runner_, session_id, &system_inodes_,
195 &cache_, std::move(trace_writer)));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000196 file_map_sources_.emplace(id, std::move(file_map_source));
197 AddWatchdogsTimer(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000198}
199
200void ProbesProducer::CreateProcessStatsDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000201 TracingSessionID session_id,
Hector Dearman77451692018-03-08 16:21:13 +0000202 DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000203 const DataSourceConfig& config) {
Hector Dearman77451692018-03-08 16:21:13 +0000204 PERFETTO_DCHECK(process_stats_sources_.count(id) == 0);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000205 auto trace_writer = endpoint_->CreateTraceWriter(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000206 static_cast<BufferID>(config.target_buffer()));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000207 auto source = std::unique_ptr<ProcessStatsDataSource>(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000208 new ProcessStatsDataSource(session_id, std::move(trace_writer)));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000209 auto it_and_inserted = process_stats_sources_.emplace(id, std::move(source));
210 PERFETTO_DCHECK(it_and_inserted.second);
Hector Dearman1b9c58a2018-03-29 18:45:06 +0100211 if (std::find(config.process_stats_config().quirks().begin(),
212 config.process_stats_config().quirks().end(),
213 ProcessStatsConfig::DISABLE_INITIAL_DUMP) !=
214 config.process_stats_config().quirks().end()) {
215 PERFETTO_DLOG("Initial process tree dump is disabled.");
216 return;
217 }
Hector Dearmanebf07c72018-03-13 10:31:05 +0000218 it_and_inserted.first->second->WriteAllProcesses();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000219}
220
221void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
222 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
Hector Dearman77451692018-03-08 16:21:13 +0000223 // |id| could be the id of any of the datasources we handle:
Hector Dearmanaa69aff2018-03-26 19:49:23 +0100224 PERFETTO_DCHECK((failed_sources_.count(id) + delegates_.count(id) +
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100225 process_stats_sources_.count(id) +
Hector Dearman77451692018-03-08 16:21:13 +0000226 file_map_sources_.count(id)) == 1);
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100227 failed_sources_.erase(id);
Hector Dearman77451692018-03-08 16:21:13 +0000228 delegates_.erase(id);
229 process_stats_sources_.erase(id);
230 file_map_sources_.erase(id);
231 watchdogs_.erase(id);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000232}
233
Isabelle Taylor69faa902018-03-21 15:42:03 +0000234void ProbesProducer::OnTracingStart() {}
235void ProbesProducer::OnTracingStop() {}
236
Isabelle Taylord404ea12018-02-19 17:28:01 +0000237void ProbesProducer::ConnectWithRetries(const char* socket_name,
238 base::TaskRunner* task_runner) {
239 PERFETTO_DCHECK(state_ == kNotStarted);
240 state_ = kNotConnected;
241
242 ResetConnectionBackoff();
243 socket_name_ = socket_name;
244 task_runner_ = task_runner;
245 Connect();
246}
247
248void ProbesProducer::Connect() {
249 PERFETTO_DCHECK(state_ == kNotConnected);
250 state_ = kConnecting;
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100251 endpoint_ = ProducerIPCClient::Connect(
Primiano Tucci578d7842018-03-29 15:27:05 +0100252 socket_name_, this, "perfetto.traced_probes", task_runner_);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000253}
254
255void ProbesProducer::IncreaseConnectionBackoff() {
256 connection_backoff_ms_ *= 2;
257 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
258 connection_backoff_ms_ = kMaxConnectionBackoffMs;
259}
260
261void ProbesProducer::ResetConnectionBackoff() {
262 connection_backoff_ms_ = kInitialConnectionBackoffMs;
263}
264
Hector Dearman0ff07c72018-03-15 09:54:46 +0000265ProbesProducer::SinkDelegate::SinkDelegate(TracingSessionID id,
266 base::TaskRunner* task_runner,
Hector Dearmanc8488032018-03-02 13:12:01 +0000267 std::unique_ptr<TraceWriter> writer)
Hector Dearman0ff07c72018-03-15 09:54:46 +0000268 : session_id_(id),
269 task_runner_(task_runner),
Hector Dearmanc8488032018-03-02 13:12:01 +0000270 writer_(std::move(writer)),
271 weak_factory_(this) {}
Isabelle Taylord404ea12018-02-19 17:28:01 +0000272
273ProbesProducer::SinkDelegate::~SinkDelegate() = default;
274
275ProbesProducer::FtraceBundleHandle
276ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
277 trace_packet_ = writer_->NewTracePacket();
278 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
279}
280
Hector Dearmanc8488032018-03-02 13:12:01 +0000281void ProbesProducer::SinkDelegate::OnBundleComplete(
282 size_t,
283 FtraceBundleHandle,
284 const FtraceMetadata& metadata) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000285 trace_packet_->Finalize();
Hector Dearman0ff07c72018-03-15 09:54:46 +0000286
Hector Dearman3c4e5c22018-03-29 11:31:55 +0100287 if (ps_source_ && !metadata.pids.empty()) {
288 const auto& pids = metadata.pids;
289 auto weak_ps_source = ps_source_;
290 task_runner_->PostTask([weak_ps_source, pids] {
291 if (weak_ps_source)
292 weak_ps_source->OnPids(pids);
293 });
294 }
295
Anna Zappone8ce30872018-03-19 17:01:15 +0000296 if (file_source_ && !metadata.inode_and_device.empty()) {
297 auto inodes = metadata.inode_and_device;
Hector Dearman0ff07c72018-03-15 09:54:46 +0000298 auto weak_file_source = file_source_;
299 task_runner_->PostTask([weak_file_source, inodes] {
300 if (weak_file_source)
301 weak_file_source->OnInodes(inodes);
Hector Dearmanc8488032018-03-02 13:12:01 +0000302 });
303 }
304}
305
Isabelle Taylord404ea12018-02-19 17:28:01 +0000306} // namespace perfetto