blob: ef344a9d58941a5c3312f048460247989b880e94 [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
2 * Copyright (C) 2017 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
Florian Mayer6a1a4d52018-06-08 16:47:07 +010017#include "src/tracing/core/tracing_service_impl.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000018
Bruce Dawson21c1a0d2018-05-18 12:01:48 +010019#include "perfetto/base/build_config.h"
20
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010021#include <errno.h>
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000022#include <inttypes.h>
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010023#include <limits.h>
Primiano Tucci53589332017-12-19 11:31:13 +010024#include <string.h>
Bruce Dawson21c1a0d2018-05-18 12:01:48 +010025
26#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010027#include <sys/uio.h>
28#include <unistd.h>
Bruce Dawson21c1a0d2018-05-18 12:01:48 +010029#endif
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000030
31#include <algorithm>
32
Primiano Tuccife922332018-03-22 16:15:04 -070033#include "perfetto/base/build_config.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000034#include "perfetto/base/task_runner.h"
Primiano Tucci0c45fa32018-01-30 15:52:30 +000035#include "perfetto/base/utils.h"
Primiano Tucci42e2de12017-12-07 16:46:04 +000036#include "perfetto/tracing/core/consumer.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000037#include "perfetto/tracing/core/data_source_config.h"
38#include "perfetto/tracing/core/producer.h"
39#include "perfetto/tracing/core/shared_memory.h"
Isabelle Taylor69faa902018-03-21 15:42:03 +000040#include "perfetto/tracing/core/shared_memory_abi.h"
Primiano Tucci53589332017-12-19 11:31:13 +010041#include "perfetto/tracing/core/trace_packet.h"
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010042#include "perfetto/tracing/core/trace_writer.h"
Sami Kyostila32e0b542018-02-14 08:55:43 +000043#include "src/tracing/core/packet_stream_validator.h"
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010044#include "src/tracing/core/shared_memory_arbiter_impl.h"
Primiano Tucciecf9e4a2018-03-14 14:51:58 +000045#include "src/tracing/core/trace_buffer.h"
Sami Kyostila32e0b542018-02-14 08:55:43 +000046
Sami Kyostilafbccb3c2018-03-21 14:00:47 +000047#include "perfetto/trace/clock_snapshot.pb.h"
Sami Kyostila32e0b542018-02-14 08:55:43 +000048#include "perfetto/trace/trusted_packet.pb.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000049
Primiano Tucci20d441d2018-01-16 09:25:51 +000050// General note: this class must assume that Producers are malicious and will
51// try to crash / exploit this class. We can trust pointers because they come
52// from the IPC layer, but we should never assume that that the producer calls
53// come in the right order or their arguments are sane / within bounds.
54
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000055namespace perfetto {
56
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000057namespace {
Primiano Tucci1a1951d2018-04-04 21:08:16 +020058constexpr size_t kDefaultShmPageSize = base::kPageSize;
Primiano Tucci20d441d2018-01-16 09:25:51 +000059constexpr int kMaxBuffersPerConsumer = 128;
Primiano Tucci9754d0d2018-09-15 12:41:46 +010060constexpr base::TimeMillis kSnapshotsInterval(10 * 1000);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +010061constexpr int kDefaultWriteIntoFilePeriodMs = 5000;
Primiano Tuccid52e6272018-04-06 19:06:53 +020062constexpr int kFlushTimeoutMs = 1000;
Primiano Tucci356d83f2018-05-08 14:14:33 +010063constexpr int kMaxConcurrentTracingSessions = 5;
Florian Mayerfa71a2f2018-02-23 13:07:55 +000064
65constexpr uint64_t kMillisPerHour = 3600000;
66
67// These apply only if enable_extra_guardrails is true.
68constexpr uint64_t kMaxTracingDurationMillis = 24 * kMillisPerHour;
69constexpr uint64_t kMaxTracingBufferSizeKb = 32 * 1024;
Bruce Dawson21c1a0d2018-05-18 12:01:48 +010070
71#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
72struct iovec {
Florian Mayer6a1a4d52018-06-08 16:47:07 +010073 void* iov_base; // Address
Bruce Dawson21c1a0d2018-05-18 12:01:48 +010074 size_t iov_len; // Block size
75};
76
77// Simple implementation of writev. Note that this does not give the atomicity
78// guarantees of a real writev, but we don't depend on these (we aren't writing
79// to the same file from another thread).
Florian Mayer6a1a4d52018-06-08 16:47:07 +010080ssize_t writev(int fd, const struct iovec* iov, int iovcnt) {
Bruce Dawson21c1a0d2018-05-18 12:01:48 +010081 ssize_t total_size = 0;
82 for (int i = 0; i < iovcnt; ++i) {
83 ssize_t current_size = write(fd, iov[i].iov_base, iov[i].iov_len);
84 if (current_size != static_cast<ssize_t>(iov[i].iov_len))
85 return -1;
86 total_size += current_size;
87 }
88 return total_size;
89}
90
91#define IOV_MAX 1024 // Linux compatible limit.
92
93// uid checking is a NOP on Windows.
Florian Mayer6a1a4d52018-06-08 16:47:07 +010094uid_t getuid() {
95 return 0;
96}
97uid_t geteuid() {
98 return 0;
99}
Bruce Dawson21c1a0d2018-05-18 12:01:48 +0100100#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000101} // namespace
102
Primiano Tucci1a1951d2018-04-04 21:08:16 +0200103// These constants instead are defined in the header because are used by tests.
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100104constexpr size_t TracingServiceImpl::kDefaultShmSize;
105constexpr size_t TracingServiceImpl::kMaxShmSize;
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100106constexpr uint32_t TracingServiceImpl::kDataSourceStopTimeoutMs;
Primiano Tucci9754d0d2018-09-15 12:41:46 +0100107constexpr uint8_t TracingServiceImpl::kSyncMarker[];
Primiano Tucci1a1951d2018-04-04 21:08:16 +0200108
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000109// static
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100110std::unique_ptr<TracingService> TracingService::CreateInstance(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000111 std::unique_ptr<SharedMemory::Factory> shm_factory,
112 base::TaskRunner* task_runner) {
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100113 return std::unique_ptr<TracingService>(
114 new TracingServiceImpl(std::move(shm_factory), task_runner));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000115}
116
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100117TracingServiceImpl::TracingServiceImpl(
118 std::unique_ptr<SharedMemory::Factory> shm_factory,
119 base::TaskRunner* task_runner)
Primiano Tucci53589332017-12-19 11:31:13 +0100120 : task_runner_(task_runner),
121 shm_factory_(std::move(shm_factory)),
Primiano Tucci5e33cad2018-04-30 14:41:25 +0100122 uid_(getuid()),
Primiano Tucci20d441d2018-01-16 09:25:51 +0000123 buffer_ids_(kMaxTraceBufferID),
124 weak_ptr_factory_(this) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000125 PERFETTO_DCHECK(task_runner_);
126}
127
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100128TracingServiceImpl::~TracingServiceImpl() {
Florian Mayeraab53552018-01-24 14:13:55 +0000129 // TODO(fmayer): handle teardown of all Producer.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000130}
131
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100132std::unique_ptr<TracingService::ProducerEndpoint>
133TracingServiceImpl::ConnectProducer(Producer* producer,
134 uid_t uid,
135 const std::string& producer_name,
136 size_t shared_memory_size_hint_bytes) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000137 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci081d46a2018-02-28 11:09:43 +0000138
Florian Mayer61c55482018-03-06 14:43:54 +0000139 if (lockdown_mode_ && uid != geteuid()) {
140 PERFETTO_DLOG("Lockdown mode. Rejecting producer with UID %ld",
141 static_cast<unsigned long>(uid));
142 return nullptr;
143 }
144
Primiano Tucci081d46a2018-02-28 11:09:43 +0000145 if (producers_.size() >= kMaxProducerID) {
146 PERFETTO_DCHECK(false);
147 return nullptr;
148 }
149 const ProducerID id = GetNextProducerID();
150 PERFETTO_DLOG("Producer %" PRIu16 " connected", id);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000151
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100152 std::unique_ptr<ProducerEndpointImpl> endpoint(new ProducerEndpointImpl(
153 id, uid, this, task_runner_, producer, producer_name));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000154 auto it_and_inserted = producers_.emplace(id, endpoint.get());
155 PERFETTO_DCHECK(it_and_inserted.second);
Primiano Tucci1a1951d2018-04-04 21:08:16 +0200156 endpoint->shmem_size_hint_bytes_ = shared_memory_size_hint_bytes;
Primiano Tucci20d441d2018-01-16 09:25:51 +0000157 task_runner_->PostTask(std::bind(&Producer::OnConnect, endpoint->producer_));
Lalit Maganti485faff2018-03-06 11:51:35 +0000158
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000159 return std::move(endpoint);
160}
161
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100162void TracingServiceImpl::DisconnectProducer(ProducerID id) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000163 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci081d46a2018-02-28 11:09:43 +0000164 PERFETTO_DLOG("Producer %" PRIu16 " disconnected", id);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000165 PERFETTO_DCHECK(producers_.count(id));
Sami Kyostila06487a22018-02-27 13:48:38 +0000166
167 for (auto it = data_sources_.begin(); it != data_sources_.end();) {
168 auto next = it;
169 next++;
170 if (it->second.producer_id == id)
Primiano Tucci9daa4832018-03-28 23:28:17 +0100171 UnregisterDataSource(id, it->second.descriptor.name());
Sami Kyostila06487a22018-02-27 13:48:38 +0000172 it = next;
173 }
174
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000175 producers_.erase(id);
Lalit Maganti485faff2018-03-06 11:51:35 +0000176 UpdateMemoryGuardrail();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000177}
178
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100179TracingServiceImpl::ProducerEndpointImpl* TracingServiceImpl::GetProducer(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000180 ProducerID id) const {
Florian Mayercd08ec62018-01-31 17:49:25 +0000181 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000182 auto it = producers_.find(id);
183 if (it == producers_.end())
184 return nullptr;
185 return it->second;
186}
187
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100188std::unique_ptr<TracingService::ConsumerEndpoint>
189TracingServiceImpl::ConnectConsumer(Consumer* consumer) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000190 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci3324dfc2017-12-20 14:35:58 +0100191 PERFETTO_DLOG("Consumer %p connected", reinterpret_cast<void*>(consumer));
Primiano Tucci42e2de12017-12-07 16:46:04 +0000192 std::unique_ptr<ConsumerEndpointImpl> endpoint(
193 new ConsumerEndpointImpl(this, task_runner_, consumer));
194 auto it_and_inserted = consumers_.emplace(endpoint.get());
195 PERFETTO_DCHECK(it_and_inserted.second);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000196 task_runner_->PostTask(std::bind(&Consumer::OnConnect, endpoint->consumer_));
Primiano Tucci42e2de12017-12-07 16:46:04 +0000197 return std::move(endpoint);
198}
199
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100200void TracingServiceImpl::DisconnectConsumer(ConsumerEndpointImpl* consumer) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000201 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci3324dfc2017-12-20 14:35:58 +0100202 PERFETTO_DLOG("Consumer %p disconnected", reinterpret_cast<void*>(consumer));
Primiano Tucci42e2de12017-12-07 16:46:04 +0000203 PERFETTO_DCHECK(consumers_.count(consumer));
Hector Dearman69a64792018-01-11 18:35:02 +0000204
Primiano Tucci20d441d2018-01-16 09:25:51 +0000205 // TODO(primiano) : Check that this is safe (what happens if there are
206 // ReadBuffers() calls posted in the meantime? They need to become noop).
207 if (consumer->tracing_session_id_)
208 FreeBuffers(consumer->tracing_session_id_); // Will also DisableTracing().
Primiano Tucci42e2de12017-12-07 16:46:04 +0000209 consumers_.erase(consumer);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100210
211// At this point no more pointers to |consumer| should be around.
212#if PERFETTO_DCHECK_IS_ON()
213 PERFETTO_DCHECK(!std::any_of(
214 tracing_sessions_.begin(), tracing_sessions_.end(),
215 [consumer](const std::pair<const TracingSessionID, TracingSession>& kv) {
216 return kv.second.consumer == consumer;
217 }));
218#endif
Primiano Tucci42e2de12017-12-07 16:46:04 +0000219}
220
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100221bool TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
222 const TraceConfig& cfg,
223 base::ScopedFile fd) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000224 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci3324dfc2017-12-20 14:35:58 +0100225 PERFETTO_DLOG("Enabling tracing for consumer %p",
226 reinterpret_cast<void*>(consumer));
Florian Mayer61c55482018-03-06 14:43:54 +0000227 if (cfg.lockdown_mode() == TraceConfig::LockdownModeOperation::LOCKDOWN_SET)
228 lockdown_mode_ = true;
229 if (cfg.lockdown_mode() == TraceConfig::LockdownModeOperation::LOCKDOWN_CLEAR)
230 lockdown_mode_ = false;
Primiano Tucci5317b5c2018-03-13 13:55:40 +0000231 TracingSession* tracing_session =
232 GetTracingSession(consumer->tracing_session_id_);
233 if (tracing_session) {
Primiano Tucci53589332017-12-19 11:31:13 +0100234 PERFETTO_DLOG(
235 "A Consumer is trying to EnableTracing() but another tracing session "
Primiano Tucci20d441d2018-01-16 09:25:51 +0000236 "is already active (forgot a call to FreeBuffers() ?)");
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100237 return false;
Primiano Tucci53589332017-12-19 11:31:13 +0100238 }
Primiano Tucci20d441d2018-01-16 09:25:51 +0000239
Florian Mayerfa71a2f2018-02-23 13:07:55 +0000240 if (cfg.enable_extra_guardrails()) {
241 if (cfg.duration_ms() > kMaxTracingDurationMillis) {
242 PERFETTO_ELOG("Requested too long trace (%" PRIu32 "ms > %" PRIu64
243 " ms)",
244 cfg.duration_ms(), kMaxTracingDurationMillis);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100245 return false;
Florian Mayerfa71a2f2018-02-23 13:07:55 +0000246 }
247 uint64_t buf_size_sum = 0;
248 for (const auto& buf : cfg.buffers())
249 buf_size_sum += buf.size_kb();
250 if (buf_size_sum > kMaxTracingBufferSizeKb) {
251 PERFETTO_ELOG("Requested too large trace buffer (%" PRIu64
252 "kB > %" PRIu64 " kB)",
253 buf_size_sum, kMaxTracingBufferSizeKb);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100254 return false;
Florian Mayerfa71a2f2018-02-23 13:07:55 +0000255 }
256 }
257
Primiano Tucci20d441d2018-01-16 09:25:51 +0000258 if (cfg.buffers_size() > kMaxBuffersPerConsumer) {
259 PERFETTO_DLOG("Too many buffers configured (%d)", cfg.buffers_size());
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100260 return false;
Primiano Tucci20d441d2018-01-16 09:25:51 +0000261 }
262
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000263 // TODO(primiano): This is a workaround to prevent that a producer gets stuck
264 // in a state where it stalls by design by having more TraceWriterImpl
Primiano Tucci356d83f2018-05-08 14:14:33 +0100265 // instances than free pages in the buffer. This is really a bug in
266 // trace_probes and the way it handles stalls in the shmem buffer.
267 if (tracing_sessions_.size() >= kMaxConcurrentTracingSessions) {
268 PERFETTO_ELOG("Too many concurrent tracing sesions (%zu)",
269 tracing_sessions_.size());
270 return false;
271 }
Primiano Tucci0c45fa32018-01-30 15:52:30 +0000272
Primiano Tucci20d441d2018-01-16 09:25:51 +0000273 const TracingSessionID tsid = ++last_tracing_session_id_;
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100274 tracing_session =
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100275 &tracing_sessions_.emplace(tsid, TracingSession(tsid, consumer, cfg))
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100276 .first->second;
277
278 if (cfg.write_into_file()) {
279 if (!fd) {
280 PERFETTO_ELOG(
281 "The TraceConfig had write_into_file==true but no fd was passed");
282 return false;
283 }
284 tracing_session->write_into_file = std::move(fd);
285 uint32_t write_period_ms = cfg.file_write_period_ms();
286 if (write_period_ms == 0)
287 write_period_ms = kDefaultWriteIntoFilePeriodMs;
Primiano Tucci9754d0d2018-09-15 12:41:46 +0100288 if (write_period_ms < min_write_period_ms_)
289 write_period_ms = min_write_period_ms_;
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100290 tracing_session->write_period_ms = write_period_ms;
291 tracing_session->max_file_size_bytes = cfg.max_file_size_bytes();
292 tracing_session->bytes_written_into_file = 0;
293 }
Primiano Tucci20d441d2018-01-16 09:25:51 +0000294
Primiano Tucci53589332017-12-19 11:31:13 +0100295 // Initialize the log buffers.
296 bool did_allocate_all_buffers = true;
Primiano Tucci20d441d2018-01-16 09:25:51 +0000297
298 // Allocate the trace buffers. Also create a map to translate a consumer
299 // relative index (TraceConfig.DataSourceConfig.target_buffer) into the
300 // corresponding BufferID, which is a global ID namespace for the service and
301 // all producers.
Primiano Tuccib7cca202018-01-29 16:30:47 +0000302 size_t total_buf_size_kb = 0;
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100303 const size_t num_buffers = static_cast<size_t>(cfg.buffers_size());
304 tracing_session->buffers_index.reserve(num_buffers);
305 for (size_t i = 0; i < num_buffers; i++) {
Primiano Tucci20d441d2018-01-16 09:25:51 +0000306 const TraceConfig::BufferConfig& buffer_cfg = cfg.buffers()[i];
307 BufferID global_id = buffer_ids_.Allocate();
308 if (!global_id) {
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000309 did_allocate_all_buffers = false; // We ran out of IDs.
Primiano Tucci53589332017-12-19 11:31:13 +0100310 break;
311 }
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100312 tracing_session->buffers_index.push_back(global_id);
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000313 const size_t buf_size_bytes = buffer_cfg.size_kb() * 1024u;
Primiano Tuccib7cca202018-01-29 16:30:47 +0000314 total_buf_size_kb += buffer_cfg.size_kb();
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000315 auto it_and_inserted =
Hector Dearman6214c8f2018-03-27 16:16:22 +0100316 buffers_.emplace(global_id, TraceBuffer::Create(buf_size_bytes));
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000317 PERFETTO_DCHECK(it_and_inserted.second); // buffers_.count(global_id) == 0.
Hector Dearman6214c8f2018-03-27 16:16:22 +0100318 std::unique_ptr<TraceBuffer>& trace_buffer = it_and_inserted.first->second;
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000319 if (!trace_buffer) {
Primiano Tuccibbaa58c2017-12-20 13:48:20 +0100320 did_allocate_all_buffers = false;
321 break;
322 }
Primiano Tucci53589332017-12-19 11:31:13 +0100323 }
Isabelle Taylor69faa902018-03-21 15:42:03 +0000324
Lalit Maganti485faff2018-03-06 11:51:35 +0000325 UpdateMemoryGuardrail();
Primiano Tucci53589332017-12-19 11:31:13 +0100326
Primiano Tucci20d441d2018-01-16 09:25:51 +0000327 // This can happen if either:
328 // - All the kMaxTraceBufferID slots are taken.
329 // - OOM, or, more relistically, we exhausted virtual memory.
330 // In any case, free all the previously allocated buffers and abort.
Florian Mayeraab53552018-01-24 14:13:55 +0000331 // TODO(fmayer): add a test to cover this case, this is quite subtle.
Primiano Tucci53589332017-12-19 11:31:13 +0100332 if (!did_allocate_all_buffers) {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100333 for (BufferID global_id : tracing_session->buffers_index) {
Primiano Tucci20d441d2018-01-16 09:25:51 +0000334 buffer_ids_.Free(global_id);
335 buffers_.erase(global_id);
336 }
337 tracing_sessions_.erase(tsid);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100338 return false;
Primiano Tucci53589332017-12-19 11:31:13 +0100339 }
340
Primiano Tucci20d441d2018-01-16 09:25:51 +0000341 consumer->tracing_session_id_ = tsid;
342
Primiano Tucci53589332017-12-19 11:31:13 +0100343 // Enable the data sources on the producers.
344 for (const TraceConfig::DataSource& cfg_data_source : cfg.data_sources()) {
345 // Scan all the registered data sources with a matching name.
346 auto range = data_sources_.equal_range(cfg_data_source.config().name());
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100347 for (auto it = range.first; it != range.second; it++) {
348 TraceConfig::ProducerConfig producer_config;
349 for (auto& config : cfg.producers()) {
350 if (GetProducer(it->second.producer_id)->name_ ==
351 config.producer_name()) {
352 producer_config = config;
353 break;
354 }
355 }
356 CreateDataSourceInstance(cfg_data_source, producer_config, it->second,
357 tracing_session);
358 }
Primiano Tucci53589332017-12-19 11:31:13 +0100359 }
Primiano Tucci53589332017-12-19 11:31:13 +0100360
Primiano Tucci20d441d2018-01-16 09:25:51 +0000361 // Trigger delayed task if the trace is time limited.
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100362 const uint32_t trace_duration_ms = cfg.duration_ms();
363 if (trace_duration_ms > 0) {
Primiano Tucci20d441d2018-01-16 09:25:51 +0000364 auto weak_this = weak_ptr_factory_.GetWeakPtr();
365 task_runner_->PostDelayedTask(
366 [weak_this, tsid] {
367 if (weak_this)
Primiano Tuccid52e6272018-04-06 19:06:53 +0200368 weak_this->FlushAndDisableTracing(tsid);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000369 },
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100370 trace_duration_ms);
Primiano Tucci53589332017-12-19 11:31:13 +0100371 }
Primiano Tuccib7cca202018-01-29 16:30:47 +0000372
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100373 // Start the periodic drain tasks if we should to save the trace into a file.
374 if (cfg.write_into_file()) {
375 auto weak_this = weak_ptr_factory_.GetWeakPtr();
376 task_runner_->PostDelayedTask(
377 [weak_this, tsid] {
378 if (weak_this)
379 weak_this->ReadBuffers(tsid, nullptr);
380 },
Sami Kyostila01c45f02018-03-29 15:43:10 +0100381 tracing_session->delay_to_next_write_period_ms());
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100382 }
383
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100384 tracing_session->pending_stop_acks.clear();
385 tracing_session->state = TracingSession::ENABLED;
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100386 PERFETTO_LOG(
387 "Enabled tracing, #sources:%zu, duration:%d ms, #buffers:%d, total "
388 "buffer size:%zu KB, total sessions:%zu",
389 cfg.data_sources().size(), trace_duration_ms, cfg.buffers_size(),
390 total_buf_size_kb, tracing_sessions_.size());
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100391 return true;
Primiano Tucci42e2de12017-12-07 16:46:04 +0000392}
393
Primiano Tucci20d441d2018-01-16 09:25:51 +0000394// DisableTracing just stops the data sources but doesn't free up any buffer.
395// This is to allow the consumer to freeze the buffers (by stopping the trace)
396// and then drain the buffers. The actual teardown of the TracingSession happens
397// in FreeBuffers().
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100398void TracingServiceImpl::DisableTracing(TracingSessionID tsid,
399 bool disable_immediately) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000400 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000401 TracingSession* tracing_session = GetTracingSession(tsid);
402 if (!tracing_session) {
403 // Can happen if the consumer calls this before EnableTracing() or after
404 // FreeBuffers().
Primiano Tuccidca727d2018-04-04 11:31:55 +0200405 PERFETTO_DLOG("DisableTracing() failed, invalid session ID %" PRIu64, tsid);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000406 return;
407 }
Primiano Tuccib7cca202018-01-29 16:30:47 +0000408
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100409 switch (tracing_session->state) {
410 // Spurious call to DisableTracing() while already disabled, nothing to do.
411 case TracingSession::DISABLED:
412 PERFETTO_DCHECK(tracing_session->data_source_instances.empty());
413 PERFETTO_DCHECK(tracing_session->pending_stop_acks.empty());
414 return;
415
416 // This is either:
417 // A) The case of a graceful DisableTracing() call followed by a call to
418 // FreeBuffers(), iff |disable_immediately| == true. In this case we want
419 // to forcefully transition in the disabled state without waiting for the
420 // outstanding acks because the buffers are going to be destroyed soon.
421 // B) A spurious call, iff |disable_immediately| == false, in which case
422 // there is nothing to do.
423 case TracingSession::DISABLING_WAITING_STOP_ACKS:
424 PERFETTO_DCHECK(tracing_session->data_source_instances.empty());
425 PERFETTO_DCHECK(!tracing_session->pending_stop_acks.empty());
426 if (disable_immediately)
427 DisableTracingNotifyConsumerAndFlushFile(tracing_session);
428 return;
429
430 // This is the nominal case, continues below.
431 case TracingSession::ENABLED:
432 break;
433 }
434
435 tracing_session->pending_stop_acks.clear();
Primiano Tucci20d441d2018-01-16 09:25:51 +0000436 for (const auto& data_source_inst : tracing_session->data_source_instances) {
437 const ProducerID producer_id = data_source_inst.first;
Sami Kyostila06487a22018-02-27 13:48:38 +0000438 const DataSourceInstanceID ds_inst_id = data_source_inst.second.instance_id;
Primiano Tucci20d441d2018-01-16 09:25:51 +0000439 ProducerEndpointImpl* producer = GetProducer(producer_id);
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100440 if (data_source_inst.second.will_notify_on_stop && !disable_immediately) {
441 tracing_session->pending_stop_acks.insert(
442 std::make_pair(producer_id, ds_inst_id));
443 }
Primiano Tuccidca727d2018-04-04 11:31:55 +0200444 producer->TearDownDataSource(ds_inst_id);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000445 }
446 tracing_session->data_source_instances.clear();
447
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100448 // Either this request is flagged with |disable_immediately| or there are no
449 // data sources that are requesting a final handshake. In both cases just mark
450 // the session as disabled immediately, notify the consumer and flush the
451 // trace file (if used).
452 if (tracing_session->pending_stop_acks.empty())
453 return DisableTracingNotifyConsumerAndFlushFile(tracing_session);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100454
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100455 tracing_session->state = TracingSession::DISABLING_WAITING_STOP_ACKS;
456 auto weak_this = weak_ptr_factory_.GetWeakPtr();
457 auto timeout_ms = override_data_source_test_timeout_ms_for_testing
458 ? override_data_source_test_timeout_ms_for_testing
459 : kDataSourceStopTimeoutMs;
460 task_runner_->PostDelayedTask(
461 [weak_this, tsid] {
462 if (weak_this)
463 weak_this->OnDisableTracingTimeout(tsid);
464 },
465 timeout_ms);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100466
Primiano Tucci20d441d2018-01-16 09:25:51 +0000467 // Deliberately NOT removing the session from |tracing_session_|, it's still
468 // needed to call ReadBuffers(). FreeBuffers() will erase() the session.
469}
470
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100471void TracingServiceImpl::NotifyDataSourceStopped(
472 ProducerID producer_id,
473 DataSourceInstanceID data_source_id) {
474 PERFETTO_DCHECK_THREAD(thread_checker_);
475 for (auto& kv : tracing_sessions_) {
476 TracingSession& tracing_session = kv.second;
477 auto& pending_stop_acks = tracing_session.pending_stop_acks;
478 if (pending_stop_acks.empty())
479 continue;
480 if (tracing_session.state != TracingSession::DISABLING_WAITING_STOP_ACKS) {
481 PERFETTO_DCHECK(false);
482 continue;
483 }
484 pending_stop_acks.erase(std::make_pair(producer_id, data_source_id));
485 if (!pending_stop_acks.empty())
486 continue;
487
488 // All data sources acked the termination.
489 DisableTracingNotifyConsumerAndFlushFile(&tracing_session);
490 } // for (tracing_session)
491}
492
493// Always invoked kDataSourceStopTimeoutMs after DisableTracing(). In nominal
494// conditions all data sources should have acked the stop and this will early
495// out.
496void TracingServiceImpl::OnDisableTracingTimeout(TracingSessionID tsid) {
497 PERFETTO_DCHECK_THREAD(thread_checker_);
498 TracingSession* tracing_session = GetTracingSession(tsid);
499 if (!tracing_session ||
500 tracing_session->state != TracingSession::DISABLING_WAITING_STOP_ACKS)
501 return; // Tracing session was successfully disabled.
502
503 PERFETTO_ILOG("Timeout while waiting for ACKs for tracing session %" PRIu64,
504 tsid);
505 PERFETTO_DCHECK(!tracing_session->pending_stop_acks.empty());
506 DisableTracingNotifyConsumerAndFlushFile(tracing_session);
507}
508
509void TracingServiceImpl::DisableTracingNotifyConsumerAndFlushFile(
510 TracingSession* tracing_session) {
511 PERFETTO_DCHECK(tracing_session->state != TracingSession::DISABLED);
512 tracing_session->pending_stop_acks.clear();
513 tracing_session->state = TracingSession::DISABLED;
514
515 if (tracing_session->write_into_file) {
516 tracing_session->write_period_ms = 0;
517 ReadBuffers(tracing_session->id, nullptr);
518 }
519
520 tracing_session->consumer->NotifyOnTracingDisabled();
521}
522
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100523void TracingServiceImpl::Flush(TracingSessionID tsid,
524 uint32_t timeout_ms,
525 ConsumerEndpoint::FlushCallback callback) {
Primiano Tuccid52e6272018-04-06 19:06:53 +0200526 PERFETTO_DCHECK_THREAD(thread_checker_);
527 TracingSession* tracing_session = GetTracingSession(tsid);
528 if (!tracing_session) {
529 PERFETTO_DLOG("Flush() failed, invalid session ID %" PRIu64, tsid);
530 return;
531 }
532
533 if (tracing_session->pending_flushes.size() > 1000) {
534 PERFETTO_ELOG("Too many flushes (%zu) pending for the tracing session",
535 tracing_session->pending_flushes.size());
536 callback(false);
537 return;
538 }
539
540 FlushRequestID flush_request_id = ++last_flush_request_id_;
541 PendingFlush& pending_flush =
542 tracing_session->pending_flushes
543 .emplace_hint(tracing_session->pending_flushes.end(),
544 flush_request_id, PendingFlush(std::move(callback)))
545 ->second;
546
547 // Send a flush request to each producer involved in the tracing session. In
548 // order to issue a flush request we have to build a map of all data source
549 // instance ids enabled for each producer.
550 std::map<ProducerID, std::vector<DataSourceInstanceID>> flush_map;
551 for (const auto& data_source_inst : tracing_session->data_source_instances) {
552 const ProducerID producer_id = data_source_inst.first;
553 const DataSourceInstanceID ds_inst_id = data_source_inst.second.instance_id;
554 flush_map[producer_id].push_back(ds_inst_id);
555 }
556
557 for (const auto& kv : flush_map) {
558 ProducerID producer_id = kv.first;
559 ProducerEndpointImpl* producer = GetProducer(producer_id);
560 const std::vector<DataSourceInstanceID>& data_sources = kv.second;
561 producer->Flush(flush_request_id, data_sources);
562 pending_flush.producers.insert(producer_id);
563 }
564
565 auto weak_this = weak_ptr_factory_.GetWeakPtr();
566 task_runner_->PostDelayedTask(
567 [weak_this, tsid, flush_request_id] {
568 if (weak_this)
569 weak_this->OnFlushTimeout(tsid, flush_request_id);
570 },
571 timeout_ms);
572}
573
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100574void TracingServiceImpl::NotifyFlushDoneForProducer(
575 ProducerID producer_id,
576 FlushRequestID flush_request_id) {
Primiano Tuccid52e6272018-04-06 19:06:53 +0200577 for (auto& kv : tracing_sessions_) {
578 // Remove all pending flushes <= |flush_request_id| for |producer_id|.
579 auto& pending_flushes = kv.second.pending_flushes;
580 auto end_it = pending_flushes.upper_bound(flush_request_id);
581 for (auto it = pending_flushes.begin(); it != end_it;) {
582 PendingFlush& pending_flush = it->second;
583 pending_flush.producers.erase(producer_id);
584 if (pending_flush.producers.empty()) {
585 task_runner_->PostTask(
586 std::bind(std::move(pending_flush.callback), /*success=*/true));
587 it = pending_flushes.erase(it);
588 } else {
589 it++;
590 }
591 } // for (pending_flushes)
592 } // for (tracing_session)
593}
594
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100595void TracingServiceImpl::OnFlushTimeout(TracingSessionID tsid,
596 FlushRequestID flush_request_id) {
Primiano Tuccid52e6272018-04-06 19:06:53 +0200597 TracingSession* tracing_session = GetTracingSession(tsid);
598 if (!tracing_session)
599 return;
600 auto it = tracing_session->pending_flushes.find(flush_request_id);
601 if (it == tracing_session->pending_flushes.end())
602 return; // Nominal case: flush was completed and acked on time.
603 auto callback = std::move(it->second.callback);
604 tracing_session->pending_flushes.erase(it);
605 callback(/*success=*/false);
606}
607
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100608void TracingServiceImpl::FlushAndDisableTracing(TracingSessionID tsid) {
Primiano Tuccid52e6272018-04-06 19:06:53 +0200609 PERFETTO_DCHECK_THREAD(thread_checker_);
610 auto weak_this = weak_ptr_factory_.GetWeakPtr();
611 Flush(tsid, kFlushTimeoutMs, [weak_this, tsid](bool success) {
612 PERFETTO_DLOG("Flush done (success: %d), disabling trace session %" PRIu64,
613 success, tsid);
614 if (weak_this)
615 weak_this->DisableTracing(tsid);
616 });
617}
618
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100619// Note: when this is called to write into a file passed when starting tracing
620// |consumer| will be == nullptr (as opposite to the case of a consumer asking
621// to send the trace data back over IPC).
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100622void TracingServiceImpl::ReadBuffers(TracingSessionID tsid,
623 ConsumerEndpointImpl* consumer) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000624 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000625 TracingSession* tracing_session = GetTracingSession(tsid);
626 if (!tracing_session) {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100627 // This will be hit systematically from the PostDelayedTask when directly
628 // writing into the file (in which case consumer == nullptr). Suppress the
629 // log in this case as it's just spam.
630 if (consumer)
631 PERFETTO_DLOG("Cannot ReadBuffers(): no tracing session is active");
Primiano Tucci53589332017-12-19 11:31:13 +0100632 return; // TODO(primiano): signal failure?
633 }
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100634
635 // This can happen if the file is closed by a previous task because it reaches
636 // |max_file_size_bytes|.
637 if (!tracing_session->write_into_file && !consumer)
638 return;
639
640 if (tracing_session->write_into_file && consumer) {
641 // If the consumer enabled tracing and asked to save the contents into the
642 // passed file makes little sense to also try to read the buffers over IPC,
643 // as that would just steal data from the periodic draining task.
644 PERFETTO_DCHECK(false);
645 return;
646 }
647
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000648 std::vector<TracePacket> packets;
Primiano Tucci5e33cad2018-04-30 14:41:25 +0100649 packets.reserve(1024); // Just an educated guess to avoid trivial expansions.
Primiano Tucci9754d0d2018-09-15 12:41:46 +0100650
651 base::TimeMillis now = base::GetWallTimeMs();
652 if (now >= tracing_session->last_snapshot_time + kSnapshotsInterval) {
653 tracing_session->last_snapshot_time = now;
654 SnapshotSyncMarker(&packets);
655 SnapshotClocks(&packets);
656 SnapshotStats(tracing_session, &packets);
657 }
Sami Kyostila200bd2e2018-03-26 12:24:10 +0100658 MaybeEmitTraceConfig(tracing_session, &packets);
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000659
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100660 size_t packets_bytes = 0; // SUM(slice.size() for each slice in |packets|).
661 size_t total_slices = 0; // SUM(#slices in |packets|).
662
663 // Add up size for packets added by the Maybe* calls above.
664 for (const TracePacket& packet : packets) {
665 packets_bytes += packet.size();
666 total_slices += packet.slices().size();
667 }
668
Primiano Tuccid61b85f2018-03-29 02:56:10 +0100669 // This is a rough threshold to determine how much to read from the buffer in
670 // each task. This is to avoid executing a single huge sending task for too
671 // long and risk to hit the watchdog. This is *not* an upper bound: we just
672 // stop accumulating new packets and PostTask *after* we cross this threshold.
673 // This constant essentially balances the PostTask and IPC overhead vs the
674 // responsiveness of the service. An extremely small value will cause one IPC
675 // and one PostTask for each slice but will keep the service extremely
676 // responsive. An extremely large value will batch the send for the full
677 // buffer in one large task, will hit the blocking send() once the socket
678 // buffers are full and hang the service for a bit (until the consumer
679 // catches up).
680 static constexpr size_t kApproxBytesPerTask = 32768;
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000681 bool did_hit_threshold = false;
682
683 // TODO(primiano): Extend the ReadBuffers API to allow reading only some
684 // buffers, not all of them in one go.
685 for (size_t buf_idx = 0;
686 buf_idx < tracing_session->num_buffers() && !did_hit_threshold;
Primiano Tucci20d441d2018-01-16 09:25:51 +0000687 buf_idx++) {
688 auto tbuf_iter = buffers_.find(tracing_session->buffers_index[buf_idx]);
689 if (tbuf_iter == buffers_.end()) {
690 PERFETTO_DCHECK(false);
691 continue;
692 }
Hector Dearman6214c8f2018-03-27 16:16:22 +0100693 TraceBuffer& tbuf = *tbuf_iter->second;
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000694 tbuf.BeginRead();
695 while (!did_hit_threshold) {
696 TracePacket packet;
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100697 uid_t producer_uid = kInvalidUid;
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000698 if (!tbuf.ReadNextTracePacket(&packet, &producer_uid))
699 break;
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100700 PERFETTO_DCHECK(producer_uid != kInvalidUid);
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000701 PERFETTO_DCHECK(packet.size() > 0);
702 if (!PacketStreamValidator::Validate(packet.slices())) {
703 PERFETTO_DLOG("Dropping invalid packet");
Primiano Tucci53589332017-12-19 11:31:13 +0100704 continue;
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000705 }
Primiano Tucci42e2de12017-12-07 16:46:04 +0000706
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000707 // Append a slice with the trusted UID of the producer. This can't
708 // be spoofed because above we validated that the existing slices
709 // don't contain any trusted UID fields. For added safety we append
710 // instead of prepending because according to protobuf semantics, if
711 // the same field is encountered multiple times the last instance
712 // takes priority. Note that truncated packets are also rejected, so
713 // the producer can't give us a partial packet (e.g., a truncated
714 // string) which only becomes valid when the UID is appended here.
715 protos::TrustedPacket trusted_packet;
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100716 trusted_packet.set_trusted_uid(static_cast<int32_t>(producer_uid));
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000717 static constexpr size_t kTrustedBufSize = 16;
718 Slice slice = Slice::Allocate(kTrustedBufSize);
719 PERFETTO_CHECK(
720 trusted_packet.SerializeToArray(slice.own_data(), kTrustedBufSize));
721 slice.size = static_cast<size_t>(trusted_packet.GetCachedSize());
722 PERFETTO_DCHECK(slice.size > 0 && slice.size <= kTrustedBufSize);
723 packet.AddSlice(std::move(slice));
Primiano Tucci53589332017-12-19 11:31:13 +0100724
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000725 // Append the packet (inclusive of the trusted uid) to |packets|.
726 packets_bytes += packet.size();
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100727 total_slices += packet.slices().size();
Primiano Tuccid61b85f2018-03-29 02:56:10 +0100728 did_hit_threshold = packets_bytes >= kApproxBytesPerTask &&
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100729 !tracing_session->write_into_file;
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000730 packets.emplace_back(std::move(packet));
731 } // for(packets...)
732 } // for(buffers...)
Primiano Tucci53589332017-12-19 11:31:13 +0100733
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100734 // If the caller asked us to write into a file by setting
735 // |write_into_file| == true in the trace config, drain the packets read
736 // (if any) into the given file descriptor.
737 if (tracing_session->write_into_file) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100738 const uint64_t max_size = tracing_session->max_file_size_bytes
739 ? tracing_session->max_file_size_bytes
740 : std::numeric_limits<size_t>::max();
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100741
742 // When writing into a file, the file should look like a root trace.proto
743 // message. Each packet should be prepended with a proto preamble stating
744 // its field id (within trace.proto) and size. Hence the addition below.
745 const size_t max_iovecs = total_slices + packets.size();
746
747 size_t num_iovecs = 0;
748 bool stop_writing_into_file = tracing_session->write_period_ms == 0;
749 std::unique_ptr<struct iovec[]> iovecs(new struct iovec[max_iovecs]);
750 size_t num_iovecs_at_last_packet = 0;
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100751 uint64_t bytes_about_to_be_written = 0;
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100752 for (TracePacket& packet : packets) {
753 std::tie(iovecs[num_iovecs].iov_base, iovecs[num_iovecs].iov_len) =
754 packet.GetProtoPreamble();
755 bytes_about_to_be_written += iovecs[num_iovecs].iov_len;
756 num_iovecs++;
757 for (const Slice& slice : packet.slices()) {
758 // writev() doesn't change the passed pointer. However, struct iovec
759 // take a non-const ptr because it's the same struct used by readv().
760 // Hence the const_cast here.
761 char* start = static_cast<char*>(const_cast<void*>(slice.start));
762 bytes_about_to_be_written += slice.size;
763 iovecs[num_iovecs++] = {start, slice.size};
764 }
765
766 if (tracing_session->bytes_written_into_file +
767 bytes_about_to_be_written >=
768 max_size) {
769 stop_writing_into_file = true;
770 num_iovecs = num_iovecs_at_last_packet;
771 break;
772 }
773
774 num_iovecs_at_last_packet = num_iovecs;
775 }
776 PERFETTO_DCHECK(num_iovecs <= max_iovecs);
777 int fd = *tracing_session->write_into_file;
778
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100779 uint64_t total_wr_size = 0;
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100780
781 // writev() can take at most IOV_MAX entries per call. Batch them.
782 constexpr size_t kIOVMax = IOV_MAX;
783 for (size_t i = 0; i < num_iovecs; i += kIOVMax) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100784 int iov_batch_size = static_cast<int>(std::min(num_iovecs - i, kIOVMax));
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100785 ssize_t wr_size = PERFETTO_EINTR(writev(fd, &iovecs[i], iov_batch_size));
786 if (wr_size <= 0) {
787 PERFETTO_PLOG("writev() failed");
788 stop_writing_into_file = true;
789 break;
790 }
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100791 total_wr_size += static_cast<size_t>(wr_size);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100792 }
793
794 tracing_session->bytes_written_into_file += total_wr_size;
795
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100796 PERFETTO_DLOG("Draining into file, written: %" PRIu64 " KB, stop: %d",
797 (total_wr_size + 1023) / 1024, stop_writing_into_file);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100798 if (stop_writing_into_file) {
799 tracing_session->write_into_file.reset();
800 tracing_session->write_period_ms = 0;
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100801 if (tracing_session->state == TracingSession::ENABLED)
802 DisableTracing(tsid);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100803 return;
804 }
805
806 auto weak_this = weak_ptr_factory_.GetWeakPtr();
807 task_runner_->PostDelayedTask(
808 [weak_this, tsid] {
809 if (weak_this)
810 weak_this->ReadBuffers(tsid, nullptr);
811 },
Sami Kyostila01c45f02018-03-29 15:43:10 +0100812 tracing_session->delay_to_next_write_period_ms());
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100813 return;
814 } // if (tracing_session->write_into_file)
815
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000816 const bool has_more = did_hit_threshold;
817 if (has_more) {
818 auto weak_consumer = consumer->GetWeakPtr();
819 auto weak_this = weak_ptr_factory_.GetWeakPtr();
820 task_runner_->PostTask([weak_this, weak_consumer, tsid] {
821 if (!weak_this || !weak_consumer)
822 return;
823 weak_this->ReadBuffers(tsid, weak_consumer.get());
824 });
825 }
Sami Kyostila32e0b542018-02-14 08:55:43 +0000826
Primiano Tucciecf9e4a2018-03-14 14:51:58 +0000827 // Keep this as tail call, just in case the consumer re-enters.
828 consumer->consumer_->OnTraceData(std::move(packets), has_more);
Primiano Tucci42e2de12017-12-07 16:46:04 +0000829}
830
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100831void TracingServiceImpl::FreeBuffers(TracingSessionID tsid) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000832 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000833 PERFETTO_DLOG("Freeing buffers for session %" PRIu64, tsid);
834 TracingSession* tracing_session = GetTracingSession(tsid);
835 if (!tracing_session) {
Primiano Tuccidca727d2018-04-04 11:31:55 +0200836 PERFETTO_DLOG("FreeBuffers() failed, invalid session ID %" PRIu64, tsid);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000837 return; // TODO(primiano): signal failure?
838 }
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100839 DisableTracing(tsid, /*disable_immediately=*/true);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +0100840
Primiano Tucci20d441d2018-01-16 09:25:51 +0000841 for (BufferID buffer_id : tracing_session->buffers_index) {
842 buffer_ids_.Free(buffer_id);
843 PERFETTO_DCHECK(buffers_.count(buffer_id) == 1);
844 buffers_.erase(buffer_id);
845 }
846 tracing_sessions_.erase(tsid);
Lalit Maganti485faff2018-03-06 11:51:35 +0000847 UpdateMemoryGuardrail();
848
Primiano Tuccib7cca202018-01-29 16:30:47 +0000849 PERFETTO_LOG("Tracing session %" PRIu64 " ended, total sessions:%zu", tsid,
850 tracing_sessions_.size());
Primiano Tucci42e2de12017-12-07 16:46:04 +0000851}
852
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100853void TracingServiceImpl::RegisterDataSource(ProducerID producer_id,
854 const DataSourceDescriptor& desc) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000855 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci9daa4832018-03-28 23:28:17 +0100856 PERFETTO_DLOG("Producer %" PRIu16 " registered data source \"%s\"",
857 producer_id, desc.name().c_str());
Primiano Tucci3324dfc2017-12-20 14:35:58 +0100858
Primiano Tucci53589332017-12-19 11:31:13 +0100859 PERFETTO_DCHECK(!desc.name().empty());
Primiano Tucci9daa4832018-03-28 23:28:17 +0100860 auto reg_ds = data_sources_.emplace(desc.name(),
861 RegisteredDataSource{producer_id, desc});
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800862
Primiano Tucci20d441d2018-01-16 09:25:51 +0000863 // If there are existing tracing sessions, we need to check if the new
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800864 // data source is enabled by any of them.
865 if (tracing_sessions_.empty())
866 return;
867
Primiano Tucci20d441d2018-01-16 09:25:51 +0000868 ProducerEndpointImpl* producer = GetProducer(producer_id);
869 if (!producer) {
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800870 PERFETTO_DCHECK(false);
871 return;
872 }
873
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800874 for (auto& iter : tracing_sessions_) {
875 TracingSession& tracing_session = iter.second;
Oystein Eftevaagf250e1c2018-08-23 16:10:52 -0700876 if (tracing_session.state != TracingSession::ENABLED)
877 continue;
878
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100879 TraceConfig::ProducerConfig producer_config;
880 for (auto& config : tracing_session.config.producers()) {
881 if (producer->name_ == config.producer_name()) {
882 producer_config = config;
883 break;
884 }
885 }
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800886 for (const TraceConfig::DataSource& cfg_data_source :
887 tracing_session.config.data_sources()) {
888 if (cfg_data_source.config().name() == desc.name())
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100889 CreateDataSourceInstance(cfg_data_source, producer_config,
890 reg_ds->second, &tracing_session);
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800891 }
892 }
893}
894
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100895void TracingServiceImpl::UnregisterDataSource(ProducerID producer_id,
896 const std::string& name) {
Sami Kyostila06487a22018-02-27 13:48:38 +0000897 PERFETTO_DCHECK_THREAD(thread_checker_);
898 PERFETTO_CHECK(producer_id);
Sami Kyostila06487a22018-02-27 13:48:38 +0000899 ProducerEndpointImpl* producer = GetProducer(producer_id);
900 PERFETTO_DCHECK(producer);
Primiano Tuccidca727d2018-04-04 11:31:55 +0200901 for (auto& kv : tracing_sessions_) {
902 auto& ds_instances = kv.second.data_source_instances;
903 for (auto it = ds_instances.begin(); it != ds_instances.end();) {
Primiano Tucci9daa4832018-03-28 23:28:17 +0100904 if (it->first == producer_id && it->second.data_source_name == name) {
Primiano Tuccidca727d2018-04-04 11:31:55 +0200905 DataSourceInstanceID ds_inst_id = it->second.instance_id;
906 producer->TearDownDataSource(ds_inst_id);
907 it = ds_instances.erase(it);
Sami Kyostila06487a22018-02-27 13:48:38 +0000908 } else {
909 ++it;
910 }
Primiano Tuccidca727d2018-04-04 11:31:55 +0200911 } // for (data_source_instances)
912 } // for (tracing_session)
Sami Kyostila06487a22018-02-27 13:48:38 +0000913
914 for (auto it = data_sources_.begin(); it != data_sources_.end(); ++it) {
915 if (it->second.producer_id == producer_id &&
Primiano Tucci9daa4832018-03-28 23:28:17 +0100916 it->second.descriptor.name() == name) {
Sami Kyostila06487a22018-02-27 13:48:38 +0000917 data_sources_.erase(it);
918 return;
919 }
920 }
Primiano Tucci9daa4832018-03-28 23:28:17 +0100921
922 PERFETTO_DLOG(
923 "Tried to unregister a non-existent data source \"%s\" for "
924 "producer %" PRIu16,
925 name.c_str(), producer_id);
Sami Kyostila06487a22018-02-27 13:48:38 +0000926 PERFETTO_DCHECK(false);
927}
928
Florian Mayer6a1a4d52018-06-08 16:47:07 +0100929void TracingServiceImpl::CreateDataSourceInstance(
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800930 const TraceConfig::DataSource& cfg_data_source,
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100931 const TraceConfig::ProducerConfig& producer_config,
Sami Kyostila06487a22018-02-27 13:48:38 +0000932 const RegisteredDataSource& data_source,
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800933 TracingSession* tracing_session) {
Florian Mayercd08ec62018-01-31 17:49:25 +0000934 PERFETTO_DCHECK_THREAD(thread_checker_);
Sami Kyostila06487a22018-02-27 13:48:38 +0000935 ProducerEndpointImpl* producer = GetProducer(data_source.producer_id);
936 PERFETTO_DCHECK(producer);
Florian Mayer61c55482018-03-06 14:43:54 +0000937 // An existing producer that is not ftrace could have registered itself as
938 // ftrace, we must not enable it in that case.
Primiano Tucci5e33cad2018-04-30 14:41:25 +0100939 if (lockdown_mode_ && producer->uid_ != uid_) {
Florian Mayer61c55482018-03-06 14:43:54 +0000940 PERFETTO_DLOG("Lockdown mode: not enabling producer %hu", producer->id_);
941 return;
942 }
Isabelle Taylor02f46be2018-03-29 10:34:08 +0100943 // TODO(primiano): Add tests for registration ordering
944 // (data sources vs consumers).
945 if (!cfg_data_source.producer_name_filter().empty()) {
946 if (std::find(cfg_data_source.producer_name_filter().begin(),
947 cfg_data_source.producer_name_filter().end(),
948 producer->name_) ==
949 cfg_data_source.producer_name_filter().end()) {
950 PERFETTO_DLOG("Data source: %s is filtered out for producer: %s",
951 cfg_data_source.config().name().c_str(),
952 producer->name_.c_str());
953 return;
954 }
955 }
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800956
Primiano Tucci20d441d2018-01-16 09:25:51 +0000957 // Create a copy of the DataSourceConfig specified in the trace config. This
958 // will be passed to the producer after translating the |target_buffer| id.
959 // The |target_buffer| parameter passed by the consumer in the trace config is
960 // relative to the buffers declared in the same trace config. This has to be
961 // translated to the global BufferID before passing it to the producers, which
962 // don't know anything about tracing sessions and consumers.
963
964 DataSourceConfig ds_config = cfg_data_source.config(); // Deliberate copy.
Florian Mayereef8b242018-02-20 10:21:20 +0000965 ds_config.set_trace_duration_ms(tracing_session->config.duration_ms());
Primiano Tucci03de28f2018-08-01 11:29:46 +0100966 ds_config.set_tracing_session_id(tracing_session->id);
Primiano Tucci20d441d2018-01-16 09:25:51 +0000967 auto relative_buffer_id = ds_config.target_buffer();
968 if (relative_buffer_id >= tracing_session->num_buffers()) {
969 PERFETTO_LOG(
Isabelle Taylor69faa902018-03-21 15:42:03 +0000970 "The TraceConfig for DataSource %s specified a target_buffer out of "
Primiano Tucci20d441d2018-01-16 09:25:51 +0000971 "bound (%d). Skipping it.",
972 ds_config.name().c_str(), relative_buffer_id);
973 return;
974 }
975 BufferID global_id = tracing_session->buffers_index[relative_buffer_id];
976 PERFETTO_DCHECK(global_id);
977 ds_config.set_target_buffer(global_id);
978
Oystein Eftevaag1269b4a2018-01-10 16:29:38 -0800979 DataSourceInstanceID inst_id = ++last_data_source_instance_id_;
Sami Kyostila06487a22018-02-27 13:48:38 +0000980 tracing_session->data_source_instances.emplace(
Primiano Tucci9daa4832018-03-28 23:28:17 +0100981 producer->id_,
Primiano Tuccibaeecf12018-07-25 12:02:20 +0100982 DataSourceInstance{inst_id, data_source.descriptor.name(),
983 data_source.descriptor.will_notify_on_stop()});
Primiano Tucci20d441d2018-01-16 09:25:51 +0000984 PERFETTO_DLOG("Starting data source %s with target buffer %" PRIu16,
985 ds_config.name().c_str(), global_id);
Isabelle Taylor69faa902018-03-21 15:42:03 +0000986 if (!producer->shared_memory()) {
Primiano Tucci1a1951d2018-04-04 21:08:16 +0200987 // Determine the SMB page size. Must be an integer multiple of 4k.
988 size_t page_size = std::min<size_t>(producer_config.page_size_kb() * 1024,
989 SharedMemoryABI::kMaxPageSize);
990 if (page_size < base::kPageSize || page_size % base::kPageSize != 0)
991 page_size = kDefaultShmPageSize;
992 producer->shared_buffer_page_size_kb_ = page_size / 1024;
Isabelle Taylor86262cb2018-03-27 16:00:54 +0100993
Primiano Tucci1a1951d2018-04-04 21:08:16 +0200994 // Determine the SMB size. Must be an integer multiple of the SMB page size.
995 // The decisional tree is as follows:
996 // 1. Give priority to what defined in the trace config.
997 // 2. If unset give priority to the hint passed by the producer.
998 // 3. Keep within bounds and ensure it's a multiple of the page size.
999 size_t shm_size = producer_config.shm_size_kb() * 1024;
1000 if (shm_size == 0)
1001 shm_size = producer->shmem_size_hint_bytes_;
1002 shm_size = std::min<size_t>(shm_size, kMaxShmSize);
1003 if (shm_size < page_size || shm_size % page_size)
Isabelle Taylor69faa902018-03-21 15:42:03 +00001004 shm_size = kDefaultShmSize;
1005
1006 // TODO(primiano): right now Create() will suicide in case of OOM if the
1007 // mmap fails. We should instead gracefully fail the request and tell the
1008 // client to go away.
1009 auto shared_memory = shm_factory_->CreateSharedMemory(shm_size);
1010 producer->SetSharedMemory(std::move(shared_memory));
Primiano Tuccidca727d2018-04-04 11:31:55 +02001011 producer->OnTracingSetup();
Isabelle Taylor69faa902018-03-21 15:42:03 +00001012 UpdateMemoryGuardrail();
1013 }
Primiano Tuccidca727d2018-04-04 11:31:55 +02001014 producer->CreateDataSourceInstance(inst_id, ds_config);
Primiano Tucci53589332017-12-19 11:31:13 +01001015}
1016
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001017// Note: all the fields % *_trusted ones are untrusted, as in, the Producer
1018// might be lying / returning garbage contents. |src| and |size| can be trusted
1019// in terms of being a valid pointer, but not the contents.
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001020void TracingServiceImpl::CopyProducerPageIntoLogBuffer(
1021 ProducerID producer_id_trusted,
1022 uid_t producer_uid_trusted,
1023 WriterID writer_id,
1024 ChunkID chunk_id,
1025 BufferID buffer_id,
1026 uint16_t num_fragments,
1027 uint8_t chunk_flags,
1028 const uint8_t* src,
1029 size_t size) {
Florian Mayercd08ec62018-01-31 17:49:25 +00001030 PERFETTO_DCHECK_THREAD(thread_checker_);
Hector Dearman6214c8f2018-03-27 16:16:22 +01001031 TraceBuffer* buf = GetBufferByID(buffer_id);
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001032 if (!buf) {
1033 PERFETTO_DLOG("Could not find target buffer %" PRIu16
1034 " for producer %" PRIu16,
1035 buffer_id, producer_id_trusted);
Primiano Tucci53589332017-12-19 11:31:13 +01001036 return;
1037 }
1038
Primiano Tucci20d441d2018-01-16 09:25:51 +00001039 // TODO(primiano): we should have a set<BufferID> |allowed_target_buffers| in
1040 // ProducerEndpointImpl to perform ACL checks and prevent that the Producer
1041 // passes a |target_buffer| which is valid, but that we never asked it to use.
1042 // Essentially we want to prevent a malicious producer to inject data into a
1043 // log buffer that has nothing to do with it.
1044
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001045 buf->CopyChunkUntrusted(producer_id_trusted, producer_uid_trusted, writer_id,
1046 chunk_id, num_fragments, chunk_flags, src, size);
1047}
Primiano Tucci53589332017-12-19 11:31:13 +01001048
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001049void TracingServiceImpl::ApplyChunkPatches(
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001050 ProducerID producer_id_trusted,
1051 const std::vector<CommitDataRequest::ChunkToPatch>& chunks_to_patch) {
1052 PERFETTO_DCHECK_THREAD(thread_checker_);
1053
1054 for (const auto& chunk : chunks_to_patch) {
1055 const ChunkID chunk_id = static_cast<ChunkID>(chunk.chunk_id());
1056 const WriterID writer_id = static_cast<WriterID>(chunk.writer_id());
Hector Dearman6214c8f2018-03-27 16:16:22 +01001057 TraceBuffer* buf =
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001058 GetBufferByID(static_cast<BufferID>(chunk.target_buffer()));
1059 static_assert(std::numeric_limits<ChunkID>::max() == kMaxChunkID,
1060 "Add a '|| chunk_id > kMaxChunkID' below if this fails");
1061 if (!writer_id || writer_id > kMaxWriterID || !buf) {
1062 PERFETTO_DLOG(
1063 "Received invalid chunks_to_patch request from Producer: %" PRIu16
1064 ", BufferID: %" PRIu32 " ChunkdID: %" PRIu32 " WriterID: %" PRIu16,
1065 producer_id_trusted, chunk.target_buffer(), chunk_id, writer_id);
1066 continue;
1067 }
1068 // Speculate on the fact that there are going to be a limited amount of
1069 // patches per request, so we can allocate the |patches| array on the stack.
Hector Dearman6214c8f2018-03-27 16:16:22 +01001070 std::array<TraceBuffer::Patch, 1024> patches; // Uninitialized.
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001071 if (chunk.patches().size() > patches.size()) {
1072 PERFETTO_DLOG("Too many patches (%zu) batched in the same request",
1073 patches.size());
1074 PERFETTO_DCHECK(false);
1075 continue;
1076 }
1077
1078 size_t i = 0;
1079 for (const auto& patch : chunk.patches()) {
1080 const std::string& patch_data = patch.data();
1081 if (patch_data.size() != patches[i].data.size()) {
1082 PERFETTO_DLOG("Received patch from producer: %" PRIu16
1083 " of unexpected size %zu",
1084 producer_id_trusted, patch_data.size());
1085 continue;
1086 }
1087 patches[i].offset_untrusted = patch.offset();
1088 memcpy(&patches[i].data[0], patch_data.data(), patches[i].data.size());
1089 i++;
1090 }
1091 buf->TryPatchChunkContents(producer_id_trusted, writer_id, chunk_id,
1092 &patches[0], i, chunk.has_more_patches());
1093 }
Primiano Tucci53589332017-12-19 11:31:13 +01001094}
1095
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001096TracingServiceImpl::TracingSession* TracingServiceImpl::GetTracingSession(
Primiano Tucci20d441d2018-01-16 09:25:51 +00001097 TracingSessionID tsid) {
Florian Mayercd08ec62018-01-31 17:49:25 +00001098 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci20d441d2018-01-16 09:25:51 +00001099 auto it = tsid ? tracing_sessions_.find(tsid) : tracing_sessions_.end();
1100 if (it == tracing_sessions_.end())
1101 return nullptr;
1102 return &it->second;
1103}
1104
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001105ProducerID TracingServiceImpl::GetNextProducerID() {
Primiano Tucci081d46a2018-02-28 11:09:43 +00001106 PERFETTO_DCHECK_THREAD(thread_checker_);
1107 PERFETTO_CHECK(producers_.size() < kMaxProducerID);
1108 do {
1109 ++last_producer_id_;
1110 } while (producers_.count(last_producer_id_) || last_producer_id_ == 0);
1111 PERFETTO_DCHECK(last_producer_id_ > 0 && last_producer_id_ <= kMaxProducerID);
1112 return last_producer_id_;
1113}
1114
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001115TraceBuffer* TracingServiceImpl::GetBufferByID(BufferID buffer_id) {
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001116 auto buf_iter = buffers_.find(buffer_id);
1117 if (buf_iter == buffers_.end())
1118 return nullptr;
1119 return &*buf_iter->second;
1120}
1121
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001122void TracingServiceImpl::UpdateMemoryGuardrail() {
Primiano Tucci09db8272018-03-08 17:47:47 +00001123#if !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD) && \
1124 !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
Lalit Maganti485faff2018-03-06 11:51:35 +00001125 uint64_t total_buffer_bytes = 0;
1126
1127 // Sum up all the shared memory buffers.
1128 for (const auto& id_to_producer : producers_) {
Isabelle Taylor69faa902018-03-21 15:42:03 +00001129 if (id_to_producer.second->shared_memory())
1130 total_buffer_bytes += id_to_producer.second->shared_memory()->size();
Lalit Maganti485faff2018-03-06 11:51:35 +00001131 }
1132
1133 // Sum up all the trace buffers.
1134 for (const auto& id_to_buffer : buffers_) {
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001135 total_buffer_bytes += id_to_buffer.second->size();
Lalit Maganti485faff2018-03-06 11:51:35 +00001136 }
1137
1138 // Set the guard rail to 32MB + the sum of all the buffers over a 30 second
1139 // interval.
1140 uint64_t guardrail = 32 * 1024 * 1024 + total_buffer_bytes;
1141 base::Watchdog::GetInstance()->SetMemoryLimit(guardrail, 30 * 1000);
1142#endif
1143}
1144
Primiano Tucci9754d0d2018-09-15 12:41:46 +01001145void TracingServiceImpl::SnapshotSyncMarker(std::vector<TracePacket>* packets) {
1146 // The sync markes is used to tokenize large traces efficiently.
1147 // See description in trace_packet.proto.
1148 if (sync_marker_packet_size_ == 0) {
1149 // Serialize the marker and the uid separately to guarantee that the marker
1150 // is serialzied at the end and is adjacent to the start of the next packet.
1151 int size_left = static_cast<int>(sizeof(sync_marker_packet_));
1152 uint8_t* dst = &sync_marker_packet_[0];
1153 protos::TrustedPacket packet;
1154 packet.set_trusted_uid(static_cast<int32_t>(uid_));
1155 PERFETTO_CHECK(packet.SerializeToArray(dst, size_left));
1156 size_left -= packet.ByteSize();
1157 sync_marker_packet_size_ += static_cast<size_t>(packet.ByteSize());
1158 dst += sync_marker_packet_size_;
Oystein Eftevaag4966fdc2018-03-28 10:20:59 -07001159
Primiano Tucci9754d0d2018-09-15 12:41:46 +01001160 packet.Clear();
1161 packet.set_synchronization_marker(kSyncMarker, sizeof(kSyncMarker));
1162 PERFETTO_CHECK(packet.SerializeToArray(dst, size_left));
1163 sync_marker_packet_size_ += static_cast<size_t>(packet.ByteSize());
1164 PERFETTO_CHECK(sync_marker_packet_size_ <= sizeof(sync_marker_packet_));
1165 };
1166 packets->emplace_back();
1167 packets->back().AddSlice(&sync_marker_packet_[0], sync_marker_packet_size_);
1168}
1169
1170void TracingServiceImpl::SnapshotClocks(std::vector<TracePacket>* packets) {
Primiano Tucci07e104d2018-04-03 20:45:35 +02001171 protos::TrustedPacket packet;
Oystein Eftevaag4966fdc2018-03-28 10:20:59 -07001172 protos::ClockSnapshot* clock_snapshot = packet.mutable_clock_snapshot();
1173
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001174#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) && \
1175 !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Sami Kyostilafbccb3c2018-03-21 14:00:47 +00001176 struct {
1177 clockid_t id;
1178 protos::ClockSnapshot::Clock::Type type;
1179 struct timespec ts;
1180 } clocks[] = {
Primiano Tucci9daa4832018-03-28 23:28:17 +01001181 {CLOCK_BOOTTIME, protos::ClockSnapshot::Clock::BOOTTIME, {0, 0}},
1182 {CLOCK_REALTIME_COARSE,
1183 protos::ClockSnapshot::Clock::REALTIME_COARSE,
1184 {0, 0}},
1185 {CLOCK_MONOTONIC_COARSE,
1186 protos::ClockSnapshot::Clock::MONOTONIC_COARSE,
1187 {0, 0}},
1188 {CLOCK_REALTIME, protos::ClockSnapshot::Clock::REALTIME, {0, 0}},
1189 {CLOCK_MONOTONIC, protos::ClockSnapshot::Clock::MONOTONIC, {0, 0}},
1190 {CLOCK_MONOTONIC_RAW,
1191 protos::ClockSnapshot::Clock::MONOTONIC_RAW,
1192 {0, 0}},
1193 {CLOCK_PROCESS_CPUTIME_ID,
1194 protos::ClockSnapshot::Clock::PROCESS_CPUTIME,
1195 {0, 0}},
1196 {CLOCK_THREAD_CPUTIME_ID,
1197 protos::ClockSnapshot::Clock::THREAD_CPUTIME,
1198 {0, 0}},
Sami Kyostilafbccb3c2018-03-21 14:00:47 +00001199 };
Sami Kyostilafbccb3c2018-03-21 14:00:47 +00001200 // First snapshot all the clocks as atomically as we can.
1201 for (auto& clock : clocks) {
1202 if (clock_gettime(clock.id, &clock.ts) == -1)
1203 PERFETTO_DLOG("clock_gettime failed for clock %d", clock.id);
1204 }
1205 for (auto& clock : clocks) {
1206 protos::ClockSnapshot::Clock* c = clock_snapshot->add_clocks();
1207 c->set_type(clock.type);
Primiano Tucci3cbb10a2018-04-10 17:52:40 +01001208 c->set_timestamp(
1209 static_cast<uint64_t>(base::FromPosixTimespec(clock.ts).count()));
Sami Kyostilafbccb3c2018-03-21 14:00:47 +00001210 }
Oystein Eftevaag4966fdc2018-03-28 10:20:59 -07001211#else // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
1212 protos::ClockSnapshot::Clock* c = clock_snapshot->add_clocks();
1213 c->set_type(protos::ClockSnapshot::Clock::MONOTONIC);
Primiano Tucci3cbb10a2018-04-10 17:52:40 +01001214 c->set_timestamp(static_cast<uint64_t>(base::GetWallTimeNs().count()));
Oystein Eftevaag4966fdc2018-03-28 10:20:59 -07001215#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
1216
Primiano Tucci5e33cad2018-04-30 14:41:25 +01001217 packet.set_trusted_uid(static_cast<int32_t>(uid_));
1218 Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
1219 PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
1220 packets->emplace_back();
1221 packets->back().AddSlice(std::move(slice));
1222}
1223
Primiano Tucci9754d0d2018-09-15 12:41:46 +01001224void TracingServiceImpl::SnapshotStats(TracingSession* tracing_session,
1225 std::vector<TracePacket>* packets) {
Primiano Tucci5e33cad2018-04-30 14:41:25 +01001226 protos::TrustedPacket packet;
1227 packet.set_trusted_uid(static_cast<int32_t>(uid_));
1228
1229 protos::TraceStats* trace_stats = packet.mutable_trace_stats();
1230 trace_stats->set_producers_connected(
1231 static_cast<uint32_t>(producers_.size()));
1232 trace_stats->set_producers_seen(last_producer_id_);
1233 trace_stats->set_data_sources_registered(
1234 static_cast<uint32_t>(data_sources_.size()));
1235 trace_stats->set_data_sources_seen(last_data_source_instance_id_);
1236 trace_stats->set_tracing_sessions(
1237 static_cast<uint32_t>(tracing_sessions_.size()));
1238 trace_stats->set_total_buffers(static_cast<uint32_t>(buffers_.size()));
1239
1240 for (BufferID buf_id : tracing_session->buffers_index) {
1241 TraceBuffer* buf = GetBufferByID(buf_id);
1242 if (!buf) {
1243 PERFETTO_DCHECK(false);
1244 continue;
1245 }
1246 auto* buf_stats_proto = trace_stats->add_buffer_stats();
1247 const TraceBuffer::Stats& buf_stats = buf->stats();
1248 buf_stats_proto->set_bytes_written(buf_stats.bytes_written);
1249 buf_stats_proto->set_chunks_written(buf_stats.chunks_written);
1250 buf_stats_proto->set_chunks_overwritten(buf_stats.chunks_overwritten);
1251 buf_stats_proto->set_write_wrap_count(buf_stats.write_wrap_count);
1252 buf_stats_proto->set_patches_succeeded(buf_stats.patches_succeeded);
1253 buf_stats_proto->set_patches_failed(buf_stats.patches_failed);
1254 buf_stats_proto->set_readaheads_succeeded(buf_stats.readaheads_succeeded);
1255 buf_stats_proto->set_readaheads_failed(buf_stats.readaheads_failed);
1256 buf_stats_proto->set_abi_violations(buf_stats.abi_violations);
1257 } // for (buf in session).
Primiano Tucci3cbb10a2018-04-10 17:52:40 +01001258 Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
Sami Kyostila200bd2e2018-03-26 12:24:10 +01001259 PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
1260 packets->emplace_back();
1261 packets->back().AddSlice(std::move(slice));
1262}
1263
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001264void TracingServiceImpl::MaybeEmitTraceConfig(
1265 TracingSession* tracing_session,
1266 std::vector<TracePacket>* packets) {
Sami Kyostila200bd2e2018-03-26 12:24:10 +01001267 if (tracing_session->did_emit_config)
1268 return;
1269 tracing_session->did_emit_config = true;
Primiano Tucci07e104d2018-04-03 20:45:35 +02001270 protos::TrustedPacket packet;
Sami Kyostila200bd2e2018-03-26 12:24:10 +01001271 tracing_session->config.ToProto(packet.mutable_trace_config());
Primiano Tucci5e33cad2018-04-30 14:41:25 +01001272 packet.set_trusted_uid(static_cast<int32_t>(uid_));
Primiano Tucci3cbb10a2018-04-10 17:52:40 +01001273 Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
Sami Kyostilafbccb3c2018-03-21 14:00:47 +00001274 PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
1275 packets->emplace_back();
1276 packets->back().AddSlice(std::move(slice));
1277}
1278
Primiano Tucci42e2de12017-12-07 16:46:04 +00001279////////////////////////////////////////////////////////////////////////////////
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001280// TracingServiceImpl::ConsumerEndpointImpl implementation
Primiano Tucci42e2de12017-12-07 16:46:04 +00001281////////////////////////////////////////////////////////////////////////////////
1282
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001283TracingServiceImpl::ConsumerEndpointImpl::ConsumerEndpointImpl(
1284 TracingServiceImpl* service,
Primiano Tucci2ffd1a52018-03-27 01:01:30 +01001285 base::TaskRunner* task_runner,
1286 Consumer* consumer)
1287 : task_runner_(task_runner),
1288 service_(service),
1289 consumer_(consumer),
1290 weak_ptr_factory_(this) {}
Primiano Tucci42e2de12017-12-07 16:46:04 +00001291
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001292TracingServiceImpl::ConsumerEndpointImpl::~ConsumerEndpointImpl() {
Primiano Tucci42e2de12017-12-07 16:46:04 +00001293 service_->DisconnectConsumer(this);
Sami Kyostila06487a22018-02-27 13:48:38 +00001294 consumer_->OnDisconnect();
Primiano Tucci42e2de12017-12-07 16:46:04 +00001295}
1296
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001297void TracingServiceImpl::ConsumerEndpointImpl::NotifyOnTracingDisabled() {
Florian Mayercd08ec62018-01-31 17:49:25 +00001298 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +01001299 auto weak_this = GetWeakPtr();
1300 task_runner_->PostTask([weak_this] {
1301 if (weak_this)
Primiano Tuccidca727d2018-04-04 11:31:55 +02001302 weak_this->consumer_->OnTracingDisabled();
Primiano Tucci2ffd1a52018-03-27 01:01:30 +01001303 });
1304}
1305
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001306void TracingServiceImpl::ConsumerEndpointImpl::EnableTracing(
1307 const TraceConfig& cfg,
1308 base::ScopedFile fd) {
Primiano Tucci2ffd1a52018-03-27 01:01:30 +01001309 PERFETTO_DCHECK_THREAD(thread_checker_);
1310 if (!service_->EnableTracing(this, cfg, std::move(fd)))
Primiano Tuccidca727d2018-04-04 11:31:55 +02001311 NotifyOnTracingDisabled();
Primiano Tucci42e2de12017-12-07 16:46:04 +00001312}
1313
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001314void TracingServiceImpl::ConsumerEndpointImpl::DisableTracing() {
Florian Mayercd08ec62018-01-31 17:49:25 +00001315 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tuccidca727d2018-04-04 11:31:55 +02001316 if (!tracing_session_id_) {
Primiano Tucci20d441d2018-01-16 09:25:51 +00001317 PERFETTO_LOG("Consumer called DisableTracing() but tracing was not active");
Primiano Tuccidca727d2018-04-04 11:31:55 +02001318 return;
Primiano Tucci20d441d2018-01-16 09:25:51 +00001319 }
Primiano Tuccidca727d2018-04-04 11:31:55 +02001320 service_->DisableTracing(tracing_session_id_);
Primiano Tucci42e2de12017-12-07 16:46:04 +00001321}
1322
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001323void TracingServiceImpl::ConsumerEndpointImpl::ReadBuffers() {
Florian Mayercd08ec62018-01-31 17:49:25 +00001324 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tuccidca727d2018-04-04 11:31:55 +02001325 if (!tracing_session_id_) {
Primiano Tucci20d441d2018-01-16 09:25:51 +00001326 PERFETTO_LOG("Consumer called ReadBuffers() but tracing was not active");
Primiano Tuccidca727d2018-04-04 11:31:55 +02001327 return;
Primiano Tucci20d441d2018-01-16 09:25:51 +00001328 }
Primiano Tuccidca727d2018-04-04 11:31:55 +02001329 service_->ReadBuffers(tracing_session_id_, this);
Primiano Tucci42e2de12017-12-07 16:46:04 +00001330}
1331
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001332void TracingServiceImpl::ConsumerEndpointImpl::FreeBuffers() {
Florian Mayercd08ec62018-01-31 17:49:25 +00001333 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tuccidca727d2018-04-04 11:31:55 +02001334 if (!tracing_session_id_) {
Primiano Tucci20d441d2018-01-16 09:25:51 +00001335 PERFETTO_LOG("Consumer called FreeBuffers() but tracing was not active");
Primiano Tuccidca727d2018-04-04 11:31:55 +02001336 return;
Primiano Tucci20d441d2018-01-16 09:25:51 +00001337 }
Primiano Tuccidca727d2018-04-04 11:31:55 +02001338 service_->FreeBuffers(tracing_session_id_);
1339 tracing_session_id_ = 0;
Primiano Tucci42e2de12017-12-07 16:46:04 +00001340}
1341
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001342void TracingServiceImpl::ConsumerEndpointImpl::Flush(uint32_t timeout_ms,
1343 FlushCallback callback) {
Primiano Tuccid52e6272018-04-06 19:06:53 +02001344 PERFETTO_DCHECK_THREAD(thread_checker_);
1345 if (!tracing_session_id_) {
1346 PERFETTO_LOG("Consumer called Flush() but tracing was not active");
1347 return;
1348 }
1349 service_->Flush(tracing_session_id_, timeout_ms, callback);
1350}
1351
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001352base::WeakPtr<TracingServiceImpl::ConsumerEndpointImpl>
1353TracingServiceImpl::ConsumerEndpointImpl::GetWeakPtr() {
Florian Mayercd08ec62018-01-31 17:49:25 +00001354 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci42e2de12017-12-07 16:46:04 +00001355 return weak_ptr_factory_.GetWeakPtr();
1356}
1357
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001358////////////////////////////////////////////////////////////////////////////////
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001359// TracingServiceImpl::ProducerEndpointImpl implementation
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001360////////////////////////////////////////////////////////////////////////////////
1361
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001362TracingServiceImpl::ProducerEndpointImpl::ProducerEndpointImpl(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001363 ProducerID id,
Sami Kyostila32e0b542018-02-14 08:55:43 +00001364 uid_t uid,
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001365 TracingServiceImpl* service,
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001366 base::TaskRunner* task_runner,
Isabelle Taylor86262cb2018-03-27 16:00:54 +01001367 Producer* producer,
1368 const std::string& producer_name)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001369 : id_(id),
Sami Kyostila32e0b542018-02-14 08:55:43 +00001370 uid_(uid),
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001371 service_(service),
1372 task_runner_(task_runner),
Isabelle Taylor86262cb2018-03-27 16:00:54 +01001373 producer_(producer),
Primiano Tuccidca727d2018-04-04 11:31:55 +02001374 name_(producer_name),
1375 weak_ptr_factory_(this) {}
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001376
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001377TracingServiceImpl::ProducerEndpointImpl::~ProducerEndpointImpl() {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001378 service_->DisconnectProducer(id_);
Sami Kyostila06487a22018-02-27 13:48:38 +00001379 producer_->OnDisconnect();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001380}
1381
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001382void TracingServiceImpl::ProducerEndpointImpl::RegisterDataSource(
Primiano Tucci9daa4832018-03-28 23:28:17 +01001383 const DataSourceDescriptor& desc) {
Florian Mayercd08ec62018-01-31 17:49:25 +00001384 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci9daa4832018-03-28 23:28:17 +01001385 if (desc.name().empty()) {
Primiano Tucci53589332017-12-19 11:31:13 +01001386 PERFETTO_DLOG("Received RegisterDataSource() with empty name");
Primiano Tucci9daa4832018-03-28 23:28:17 +01001387 return;
Primiano Tucci53589332017-12-19 11:31:13 +01001388 }
Primiano Tucci9daa4832018-03-28 23:28:17 +01001389
1390 service_->RegisterDataSource(id_, desc);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001391}
1392
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001393void TracingServiceImpl::ProducerEndpointImpl::UnregisterDataSource(
Primiano Tucci9daa4832018-03-28 23:28:17 +01001394 const std::string& name) {
Florian Mayercd08ec62018-01-31 17:49:25 +00001395 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci9daa4832018-03-28 23:28:17 +01001396 service_->UnregisterDataSource(id_, name);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001397}
1398
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001399void TracingServiceImpl::ProducerEndpointImpl::CommitData(
Primiano Tucci3e69ed92018-03-14 14:52:29 +00001400 const CommitDataRequest& req_untrusted,
1401 CommitDataCallback callback) {
Florian Mayercd08ec62018-01-31 17:49:25 +00001402 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci79f3f912018-03-02 12:00:31 +00001403
Isabelle Taylor69faa902018-03-21 15:42:03 +00001404 if (!shared_memory_) {
1405 PERFETTO_DLOG(
1406 "Attempted to commit data before the shared memory was allocated.");
1407 return;
1408 }
1409 PERFETTO_DCHECK(shmem_abi_.is_valid());
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001410 for (const auto& entry : req_untrusted.chunks_to_move()) {
1411 const uint32_t page_idx = entry.page();
Primiano Tucci53589332017-12-19 11:31:13 +01001412 if (page_idx >= shmem_abi_.num_pages())
Primiano Tucci79f3f912018-03-02 12:00:31 +00001413 continue; // A buggy or malicious producer.
Primiano Tucci53589332017-12-19 11:31:13 +01001414
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001415 SharedMemoryABI::Chunk chunk =
1416 shmem_abi_.TryAcquireChunkForReading(page_idx, entry.chunk());
1417 if (!chunk.is_valid()) {
1418 PERFETTO_DLOG("Asked to move chunk %d:%d, but it's not complete",
1419 entry.page(), entry.chunk());
Primiano Tucci53589332017-12-19 11:31:13 +01001420 continue;
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001421 }
Primiano Tucci79f3f912018-03-02 12:00:31 +00001422
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001423 // TryAcquireChunkForReading() has load-acquire semantics. Once acquired,
1424 // the ABI contract expects the producer to not touch the chunk anymore
1425 // (until the service marks that as free). This is why all the reads below
1426 // are just memory_order_relaxed. Also, the code here assumes that all this
1427 // data can be malicious and just gives up if anything is malformed.
1428 BufferID buffer_id = static_cast<BufferID>(entry.target_buffer());
1429 const SharedMemoryABI::ChunkHeader& chunk_header = *chunk.header();
1430 WriterID writer_id = chunk_header.writer_id.load(std::memory_order_relaxed);
1431 ChunkID chunk_id = chunk_header.chunk_id.load(std::memory_order_relaxed);
1432 auto packets = chunk_header.packets.load(std::memory_order_relaxed);
1433 uint16_t num_fragments = packets.count;
1434 uint8_t chunk_flags = packets.flags;
Primiano Tucci79f3f912018-03-02 12:00:31 +00001435
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001436 service_->CopyProducerPageIntoLogBuffer(
1437 id_, uid_, writer_id, chunk_id, buffer_id, num_fragments, chunk_flags,
1438 chunk.payload_begin(), chunk.payload_size());
Primiano Tucci53589332017-12-19 11:31:13 +01001439
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001440 // This one has release-store semantics.
1441 shmem_abi_.ReleaseChunkAsFree(std::move(chunk));
1442 } // for(chunks_to_move)
Primiano Tucci53589332017-12-19 11:31:13 +01001443
Primiano Tucciecf9e4a2018-03-14 14:51:58 +00001444 service_->ApplyChunkPatches(id_, req_untrusted.chunks_to_patch());
Primiano Tucci3e69ed92018-03-14 14:52:29 +00001445
Primiano Tuccid52e6272018-04-06 19:06:53 +02001446 if (req_untrusted.flush_request_id()) {
1447 service_->NotifyFlushDoneForProducer(id_, req_untrusted.flush_request_id());
1448 }
1449
Primiano Tucci3e69ed92018-03-14 14:52:29 +00001450 // Keep this invocation last. ProducerIPCService::CommitData() relies on this
1451 // callback being invoked within the same callstack and not posted. If this
1452 // changes, the code there needs to be changed accordingly.
1453 if (callback)
1454 callback();
Primiano Tucci53589332017-12-19 11:31:13 +01001455}
1456
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001457void TracingServiceImpl::ProducerEndpointImpl::SetSharedMemory(
Isabelle Taylor69faa902018-03-21 15:42:03 +00001458 std::unique_ptr<SharedMemory> shared_memory) {
1459 PERFETTO_DCHECK(!shared_memory_ && !shmem_abi_.is_valid());
1460 shared_memory_ = std::move(shared_memory);
1461 shmem_abi_.Initialize(reinterpret_cast<uint8_t*>(shared_memory_->start()),
1462 shared_memory_->size(),
1463 shared_buffer_page_size_kb() * 1024);
1464}
1465
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001466SharedMemory* TracingServiceImpl::ProducerEndpointImpl::shared_memory() const {
Florian Mayercd08ec62018-01-31 17:49:25 +00001467 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci53589332017-12-19 11:31:13 +01001468 return shared_memory_.get();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001469}
1470
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001471size_t TracingServiceImpl::ProducerEndpointImpl::shared_buffer_page_size_kb()
1472 const {
Isabelle Taylor69faa902018-03-21 15:42:03 +00001473 return shared_buffer_page_size_kb_;
1474}
1475
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001476void TracingServiceImpl::ProducerEndpointImpl::TearDownDataSource(
Primiano Tuccidca727d2018-04-04 11:31:55 +02001477 DataSourceInstanceID ds_inst_id) {
1478 // TODO(primiano): When we'll support tearing down the SMB, at this point we
1479 // should send the Producer a TearDownTracing if all its data sources have
1480 // been disabled (see b/77532839 and aosp/655179 PS1).
Primiano Tuccid52e6272018-04-06 19:06:53 +02001481 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tuccidca727d2018-04-04 11:31:55 +02001482 auto weak_this = weak_ptr_factory_.GetWeakPtr();
1483 task_runner_->PostTask([weak_this, ds_inst_id] {
1484 if (weak_this)
1485 weak_this->producer_->TearDownDataSourceInstance(ds_inst_id);
1486 });
1487}
1488
1489SharedMemoryArbiterImpl*
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001490TracingServiceImpl::ProducerEndpointImpl::GetOrCreateShmemArbiter() {
Florian Mayercd08ec62018-01-31 17:49:25 +00001491 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tucci2ffd1a52018-03-27 01:01:30 +01001492 if (!inproc_shmem_arbiter_) {
1493 inproc_shmem_arbiter_.reset(new SharedMemoryArbiterImpl(
1494 shared_memory_->start(), shared_memory_->size(),
1495 shared_buffer_page_size_kb_ * 1024, this, task_runner_));
1496 }
Primiano Tuccidca727d2018-04-04 11:31:55 +02001497 return inproc_shmem_arbiter_.get();
1498}
1499
1500std::unique_ptr<TraceWriter>
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001501TracingServiceImpl::ProducerEndpointImpl::CreateTraceWriter(BufferID buf_id) {
Primiano Tuccidca727d2018-04-04 11:31:55 +02001502 PERFETTO_DCHECK_THREAD(thread_checker_);
1503 return GetOrCreateShmemArbiter()->CreateTraceWriter(buf_id);
1504}
1505
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001506void TracingServiceImpl::ProducerEndpointImpl::OnTracingSetup() {
Primiano Tuccidca727d2018-04-04 11:31:55 +02001507 auto weak_this = weak_ptr_factory_.GetWeakPtr();
1508 task_runner_->PostTask([weak_this] {
1509 if (weak_this)
1510 weak_this->producer_->OnTracingSetup();
1511 });
1512}
1513
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001514void TracingServiceImpl::ProducerEndpointImpl::Flush(
Primiano Tuccid52e6272018-04-06 19:06:53 +02001515 FlushRequestID flush_request_id,
1516 const std::vector<DataSourceInstanceID>& data_sources) {
1517 PERFETTO_DCHECK_THREAD(thread_checker_);
1518 auto weak_this = weak_ptr_factory_.GetWeakPtr();
1519 task_runner_->PostTask([weak_this, flush_request_id, data_sources] {
1520 if (weak_this) {
1521 weak_this->producer_->Flush(flush_request_id, data_sources.data(),
1522 data_sources.size());
1523 }
1524 });
1525}
1526
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001527void TracingServiceImpl::ProducerEndpointImpl::CreateDataSourceInstance(
Primiano Tuccidca727d2018-04-04 11:31:55 +02001528 DataSourceInstanceID ds_id,
1529 const DataSourceConfig& config) {
Primiano Tuccid52e6272018-04-06 19:06:53 +02001530 PERFETTO_DCHECK_THREAD(thread_checker_);
Primiano Tuccidca727d2018-04-04 11:31:55 +02001531 auto weak_this = weak_ptr_factory_.GetWeakPtr();
1532 task_runner_->PostTask([weak_this, ds_id, config] {
1533 if (weak_this)
1534 weak_this->producer_->CreateDataSourceInstance(ds_id, std::move(config));
1535 });
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001536}
1537
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001538void TracingServiceImpl::ProducerEndpointImpl::NotifyFlushComplete(
1539 FlushRequestID id) {
Primiano Tuccid52e6272018-04-06 19:06:53 +02001540 PERFETTO_DCHECK_THREAD(thread_checker_);
1541 return GetOrCreateShmemArbiter()->NotifyFlushComplete(id);
1542}
1543
Primiano Tuccibaeecf12018-07-25 12:02:20 +01001544void TracingServiceImpl::ProducerEndpointImpl::NotifyDataSourceStopped(
1545 DataSourceInstanceID data_source_id) {
1546 PERFETTO_DCHECK_THREAD(thread_checker_);
1547 service_->NotifyDataSourceStopped(id_, data_source_id);
1548}
1549
Primiano Tucci53589332017-12-19 11:31:13 +01001550////////////////////////////////////////////////////////////////////////////////
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001551// TracingServiceImpl::TracingSession implementation
Primiano Tucci20d441d2018-01-16 09:25:51 +00001552////////////////////////////////////////////////////////////////////////////////
1553
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001554TracingServiceImpl::TracingSession::TracingSession(
Primiano Tuccibaeecf12018-07-25 12:02:20 +01001555 TracingSessionID session_id,
Florian Mayer6a1a4d52018-06-08 16:47:07 +01001556 ConsumerEndpointImpl* consumer_ptr,
1557 const TraceConfig& new_config)
Primiano Tuccibaeecf12018-07-25 12:02:20 +01001558 : id(session_id), consumer(consumer_ptr), config(new_config) {}
Primiano Tucci20d441d2018-01-16 09:25:51 +00001559
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001560} // namespace perfetto