blob: 5d29fd9e786c0987ed1ace32230f650351d8bc7b [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>
Anna Zappone27ac99c2018-03-06 14:25:35 +000021#include <queue>
Isabelle Taylord404ea12018-02-19 17:28:01 +000022#include <string>
23
24#include "perfetto/base/logging.h"
Hector Dearman0ff07c72018-03-15 09:54:46 +000025#include "perfetto/base/weak_ptr.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000026#include "perfetto/traced/traced.h"
27#include "perfetto/tracing/core/data_source_config.h"
28#include "perfetto/tracing/core/data_source_descriptor.h"
Hector Dearmana89cc572018-02-23 12:02:58 +000029#include "perfetto/tracing/core/ftrace_config.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000030#include "perfetto/tracing/core/trace_config.h"
31#include "perfetto/tracing/core/trace_packet.h"
Anna Zappone2a6f9042018-03-14 13:26:07 +000032#include "src/traced/probes/filesystem/inode_file_data_source.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000033
Anna Zappone27ac99c2018-03-06 14:25:35 +000034#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000035#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000036#include "perfetto/trace/trace_packet.pbzero.h"
37
38namespace perfetto {
39namespace {
40
41uint64_t kInitialConnectionBackoffMs = 100;
42uint64_t kMaxConnectionBackoffMs = 30 * 1000;
Florian Mayerdbd08782018-03-21 14:07:51 +000043constexpr char kFtraceSourceName[] = "com.google.perfetto.ftrace";
44constexpr char kProcessStatsSourceName[] = "com.google.perfetto.process_stats";
45constexpr char kInodeMapSourceName[] = "com.google.perfetto.inode_file_map";
Isabelle Taylord404ea12018-02-19 17:28:01 +000046
47} // namespace.
48
49// State transition diagram:
50// +----------------------------+
51// v +
52// NotStarted -> NotConnected -> Connecting -> Connected
53// ^ +
54// +--------------+
55//
56
Hector Dearmanc8488032018-03-02 13:12:01 +000057ProbesProducer::ProbesProducer() {}
Isabelle Taylord404ea12018-02-19 17:28:01 +000058ProbesProducer::~ProbesProducer() = default;
59
60void ProbesProducer::OnConnect() {
61 PERFETTO_DCHECK(state_ == kConnecting);
62 state_ = kConnected;
63 ResetConnectionBackoff();
64 PERFETTO_LOG("Connected to the service");
65
66 DataSourceDescriptor ftrace_descriptor;
67 ftrace_descriptor.set_name(kFtraceSourceName);
Lalit Magantia88807d2018-03-05 18:21:38 +000068 endpoint_->RegisterDataSource(ftrace_descriptor, [](DataSourceInstanceID) {});
Isabelle Taylord404ea12018-02-19 17:28:01 +000069
70 DataSourceDescriptor process_stats_descriptor;
71 process_stats_descriptor.set_name(kProcessStatsSourceName);
72 endpoint_->RegisterDataSource(process_stats_descriptor,
Lalit Magantia88807d2018-03-05 18:21:38 +000073 [](DataSourceInstanceID) {});
Anna Zappone27ac99c2018-03-06 14:25:35 +000074
75 DataSourceDescriptor inode_map_descriptor;
Hector Dearman0ff07c72018-03-15 09:54:46 +000076 inode_map_descriptor.set_name(kInodeMapSourceName);
Anna Zappone27ac99c2018-03-06 14:25:35 +000077 endpoint_->RegisterDataSource(inode_map_descriptor,
78 [](DataSourceInstanceID) {});
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,
185 const DataSourceConfig& source_config) {
186 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())
Anna Zappone3be7b672018-03-23 17:26:10 +0000191 CreateStaticDeviceToInodeMap("/system/", &system_inodes_);
Hector Dearman0ff07c72018-03-15 09:54:46 +0000192 auto file_map_source =
193 std::unique_ptr<InodeFileDataSource>(new InodeFileDataSource(
Anna Zappone3be7b672018-03-23 17:26:10 +0000194 session_id, &system_inodes_, &cache_, std::move(trace_writer)));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000195 file_map_sources_.emplace(id, std::move(file_map_source));
196 AddWatchdogsTimer(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000197}
198
199void ProbesProducer::CreateProcessStatsDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000200 TracingSessionID session_id,
Hector Dearman77451692018-03-08 16:21:13 +0000201 DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000202 const DataSourceConfig& config) {
Hector Dearman77451692018-03-08 16:21:13 +0000203 PERFETTO_DCHECK(process_stats_sources_.count(id) == 0);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000204 auto trace_writer = endpoint_->CreateTraceWriter(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000205 static_cast<BufferID>(config.target_buffer()));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000206 auto source = std::unique_ptr<ProcessStatsDataSource>(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000207 new ProcessStatsDataSource(session_id, std::move(trace_writer)));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000208 auto it_and_inserted = process_stats_sources_.emplace(id, std::move(source));
209 PERFETTO_DCHECK(it_and_inserted.second);
210 it_and_inserted.first->second->WriteAllProcesses();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000211}
212
213void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
214 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
Hector Dearman77451692018-03-08 16:21:13 +0000215 // |id| could be the id of any of the datasources we handle:
Hector Dearmanaa69aff2018-03-26 19:49:23 +0100216 PERFETTO_DCHECK((failed_sources_.count(id) + delegates_.count(id) +
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100217 process_stats_sources_.count(id) +
Hector Dearman77451692018-03-08 16:21:13 +0000218 file_map_sources_.count(id)) == 1);
Hector Dearmanbcb56fb2018-03-26 13:59:24 +0100219 failed_sources_.erase(id);
Hector Dearman77451692018-03-08 16:21:13 +0000220 delegates_.erase(id);
221 process_stats_sources_.erase(id);
222 file_map_sources_.erase(id);
223 watchdogs_.erase(id);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000224}
225
Isabelle Taylor69faa902018-03-21 15:42:03 +0000226void ProbesProducer::OnTracingStart() {}
227void ProbesProducer::OnTracingStop() {}
228
Isabelle Taylord404ea12018-02-19 17:28:01 +0000229void ProbesProducer::ConnectWithRetries(const char* socket_name,
230 base::TaskRunner* task_runner) {
231 PERFETTO_DCHECK(state_ == kNotStarted);
232 state_ = kNotConnected;
233
234 ResetConnectionBackoff();
235 socket_name_ = socket_name;
236 task_runner_ = task_runner;
237 Connect();
238}
239
240void ProbesProducer::Connect() {
241 PERFETTO_DCHECK(state_ == kNotConnected);
242 state_ = kConnecting;
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100243 endpoint_ = ProducerIPCClient::Connect(
244 socket_name_, this, "com.google.perfetto.traced_probes", task_runner_);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000245}
246
247void ProbesProducer::IncreaseConnectionBackoff() {
248 connection_backoff_ms_ *= 2;
249 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
250 connection_backoff_ms_ = kMaxConnectionBackoffMs;
251}
252
253void ProbesProducer::ResetConnectionBackoff() {
254 connection_backoff_ms_ = kInitialConnectionBackoffMs;
255}
256
Hector Dearman0ff07c72018-03-15 09:54:46 +0000257ProbesProducer::SinkDelegate::SinkDelegate(TracingSessionID id,
258 base::TaskRunner* task_runner,
Hector Dearmanc8488032018-03-02 13:12:01 +0000259 std::unique_ptr<TraceWriter> writer)
Hector Dearman0ff07c72018-03-15 09:54:46 +0000260 : session_id_(id),
261 task_runner_(task_runner),
Hector Dearmanc8488032018-03-02 13:12:01 +0000262 writer_(std::move(writer)),
263 weak_factory_(this) {}
Isabelle Taylord404ea12018-02-19 17:28:01 +0000264
265ProbesProducer::SinkDelegate::~SinkDelegate() = default;
266
267ProbesProducer::FtraceBundleHandle
268ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
269 trace_packet_ = writer_->NewTracePacket();
270 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
271}
272
Hector Dearmanc8488032018-03-02 13:12:01 +0000273void ProbesProducer::SinkDelegate::OnBundleComplete(
274 size_t,
275 FtraceBundleHandle,
276 const FtraceMetadata& metadata) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000277 trace_packet_->Finalize();
Hector Dearman0ff07c72018-03-15 09:54:46 +0000278
Anna Zappone8ce30872018-03-19 17:01:15 +0000279 if (file_source_ && !metadata.inode_and_device.empty()) {
280 auto inodes = metadata.inode_and_device;
Hector Dearman0ff07c72018-03-15 09:54:46 +0000281 auto weak_file_source = file_source_;
282 task_runner_->PostTask([weak_file_source, inodes] {
283 if (weak_file_source)
284 weak_file_source->OnInodes(inodes);
Hector Dearmanc8488032018-03-02 13:12:01 +0000285 });
286 }
287}
288
Isabelle Taylord404ea12018-02-19 17:28:01 +0000289} // namespace perfetto