blob: 854abf155835cd5a2b258ab9a67a1969402c0066 [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;
43const char* kFtraceSourceName = "com.google.perfetto.ftrace";
44const char* kProcessStatsSourceName = "com.google.perfetto.process_stats";
Hector Dearman0ff07c72018-03-15 09:54:46 +000045const 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) {
100 CreateFtraceDataSourceInstance(session_id, instance_id, config);
101 } else if (config.name() == kInodeMapSourceName) {
102 CreateInodeFileDataSourceInstance(session_id, instance_id, config);
103 } else if (config.name() == kProcessStatsSourceName) {
104 CreateProcessStatsDataSourceInstance(session_id, instance_id, config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000105 } else {
106 PERFETTO_ELOG("Data source name: %s not recognised.",
Hector Dearman0ff07c72018-03-15 09:54:46 +0000107 config.name().c_str());
108 return;
109 }
110
111 std::map<TracingSessionID, InodeFileDataSource*> file_sources;
112 std::map<TracingSessionID, ProcessStatsDataSource*> ps_sources;
113 for (const auto& pair : file_map_sources_)
114 file_sources[pair.second->session_id()] = pair.second.get();
115 for (const auto& pair : process_stats_sources_)
116 ps_sources[pair.second->session_id()] = pair.second.get();
117
118 for (const auto& id_to_source : delegates_) {
119 const std::unique_ptr<SinkDelegate>& source = id_to_source.second;
120 if (session_id != source->session_id())
121 continue;
122 if (!source->ps_source() && ps_sources.count(session_id))
123 source->set_ps_source(ps_sources[session_id]->GetWeakPtr());
124 if (!source->file_source() && file_sources.count(session_id))
125 source->set_file_source(file_sources[session_id]->GetWeakPtr());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000126 }
127}
128
Anna Zappone27ac99c2018-03-06 14:25:35 +0000129void ProbesProducer::AddWatchdogsTimer(DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000130 const DataSourceConfig& config) {
131 if (config.trace_duration_ms() != 0)
Anna Zappone27ac99c2018-03-06 14:25:35 +0000132 watchdogs_.emplace(id, base::Watchdog::GetInstance()->CreateFatalTimer(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000133 5000 + 2 * config.trace_duration_ms()));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000134}
135
Isabelle Taylord404ea12018-02-19 17:28:01 +0000136void ProbesProducer::CreateFtraceDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000137 TracingSessionID session_id,
Isabelle Taylord404ea12018-02-19 17:28:01 +0000138 DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000139 const DataSourceConfig& config) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000140 // Don't retry if FtraceController::Create() failed once.
141 // This can legitimately happen on user builds where we cannot access the
142 // debug paths, e.g., because of SELinux rules.
143 if (ftrace_creation_failed_)
144 return;
145
146 // Lazily create on the first instance.
147 if (!ftrace_) {
148 ftrace_ = FtraceController::Create(task_runner_);
149
150 if (!ftrace_) {
151 PERFETTO_ELOG("Failed to create FtraceController");
152 ftrace_creation_failed_ = true;
153 return;
154 }
155
156 ftrace_->DisableAllEvents();
157 ftrace_->ClearTrace();
158 }
159
160 PERFETTO_LOG("Ftrace start (id=%" PRIu64 ", target_buf=%" PRIu32 ")", id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000161 config.target_buffer());
Isabelle Taylord404ea12018-02-19 17:28:01 +0000162
Hector Dearman0ff07c72018-03-15 09:54:46 +0000163 FtraceConfig proto_config = config.ftrace_config();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000164
165 // TODO(hjd): Static cast is bad, target_buffer() should return a BufferID.
166 auto trace_writer = endpoint_->CreateTraceWriter(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000167 static_cast<BufferID>(config.target_buffer()));
Hector Dearmanc8488032018-03-02 13:12:01 +0000168 auto delegate = std::unique_ptr<SinkDelegate>(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000169 new SinkDelegate(session_id, task_runner_, std::move(trace_writer)));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000170 auto sink = ftrace_->CreateSink(std::move(proto_config), delegate.get());
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000171 if (!sink) {
172 PERFETTO_ELOG("Failed to start tracing (maybe someone else is using it?)");
173 return;
174 }
Hector Dearman210dc6f2018-03-12 10:51:07 +0000175 delegate->set_sink(std::move(sink));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000176 delegates_.emplace(id, std::move(delegate));
Hector Dearman0ff07c72018-03-15 09:54:46 +0000177 AddWatchdogsTimer(id, config);
Anna Zappone27ac99c2018-03-06 14:25:35 +0000178}
179
Anna Zappone2a6f9042018-03-14 13:26:07 +0000180void ProbesProducer::CreateInodeFileDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000181 TracingSessionID session_id,
Anna Zappone27ac99c2018-03-06 14:25:35 +0000182 DataSourceInstanceID id,
183 const DataSourceConfig& source_config) {
184 PERFETTO_LOG("Inode file map start (id=%" PRIu64 ", target_buf=%" PRIu32 ")",
185 id, source_config.target_buffer());
186 auto trace_writer = endpoint_->CreateTraceWriter(
187 static_cast<BufferID>(source_config.target_buffer()));
Anna Zappone2a6f9042018-03-14 13:26:07 +0000188 if (system_inodes_.empty())
189 CreateDeviceToInodeMap("/system/", &system_inodes_);
Hector Dearman0ff07c72018-03-15 09:54:46 +0000190 auto file_map_source =
191 std::unique_ptr<InodeFileDataSource>(new InodeFileDataSource(
192 session_id, &system_inodes_, std::move(trace_writer)));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000193 file_map_sources_.emplace(id, std::move(file_map_source));
194 AddWatchdogsTimer(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000195}
196
197void ProbesProducer::CreateProcessStatsDataSourceInstance(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000198 TracingSessionID session_id,
Hector Dearman77451692018-03-08 16:21:13 +0000199 DataSourceInstanceID id,
Hector Dearman0ff07c72018-03-15 09:54:46 +0000200 const DataSourceConfig& config) {
Hector Dearman77451692018-03-08 16:21:13 +0000201 PERFETTO_DCHECK(process_stats_sources_.count(id) == 0);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000202 auto trace_writer = endpoint_->CreateTraceWriter(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000203 static_cast<BufferID>(config.target_buffer()));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000204 auto source = std::unique_ptr<ProcessStatsDataSource>(
Hector Dearman0ff07c72018-03-15 09:54:46 +0000205 new ProcessStatsDataSource(session_id, std::move(trace_writer)));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000206 auto it_and_inserted = process_stats_sources_.emplace(id, std::move(source));
207 PERFETTO_DCHECK(it_and_inserted.second);
208 it_and_inserted.first->second->WriteAllProcesses();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000209}
210
211void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
212 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
Hector Dearman77451692018-03-08 16:21:13 +0000213 // |id| could be the id of any of the datasources we handle:
214 PERFETTO_DCHECK((delegates_.count(id) + process_stats_sources_.count(id) +
215 file_map_sources_.count(id)) == 1);
216 delegates_.erase(id);
217 process_stats_sources_.erase(id);
218 file_map_sources_.erase(id);
219 watchdogs_.erase(id);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000220}
221
222void ProbesProducer::ConnectWithRetries(const char* socket_name,
223 base::TaskRunner* task_runner) {
224 PERFETTO_DCHECK(state_ == kNotStarted);
225 state_ = kNotConnected;
226
227 ResetConnectionBackoff();
228 socket_name_ = socket_name;
229 task_runner_ = task_runner;
230 Connect();
231}
232
233void ProbesProducer::Connect() {
234 PERFETTO_DCHECK(state_ == kNotConnected);
235 state_ = kConnecting;
236 endpoint_ = ProducerIPCClient::Connect(socket_name_, this, task_runner_);
237}
238
239void ProbesProducer::IncreaseConnectionBackoff() {
240 connection_backoff_ms_ *= 2;
241 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
242 connection_backoff_ms_ = kMaxConnectionBackoffMs;
243}
244
245void ProbesProducer::ResetConnectionBackoff() {
246 connection_backoff_ms_ = kInitialConnectionBackoffMs;
247}
248
Hector Dearman0ff07c72018-03-15 09:54:46 +0000249ProbesProducer::SinkDelegate::SinkDelegate(TracingSessionID id,
250 base::TaskRunner* task_runner,
Hector Dearmanc8488032018-03-02 13:12:01 +0000251 std::unique_ptr<TraceWriter> writer)
Hector Dearman0ff07c72018-03-15 09:54:46 +0000252 : session_id_(id),
253 task_runner_(task_runner),
Hector Dearmanc8488032018-03-02 13:12:01 +0000254 writer_(std::move(writer)),
255 weak_factory_(this) {}
Isabelle Taylord404ea12018-02-19 17:28:01 +0000256
257ProbesProducer::SinkDelegate::~SinkDelegate() = default;
258
259ProbesProducer::FtraceBundleHandle
260ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
261 trace_packet_ = writer_->NewTracePacket();
262 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
263}
264
Hector Dearmanc8488032018-03-02 13:12:01 +0000265void ProbesProducer::SinkDelegate::OnBundleComplete(
266 size_t,
267 FtraceBundleHandle,
268 const FtraceMetadata& metadata) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000269 trace_packet_->Finalize();
Hector Dearman0ff07c72018-03-15 09:54:46 +0000270
271 if (file_source_ && !metadata.inodes.empty()) {
Hector Dearmanc8488032018-03-02 13:12:01 +0000272 auto inodes = metadata.inodes;
Hector Dearman0ff07c72018-03-15 09:54:46 +0000273 auto weak_file_source = file_source_;
274 task_runner_->PostTask([weak_file_source, inodes] {
275 if (weak_file_source)
276 weak_file_source->OnInodes(inodes);
Hector Dearmanc8488032018-03-02 13:12:01 +0000277 });
278 }
279}
280
Isabelle Taylord404ea12018-02-19 17:28:01 +0000281} // namespace perfetto