blob: 27064fd95cc3c73e413c565f42a4a36668b711d5 [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"
25#include "perfetto/traced/traced.h"
26#include "perfetto/tracing/core/data_source_config.h"
27#include "perfetto/tracing/core/data_source_descriptor.h"
Hector Dearmana89cc572018-02-23 12:02:58 +000028#include "perfetto/tracing/core/ftrace_config.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000029#include "perfetto/tracing/core/trace_config.h"
30#include "perfetto/tracing/core/trace_packet.h"
Anna Zappone2a6f9042018-03-14 13:26:07 +000031#include "src/traced/probes/filesystem/inode_file_data_source.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000032
Anna Zappone27ac99c2018-03-06 14:25:35 +000033#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000034#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
Isabelle Taylord404ea12018-02-19 17:28:01 +000035#include "perfetto/trace/trace_packet.pbzero.h"
36
37namespace perfetto {
38namespace {
39
40uint64_t kInitialConnectionBackoffMs = 100;
41uint64_t kMaxConnectionBackoffMs = 30 * 1000;
42const char* kFtraceSourceName = "com.google.perfetto.ftrace";
43const char* kProcessStatsSourceName = "com.google.perfetto.process_stats";
Anna Zappone27ac99c2018-03-06 14:25:35 +000044const char* kInodeFileMapSourceName = "com.google.perfetto.inode_file_map";
Isabelle Taylord404ea12018-02-19 17:28:01 +000045
46} // namespace.
47
48// State transition diagram:
49// +----------------------------+
50// v +
51// NotStarted -> NotConnected -> Connecting -> Connected
52// ^ +
53// +--------------+
54//
55
Hector Dearmanc8488032018-03-02 13:12:01 +000056ProbesProducer::ProbesProducer() {}
Isabelle Taylord404ea12018-02-19 17:28:01 +000057ProbesProducer::~ProbesProducer() = default;
58
59void ProbesProducer::OnConnect() {
60 PERFETTO_DCHECK(state_ == kConnecting);
61 state_ = kConnected;
62 ResetConnectionBackoff();
63 PERFETTO_LOG("Connected to the service");
64
65 DataSourceDescriptor ftrace_descriptor;
66 ftrace_descriptor.set_name(kFtraceSourceName);
Lalit Magantia88807d2018-03-05 18:21:38 +000067 endpoint_->RegisterDataSource(ftrace_descriptor, [](DataSourceInstanceID) {});
Isabelle Taylord404ea12018-02-19 17:28:01 +000068
69 DataSourceDescriptor process_stats_descriptor;
70 process_stats_descriptor.set_name(kProcessStatsSourceName);
71 endpoint_->RegisterDataSource(process_stats_descriptor,
Lalit Magantia88807d2018-03-05 18:21:38 +000072 [](DataSourceInstanceID) {});
Anna Zappone27ac99c2018-03-06 14:25:35 +000073
74 DataSourceDescriptor inode_map_descriptor;
75 inode_map_descriptor.set_name(kInodeFileMapSourceName);
76 endpoint_->RegisterDataSource(inode_map_descriptor,
77 [](DataSourceInstanceID) {});
Isabelle Taylord404ea12018-02-19 17:28:01 +000078}
79
80void ProbesProducer::OnDisconnect() {
81 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
82 state_ = kNotConnected;
83 PERFETTO_LOG("Disconnected from tracing service");
84 IncreaseConnectionBackoff();
85
86 // TODO(hjd): Erase all sinks and add e2e test for this.
87 task_runner_->PostDelayedTask([this] { this->Connect(); },
88 connection_backoff_ms_);
89}
90
91void ProbesProducer::CreateDataSourceInstance(
92 DataSourceInstanceID id,
93 const DataSourceConfig& source_config) {
Isabelle Taylord404ea12018-02-19 17:28:01 +000094 if (source_config.name() == kFtraceSourceName) {
95 CreateFtraceDataSourceInstance(id, source_config);
Anna Zappone27ac99c2018-03-06 14:25:35 +000096 } else if (source_config.name() == kInodeFileMapSourceName) {
Anna Zappone2a6f9042018-03-14 13:26:07 +000097 CreateInodeFileDataSourceInstance(id, source_config);
Hector Dearman77451692018-03-08 16:21:13 +000098 } else if (source_config.name() == kProcessStatsSourceName) {
99 CreateProcessStatsDataSourceInstance(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000100 } else {
101 PERFETTO_ELOG("Data source name: %s not recognised.",
102 source_config.name().c_str());
103 }
104}
105
Anna Zappone27ac99c2018-03-06 14:25:35 +0000106void ProbesProducer::AddWatchdogsTimer(DataSourceInstanceID id,
107 const DataSourceConfig& source_config) {
108 if (source_config.trace_duration_ms() != 0)
109 watchdogs_.emplace(id, base::Watchdog::GetInstance()->CreateFatalTimer(
110 5000 + 2 * source_config.trace_duration_ms()));
111}
112
Isabelle Taylord404ea12018-02-19 17:28:01 +0000113void ProbesProducer::CreateFtraceDataSourceInstance(
114 DataSourceInstanceID id,
115 const DataSourceConfig& source_config) {
116 // Don't retry if FtraceController::Create() failed once.
117 // This can legitimately happen on user builds where we cannot access the
118 // debug paths, e.g., because of SELinux rules.
119 if (ftrace_creation_failed_)
120 return;
121
122 // Lazily create on the first instance.
123 if (!ftrace_) {
124 ftrace_ = FtraceController::Create(task_runner_);
125
126 if (!ftrace_) {
127 PERFETTO_ELOG("Failed to create FtraceController");
128 ftrace_creation_failed_ = true;
129 return;
130 }
131
132 ftrace_->DisableAllEvents();
133 ftrace_->ClearTrace();
134 }
135
136 PERFETTO_LOG("Ftrace start (id=%" PRIu64 ", target_buf=%" PRIu32 ")", id,
137 source_config.target_buffer());
138
Hector Dearmana89cc572018-02-23 12:02:58 +0000139 FtraceConfig proto_config = source_config.ftrace_config();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000140
141 // TODO(hjd): Static cast is bad, target_buffer() should return a BufferID.
142 auto trace_writer = endpoint_->CreateTraceWriter(
143 static_cast<BufferID>(source_config.target_buffer()));
Hector Dearmanc8488032018-03-02 13:12:01 +0000144 auto delegate = std::unique_ptr<SinkDelegate>(
145 new SinkDelegate(task_runner_, std::move(trace_writer)));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000146 auto sink = ftrace_->CreateSink(std::move(proto_config), delegate.get());
Hector Dearmanee3c49d2018-02-28 14:10:22 +0000147 if (!sink) {
148 PERFETTO_ELOG("Failed to start tracing (maybe someone else is using it?)");
149 return;
150 }
Hector Dearman210dc6f2018-03-12 10:51:07 +0000151 delegate->set_sink(std::move(sink));
Isabelle Taylord404ea12018-02-19 17:28:01 +0000152 delegates_.emplace(id, std::move(delegate));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000153 AddWatchdogsTimer(id, source_config);
154}
155
Anna Zappone2a6f9042018-03-14 13:26:07 +0000156void ProbesProducer::CreateInodeFileDataSourceInstance(
Anna Zappone27ac99c2018-03-06 14:25:35 +0000157 DataSourceInstanceID id,
158 const DataSourceConfig& source_config) {
159 PERFETTO_LOG("Inode file map start (id=%" PRIu64 ", target_buf=%" PRIu32 ")",
160 id, source_config.target_buffer());
161 auto trace_writer = endpoint_->CreateTraceWriter(
162 static_cast<BufferID>(source_config.target_buffer()));
Anna Zappone2a6f9042018-03-14 13:26:07 +0000163 if (system_inodes_.empty())
164 CreateDeviceToInodeMap("/system/", &system_inodes_);
165 auto file_map_source = std::unique_ptr<InodeFileDataSource>(
166 new InodeFileDataSource(&system_inodes_, std::move(trace_writer)));
Anna Zappone27ac99c2018-03-06 14:25:35 +0000167 file_map_sources_.emplace(id, std::move(file_map_source));
168 AddWatchdogsTimer(id, source_config);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000169}
170
171void ProbesProducer::CreateProcessStatsDataSourceInstance(
Hector Dearman77451692018-03-08 16:21:13 +0000172 DataSourceInstanceID id,
Isabelle Taylord404ea12018-02-19 17:28:01 +0000173 const DataSourceConfig& source_config) {
Hector Dearman77451692018-03-08 16:21:13 +0000174 PERFETTO_DCHECK(process_stats_sources_.count(id) == 0);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000175 auto trace_writer = endpoint_->CreateTraceWriter(
176 static_cast<BufferID>(source_config.target_buffer()));
Hector Dearmanebf07c72018-03-13 10:31:05 +0000177 auto source = std::unique_ptr<ProcessStatsDataSource>(
178 new ProcessStatsDataSource(std::move(trace_writer)));
179 auto it_and_inserted = process_stats_sources_.emplace(id, std::move(source));
180 PERFETTO_DCHECK(it_and_inserted.second);
181 it_and_inserted.first->second->WriteAllProcesses();
Isabelle Taylord404ea12018-02-19 17:28:01 +0000182}
183
184void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
185 PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
Hector Dearman77451692018-03-08 16:21:13 +0000186 // |id| could be the id of any of the datasources we handle:
187 PERFETTO_DCHECK((delegates_.count(id) + process_stats_sources_.count(id) +
188 file_map_sources_.count(id)) == 1);
189 delegates_.erase(id);
190 process_stats_sources_.erase(id);
191 file_map_sources_.erase(id);
192 watchdogs_.erase(id);
Isabelle Taylord404ea12018-02-19 17:28:01 +0000193}
194
195void ProbesProducer::ConnectWithRetries(const char* socket_name,
196 base::TaskRunner* task_runner) {
197 PERFETTO_DCHECK(state_ == kNotStarted);
198 state_ = kNotConnected;
199
200 ResetConnectionBackoff();
201 socket_name_ = socket_name;
202 task_runner_ = task_runner;
203 Connect();
204}
205
206void ProbesProducer::Connect() {
207 PERFETTO_DCHECK(state_ == kNotConnected);
208 state_ = kConnecting;
209 endpoint_ = ProducerIPCClient::Connect(socket_name_, this, task_runner_);
210}
211
212void ProbesProducer::IncreaseConnectionBackoff() {
213 connection_backoff_ms_ *= 2;
214 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
215 connection_backoff_ms_ = kMaxConnectionBackoffMs;
216}
217
218void ProbesProducer::ResetConnectionBackoff() {
219 connection_backoff_ms_ = kInitialConnectionBackoffMs;
220}
221
Hector Dearmanc8488032018-03-02 13:12:01 +0000222ProbesProducer::SinkDelegate::SinkDelegate(base::TaskRunner* task_runner,
223 std::unique_ptr<TraceWriter> writer)
224 : task_runner_(task_runner),
225 writer_(std::move(writer)),
226 weak_factory_(this) {}
Isabelle Taylord404ea12018-02-19 17:28:01 +0000227
228ProbesProducer::SinkDelegate::~SinkDelegate() = default;
229
230ProbesProducer::FtraceBundleHandle
Hector Dearmanc8488032018-03-02 13:12:01 +0000231
Isabelle Taylord404ea12018-02-19 17:28:01 +0000232ProbesProducer::SinkDelegate::GetBundleForCpu(size_t) {
233 trace_packet_ = writer_->NewTracePacket();
234 return FtraceBundleHandle(trace_packet_->set_ftrace_events());
235}
236
Hector Dearmanc8488032018-03-02 13:12:01 +0000237void ProbesProducer::SinkDelegate::OnBundleComplete(
238 size_t,
239 FtraceBundleHandle,
240 const FtraceMetadata& metadata) {
Isabelle Taylord404ea12018-02-19 17:28:01 +0000241 trace_packet_->Finalize();
Hector Dearmanc8488032018-03-02 13:12:01 +0000242 if (!metadata.inodes.empty()) {
243 auto weak_this = weak_factory_.GetWeakPtr();
244 auto inodes = metadata.inodes;
245 task_runner_->PostTask([weak_this, inodes] {
246 if (weak_this)
247 weak_this->OnInodes(inodes);
248 });
249 }
250}
251
252void ProbesProducer::SinkDelegate::OnInodes(
Anna Zappone2a6f9042018-03-14 13:26:07 +0000253 const std::vector<std::pair<Inode, uint32_t>>& inodes) {
254 PERFETTO_LOG("Saw FtraceBundle with %zu inodes.", inodes.size());
Anna Zappone27ac99c2018-03-06 14:25:35 +0000255}
256
Isabelle Taylord404ea12018-02-19 17:28:01 +0000257} // namespace perfetto