Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1 | /* |
| 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 17 | #include "src/tracing/core/tracing_service_impl.h" |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 18 | |
Bruce Dawson | 21c1a0d | 2018-05-18 12:01:48 +0100 | [diff] [blame] | 19 | #include "perfetto/base/build_config.h" |
| 20 | |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 21 | #include <errno.h> |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 22 | #include <inttypes.h> |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 23 | #include <limits.h> |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 24 | #include <string.h> |
Bruce Dawson | 21c1a0d | 2018-05-18 12:01:48 +0100 | [diff] [blame] | 25 | |
| 26 | #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 27 | #include <sys/uio.h> |
| 28 | #include <unistd.h> |
Bruce Dawson | 21c1a0d | 2018-05-18 12:01:48 +0100 | [diff] [blame] | 29 | #endif |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 30 | |
| 31 | #include <algorithm> |
| 32 | |
Primiano Tucci | fe92233 | 2018-03-22 16:15:04 -0700 | [diff] [blame] | 33 | #include "perfetto/base/build_config.h" |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 34 | #include "perfetto/base/task_runner.h" |
Primiano Tucci | 0c45fa3 | 2018-01-30 15:52:30 +0000 | [diff] [blame] | 35 | #include "perfetto/base/utils.h" |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 36 | #include "perfetto/tracing/core/consumer.h" |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 37 | #include "perfetto/tracing/core/data_source_config.h" |
| 38 | #include "perfetto/tracing/core/producer.h" |
| 39 | #include "perfetto/tracing/core/shared_memory.h" |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 40 | #include "perfetto/tracing/core/shared_memory_abi.h" |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 41 | #include "perfetto/tracing/core/trace_packet.h" |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 42 | #include "perfetto/tracing/core/trace_writer.h" |
Sami Kyostila | 32e0b54 | 2018-02-14 08:55:43 +0000 | [diff] [blame] | 43 | #include "src/tracing/core/packet_stream_validator.h" |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 44 | #include "src/tracing/core/shared_memory_arbiter_impl.h" |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 45 | #include "src/tracing/core/trace_buffer.h" |
Sami Kyostila | 32e0b54 | 2018-02-14 08:55:43 +0000 | [diff] [blame] | 46 | |
Sami Kyostila | fbccb3c | 2018-03-21 14:00:47 +0000 | [diff] [blame] | 47 | #include "perfetto/trace/clock_snapshot.pb.h" |
Sami Kyostila | 32e0b54 | 2018-02-14 08:55:43 +0000 | [diff] [blame] | 48 | #include "perfetto/trace/trusted_packet.pb.h" |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 49 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 50 | // 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 Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 55 | namespace perfetto { |
| 56 | |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 57 | namespace { |
Primiano Tucci | 1a1951d | 2018-04-04 21:08:16 +0200 | [diff] [blame] | 58 | constexpr size_t kDefaultShmPageSize = base::kPageSize; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 59 | constexpr int kMaxBuffersPerConsumer = 128; |
Primiano Tucci | 9754d0d | 2018-09-15 12:41:46 +0100 | [diff] [blame^] | 60 | constexpr base::TimeMillis kSnapshotsInterval(10 * 1000); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 61 | constexpr int kDefaultWriteIntoFilePeriodMs = 5000; |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 62 | constexpr int kFlushTimeoutMs = 1000; |
Primiano Tucci | 356d83f | 2018-05-08 14:14:33 +0100 | [diff] [blame] | 63 | constexpr int kMaxConcurrentTracingSessions = 5; |
Florian Mayer | fa71a2f | 2018-02-23 13:07:55 +0000 | [diff] [blame] | 64 | |
| 65 | constexpr uint64_t kMillisPerHour = 3600000; |
| 66 | |
| 67 | // These apply only if enable_extra_guardrails is true. |
| 68 | constexpr uint64_t kMaxTracingDurationMillis = 24 * kMillisPerHour; |
| 69 | constexpr uint64_t kMaxTracingBufferSizeKb = 32 * 1024; |
Bruce Dawson | 21c1a0d | 2018-05-18 12:01:48 +0100 | [diff] [blame] | 70 | |
| 71 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
| 72 | struct iovec { |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 73 | void* iov_base; // Address |
Bruce Dawson | 21c1a0d | 2018-05-18 12:01:48 +0100 | [diff] [blame] | 74 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 80 | ssize_t writev(int fd, const struct iovec* iov, int iovcnt) { |
Bruce Dawson | 21c1a0d | 2018-05-18 12:01:48 +0100 | [diff] [blame] | 81 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 94 | uid_t getuid() { |
| 95 | return 0; |
| 96 | } |
| 97 | uid_t geteuid() { |
| 98 | return 0; |
| 99 | } |
Bruce Dawson | 21c1a0d | 2018-05-18 12:01:48 +0100 | [diff] [blame] | 100 | #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 101 | } // namespace |
| 102 | |
Primiano Tucci | 1a1951d | 2018-04-04 21:08:16 +0200 | [diff] [blame] | 103 | // These constants instead are defined in the header because are used by tests. |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 104 | constexpr size_t TracingServiceImpl::kDefaultShmSize; |
| 105 | constexpr size_t TracingServiceImpl::kMaxShmSize; |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 106 | constexpr uint32_t TracingServiceImpl::kDataSourceStopTimeoutMs; |
Primiano Tucci | 9754d0d | 2018-09-15 12:41:46 +0100 | [diff] [blame^] | 107 | constexpr uint8_t TracingServiceImpl::kSyncMarker[]; |
Primiano Tucci | 1a1951d | 2018-04-04 21:08:16 +0200 | [diff] [blame] | 108 | |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 109 | // static |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 110 | std::unique_ptr<TracingService> TracingService::CreateInstance( |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 111 | std::unique_ptr<SharedMemory::Factory> shm_factory, |
| 112 | base::TaskRunner* task_runner) { |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 113 | return std::unique_ptr<TracingService>( |
| 114 | new TracingServiceImpl(std::move(shm_factory), task_runner)); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 115 | } |
| 116 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 117 | TracingServiceImpl::TracingServiceImpl( |
| 118 | std::unique_ptr<SharedMemory::Factory> shm_factory, |
| 119 | base::TaskRunner* task_runner) |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 120 | : task_runner_(task_runner), |
| 121 | shm_factory_(std::move(shm_factory)), |
Primiano Tucci | 5e33cad | 2018-04-30 14:41:25 +0100 | [diff] [blame] | 122 | uid_(getuid()), |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 123 | buffer_ids_(kMaxTraceBufferID), |
| 124 | weak_ptr_factory_(this) { |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 125 | PERFETTO_DCHECK(task_runner_); |
| 126 | } |
| 127 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 128 | TracingServiceImpl::~TracingServiceImpl() { |
Florian Mayer | aab5355 | 2018-01-24 14:13:55 +0000 | [diff] [blame] | 129 | // TODO(fmayer): handle teardown of all Producer. |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 130 | } |
| 131 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 132 | std::unique_ptr<TracingService::ProducerEndpoint> |
| 133 | TracingServiceImpl::ConnectProducer(Producer* producer, |
| 134 | uid_t uid, |
| 135 | const std::string& producer_name, |
| 136 | size_t shared_memory_size_hint_bytes) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 137 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 081d46a | 2018-02-28 11:09:43 +0000 | [diff] [blame] | 138 | |
Florian Mayer | 61c5548 | 2018-03-06 14:43:54 +0000 | [diff] [blame] | 139 | 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 Tucci | 081d46a | 2018-02-28 11:09:43 +0000 | [diff] [blame] | 145 | 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 Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 151 | |
Isabelle Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 152 | std::unique_ptr<ProducerEndpointImpl> endpoint(new ProducerEndpointImpl( |
| 153 | id, uid, this, task_runner_, producer, producer_name)); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 154 | auto it_and_inserted = producers_.emplace(id, endpoint.get()); |
| 155 | PERFETTO_DCHECK(it_and_inserted.second); |
Primiano Tucci | 1a1951d | 2018-04-04 21:08:16 +0200 | [diff] [blame] | 156 | endpoint->shmem_size_hint_bytes_ = shared_memory_size_hint_bytes; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 157 | task_runner_->PostTask(std::bind(&Producer::OnConnect, endpoint->producer_)); |
Lalit Maganti | 485faff | 2018-03-06 11:51:35 +0000 | [diff] [blame] | 158 | |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 159 | return std::move(endpoint); |
| 160 | } |
| 161 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 162 | void TracingServiceImpl::DisconnectProducer(ProducerID id) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 163 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 081d46a | 2018-02-28 11:09:43 +0000 | [diff] [blame] | 164 | PERFETTO_DLOG("Producer %" PRIu16 " disconnected", id); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 165 | PERFETTO_DCHECK(producers_.count(id)); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 166 | |
| 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 Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 171 | UnregisterDataSource(id, it->second.descriptor.name()); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 172 | it = next; |
| 173 | } |
| 174 | |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 175 | producers_.erase(id); |
Lalit Maganti | 485faff | 2018-03-06 11:51:35 +0000 | [diff] [blame] | 176 | UpdateMemoryGuardrail(); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 177 | } |
| 178 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 179 | TracingServiceImpl::ProducerEndpointImpl* TracingServiceImpl::GetProducer( |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 180 | ProducerID id) const { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 181 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 182 | auto it = producers_.find(id); |
| 183 | if (it == producers_.end()) |
| 184 | return nullptr; |
| 185 | return it->second; |
| 186 | } |
| 187 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 188 | std::unique_ptr<TracingService::ConsumerEndpoint> |
| 189 | TracingServiceImpl::ConnectConsumer(Consumer* consumer) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 190 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 3324dfc | 2017-12-20 14:35:58 +0100 | [diff] [blame] | 191 | PERFETTO_DLOG("Consumer %p connected", reinterpret_cast<void*>(consumer)); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 192 | 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 Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 196 | task_runner_->PostTask(std::bind(&Consumer::OnConnect, endpoint->consumer_)); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 197 | return std::move(endpoint); |
| 198 | } |
| 199 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 200 | void TracingServiceImpl::DisconnectConsumer(ConsumerEndpointImpl* consumer) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 201 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 3324dfc | 2017-12-20 14:35:58 +0100 | [diff] [blame] | 202 | PERFETTO_DLOG("Consumer %p disconnected", reinterpret_cast<void*>(consumer)); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 203 | PERFETTO_DCHECK(consumers_.count(consumer)); |
Hector Dearman | 69a6479 | 2018-01-11 18:35:02 +0000 | [diff] [blame] | 204 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 205 | // 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 Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 209 | consumers_.erase(consumer); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 210 | |
| 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 Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 219 | } |
| 220 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 221 | bool TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer, |
| 222 | const TraceConfig& cfg, |
| 223 | base::ScopedFile fd) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 224 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 3324dfc | 2017-12-20 14:35:58 +0100 | [diff] [blame] | 225 | PERFETTO_DLOG("Enabling tracing for consumer %p", |
| 226 | reinterpret_cast<void*>(consumer)); |
Florian Mayer | 61c5548 | 2018-03-06 14:43:54 +0000 | [diff] [blame] | 227 | 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 Tucci | 5317b5c | 2018-03-13 13:55:40 +0000 | [diff] [blame] | 231 | TracingSession* tracing_session = |
| 232 | GetTracingSession(consumer->tracing_session_id_); |
| 233 | if (tracing_session) { |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 234 | PERFETTO_DLOG( |
| 235 | "A Consumer is trying to EnableTracing() but another tracing session " |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 236 | "is already active (forgot a call to FreeBuffers() ?)"); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 237 | return false; |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 238 | } |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 239 | |
Florian Mayer | fa71a2f | 2018-02-23 13:07:55 +0000 | [diff] [blame] | 240 | 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 245 | return false; |
Florian Mayer | fa71a2f | 2018-02-23 13:07:55 +0000 | [diff] [blame] | 246 | } |
| 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 254 | return false; |
Florian Mayer | fa71a2f | 2018-02-23 13:07:55 +0000 | [diff] [blame] | 255 | } |
| 256 | } |
| 257 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 258 | if (cfg.buffers_size() > kMaxBuffersPerConsumer) { |
| 259 | PERFETTO_DLOG("Too many buffers configured (%d)", cfg.buffers_size()); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 260 | return false; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 261 | } |
| 262 | |
Primiano Tucci | 0c45fa3 | 2018-01-30 15:52:30 +0000 | [diff] [blame] | 263 | // 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 Tucci | 356d83f | 2018-05-08 14:14:33 +0100 | [diff] [blame] | 265 | // 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 Tucci | 0c45fa3 | 2018-01-30 15:52:30 +0000 | [diff] [blame] | 272 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 273 | const TracingSessionID tsid = ++last_tracing_session_id_; |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 274 | tracing_session = |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 275 | &tracing_sessions_.emplace(tsid, TracingSession(tsid, consumer, cfg)) |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 276 | .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 Tucci | 9754d0d | 2018-09-15 12:41:46 +0100 | [diff] [blame^] | 288 | if (write_period_ms < min_write_period_ms_) |
| 289 | write_period_ms = min_write_period_ms_; |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 290 | 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 Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 294 | |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 295 | // Initialize the log buffers. |
| 296 | bool did_allocate_all_buffers = true; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 297 | |
| 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 Tucci | b7cca20 | 2018-01-29 16:30:47 +0000 | [diff] [blame] | 302 | size_t total_buf_size_kb = 0; |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 303 | 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 Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 306 | const TraceConfig::BufferConfig& buffer_cfg = cfg.buffers()[i]; |
| 307 | BufferID global_id = buffer_ids_.Allocate(); |
| 308 | if (!global_id) { |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 309 | did_allocate_all_buffers = false; // We ran out of IDs. |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 310 | break; |
| 311 | } |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 312 | tracing_session->buffers_index.push_back(global_id); |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 313 | const size_t buf_size_bytes = buffer_cfg.size_kb() * 1024u; |
Primiano Tucci | b7cca20 | 2018-01-29 16:30:47 +0000 | [diff] [blame] | 314 | total_buf_size_kb += buffer_cfg.size_kb(); |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 315 | auto it_and_inserted = |
Hector Dearman | 6214c8f | 2018-03-27 16:16:22 +0100 | [diff] [blame] | 316 | buffers_.emplace(global_id, TraceBuffer::Create(buf_size_bytes)); |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 317 | PERFETTO_DCHECK(it_and_inserted.second); // buffers_.count(global_id) == 0. |
Hector Dearman | 6214c8f | 2018-03-27 16:16:22 +0100 | [diff] [blame] | 318 | std::unique_ptr<TraceBuffer>& trace_buffer = it_and_inserted.first->second; |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 319 | if (!trace_buffer) { |
Primiano Tucci | bbaa58c | 2017-12-20 13:48:20 +0100 | [diff] [blame] | 320 | did_allocate_all_buffers = false; |
| 321 | break; |
| 322 | } |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 323 | } |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 324 | |
Lalit Maganti | 485faff | 2018-03-06 11:51:35 +0000 | [diff] [blame] | 325 | UpdateMemoryGuardrail(); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 326 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 327 | // 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 Mayer | aab5355 | 2018-01-24 14:13:55 +0000 | [diff] [blame] | 331 | // TODO(fmayer): add a test to cover this case, this is quite subtle. |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 332 | if (!did_allocate_all_buffers) { |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 333 | for (BufferID global_id : tracing_session->buffers_index) { |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 334 | buffer_ids_.Free(global_id); |
| 335 | buffers_.erase(global_id); |
| 336 | } |
| 337 | tracing_sessions_.erase(tsid); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 338 | return false; |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 339 | } |
| 340 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 341 | consumer->tracing_session_id_ = tsid; |
| 342 | |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 343 | // 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 Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 347 | 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 Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 359 | } |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 360 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 361 | // Trigger delayed task if the trace is time limited. |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 362 | const uint32_t trace_duration_ms = cfg.duration_ms(); |
| 363 | if (trace_duration_ms > 0) { |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 364 | auto weak_this = weak_ptr_factory_.GetWeakPtr(); |
| 365 | task_runner_->PostDelayedTask( |
| 366 | [weak_this, tsid] { |
| 367 | if (weak_this) |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 368 | weak_this->FlushAndDisableTracing(tsid); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 369 | }, |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 370 | trace_duration_ms); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 371 | } |
Primiano Tucci | b7cca20 | 2018-01-29 16:30:47 +0000 | [diff] [blame] | 372 | |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 373 | // 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 Kyostila | 01c45f0 | 2018-03-29 15:43:10 +0100 | [diff] [blame] | 381 | tracing_session->delay_to_next_write_period_ms()); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 382 | } |
| 383 | |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 384 | tracing_session->pending_stop_acks.clear(); |
| 385 | tracing_session->state = TracingSession::ENABLED; |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 386 | 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 391 | return true; |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 392 | } |
| 393 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 394 | // 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 Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 398 | void TracingServiceImpl::DisableTracing(TracingSessionID tsid, |
| 399 | bool disable_immediately) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 400 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 401 | TracingSession* tracing_session = GetTracingSession(tsid); |
| 402 | if (!tracing_session) { |
| 403 | // Can happen if the consumer calls this before EnableTracing() or after |
| 404 | // FreeBuffers(). |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 405 | PERFETTO_DLOG("DisableTracing() failed, invalid session ID %" PRIu64, tsid); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 406 | return; |
| 407 | } |
Primiano Tucci | b7cca20 | 2018-01-29 16:30:47 +0000 | [diff] [blame] | 408 | |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 409 | 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 Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 436 | for (const auto& data_source_inst : tracing_session->data_source_instances) { |
| 437 | const ProducerID producer_id = data_source_inst.first; |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 438 | const DataSourceInstanceID ds_inst_id = data_source_inst.second.instance_id; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 439 | ProducerEndpointImpl* producer = GetProducer(producer_id); |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 440 | 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 Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 444 | producer->TearDownDataSource(ds_inst_id); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 445 | } |
| 446 | tracing_session->data_source_instances.clear(); |
| 447 | |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 448 | // 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 454 | |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 455 | 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 466 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 467 | // Deliberately NOT removing the session from |tracing_session_|, it's still |
| 468 | // needed to call ReadBuffers(). FreeBuffers() will erase() the session. |
| 469 | } |
| 470 | |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 471 | void 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. |
| 496 | void 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 | |
| 509 | void 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 523 | void TracingServiceImpl::Flush(TracingSessionID tsid, |
| 524 | uint32_t timeout_ms, |
| 525 | ConsumerEndpoint::FlushCallback callback) { |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 526 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 574 | void TracingServiceImpl::NotifyFlushDoneForProducer( |
| 575 | ProducerID producer_id, |
| 576 | FlushRequestID flush_request_id) { |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 577 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 595 | void TracingServiceImpl::OnFlushTimeout(TracingSessionID tsid, |
| 596 | FlushRequestID flush_request_id) { |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 597 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 608 | void TracingServiceImpl::FlushAndDisableTracing(TracingSessionID tsid) { |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 609 | 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 619 | // 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 622 | void TracingServiceImpl::ReadBuffers(TracingSessionID tsid, |
| 623 | ConsumerEndpointImpl* consumer) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 624 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 625 | TracingSession* tracing_session = GetTracingSession(tsid); |
| 626 | if (!tracing_session) { |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 627 | // 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 Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 632 | return; // TODO(primiano): signal failure? |
| 633 | } |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 634 | |
| 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 Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 648 | std::vector<TracePacket> packets; |
Primiano Tucci | 5e33cad | 2018-04-30 14:41:25 +0100 | [diff] [blame] | 649 | packets.reserve(1024); // Just an educated guess to avoid trivial expansions. |
Primiano Tucci | 9754d0d | 2018-09-15 12:41:46 +0100 | [diff] [blame^] | 650 | |
| 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 Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 658 | MaybeEmitTraceConfig(tracing_session, &packets); |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 659 | |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 660 | 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 Tucci | d61b85f | 2018-03-29 02:56:10 +0100 | [diff] [blame] | 669 | // 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 Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 681 | 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 Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 687 | 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 Dearman | 6214c8f | 2018-03-27 16:16:22 +0100 | [diff] [blame] | 693 | TraceBuffer& tbuf = *tbuf_iter->second; |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 694 | tbuf.BeginRead(); |
| 695 | while (!did_hit_threshold) { |
| 696 | TracePacket packet; |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 697 | uid_t producer_uid = kInvalidUid; |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 698 | if (!tbuf.ReadNextTracePacket(&packet, &producer_uid)) |
| 699 | break; |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 700 | PERFETTO_DCHECK(producer_uid != kInvalidUid); |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 701 | PERFETTO_DCHECK(packet.size() > 0); |
| 702 | if (!PacketStreamValidator::Validate(packet.slices())) { |
| 703 | PERFETTO_DLOG("Dropping invalid packet"); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 704 | continue; |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 705 | } |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 706 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 707 | // 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 716 | trusted_packet.set_trusted_uid(static_cast<int32_t>(producer_uid)); |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 717 | 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 Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 724 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 725 | // Append the packet (inclusive of the trusted uid) to |packets|. |
| 726 | packets_bytes += packet.size(); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 727 | total_slices += packet.slices().size(); |
Primiano Tucci | d61b85f | 2018-03-29 02:56:10 +0100 | [diff] [blame] | 728 | did_hit_threshold = packets_bytes >= kApproxBytesPerTask && |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 729 | !tracing_session->write_into_file; |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 730 | packets.emplace_back(std::move(packet)); |
| 731 | } // for(packets...) |
| 732 | } // for(buffers...) |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 733 | |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 734 | // 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 738 | 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 Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 741 | |
| 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 751 | uint64_t bytes_about_to_be_written = 0; |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 752 | 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 779 | uint64_t total_wr_size = 0; |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 780 | |
| 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 784 | int iov_batch_size = static_cast<int>(std::min(num_iovecs - i, kIOVMax)); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 785 | 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 791 | total_wr_size += static_cast<size_t>(wr_size); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 792 | } |
| 793 | |
| 794 | tracing_session->bytes_written_into_file += total_wr_size; |
| 795 | |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 796 | PERFETTO_DLOG("Draining into file, written: %" PRIu64 " KB, stop: %d", |
| 797 | (total_wr_size + 1023) / 1024, stop_writing_into_file); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 798 | if (stop_writing_into_file) { |
| 799 | tracing_session->write_into_file.reset(); |
| 800 | tracing_session->write_period_ms = 0; |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 801 | if (tracing_session->state == TracingSession::ENABLED) |
| 802 | DisableTracing(tsid); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 803 | 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 Kyostila | 01c45f0 | 2018-03-29 15:43:10 +0100 | [diff] [blame] | 812 | tracing_session->delay_to_next_write_period_ms()); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 813 | return; |
| 814 | } // if (tracing_session->write_into_file) |
| 815 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 816 | 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 Kyostila | 32e0b54 | 2018-02-14 08:55:43 +0000 | [diff] [blame] | 826 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 827 | // Keep this as tail call, just in case the consumer re-enters. |
| 828 | consumer->consumer_->OnTraceData(std::move(packets), has_more); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 829 | } |
| 830 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 831 | void TracingServiceImpl::FreeBuffers(TracingSessionID tsid) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 832 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 833 | PERFETTO_DLOG("Freeing buffers for session %" PRIu64, tsid); |
| 834 | TracingSession* tracing_session = GetTracingSession(tsid); |
| 835 | if (!tracing_session) { |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 836 | PERFETTO_DLOG("FreeBuffers() failed, invalid session ID %" PRIu64, tsid); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 837 | return; // TODO(primiano): signal failure? |
| 838 | } |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 839 | DisableTracing(tsid, /*disable_immediately=*/true); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 840 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 841 | 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 Maganti | 485faff | 2018-03-06 11:51:35 +0000 | [diff] [blame] | 847 | UpdateMemoryGuardrail(); |
| 848 | |
Primiano Tucci | b7cca20 | 2018-01-29 16:30:47 +0000 | [diff] [blame] | 849 | PERFETTO_LOG("Tracing session %" PRIu64 " ended, total sessions:%zu", tsid, |
| 850 | tracing_sessions_.size()); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 851 | } |
| 852 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 853 | void TracingServiceImpl::RegisterDataSource(ProducerID producer_id, |
| 854 | const DataSourceDescriptor& desc) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 855 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 856 | PERFETTO_DLOG("Producer %" PRIu16 " registered data source \"%s\"", |
| 857 | producer_id, desc.name().c_str()); |
Primiano Tucci | 3324dfc | 2017-12-20 14:35:58 +0100 | [diff] [blame] | 858 | |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 859 | PERFETTO_DCHECK(!desc.name().empty()); |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 860 | auto reg_ds = data_sources_.emplace(desc.name(), |
| 861 | RegisteredDataSource{producer_id, desc}); |
Oystein Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 862 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 863 | // If there are existing tracing sessions, we need to check if the new |
Oystein Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 864 | // data source is enabled by any of them. |
| 865 | if (tracing_sessions_.empty()) |
| 866 | return; |
| 867 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 868 | ProducerEndpointImpl* producer = GetProducer(producer_id); |
| 869 | if (!producer) { |
Oystein Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 870 | PERFETTO_DCHECK(false); |
| 871 | return; |
| 872 | } |
| 873 | |
Oystein Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 874 | for (auto& iter : tracing_sessions_) { |
| 875 | TracingSession& tracing_session = iter.second; |
Oystein Eftevaag | f250e1c | 2018-08-23 16:10:52 -0700 | [diff] [blame] | 876 | if (tracing_session.state != TracingSession::ENABLED) |
| 877 | continue; |
| 878 | |
Isabelle Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 879 | 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 Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 886 | for (const TraceConfig::DataSource& cfg_data_source : |
| 887 | tracing_session.config.data_sources()) { |
| 888 | if (cfg_data_source.config().name() == desc.name()) |
Isabelle Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 889 | CreateDataSourceInstance(cfg_data_source, producer_config, |
| 890 | reg_ds->second, &tracing_session); |
Oystein Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 891 | } |
| 892 | } |
| 893 | } |
| 894 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 895 | void TracingServiceImpl::UnregisterDataSource(ProducerID producer_id, |
| 896 | const std::string& name) { |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 897 | PERFETTO_DCHECK_THREAD(thread_checker_); |
| 898 | PERFETTO_CHECK(producer_id); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 899 | ProducerEndpointImpl* producer = GetProducer(producer_id); |
| 900 | PERFETTO_DCHECK(producer); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 901 | 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 Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 904 | if (it->first == producer_id && it->second.data_source_name == name) { |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 905 | DataSourceInstanceID ds_inst_id = it->second.instance_id; |
| 906 | producer->TearDownDataSource(ds_inst_id); |
| 907 | it = ds_instances.erase(it); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 908 | } else { |
| 909 | ++it; |
| 910 | } |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 911 | } // for (data_source_instances) |
| 912 | } // for (tracing_session) |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 913 | |
| 914 | for (auto it = data_sources_.begin(); it != data_sources_.end(); ++it) { |
| 915 | if (it->second.producer_id == producer_id && |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 916 | it->second.descriptor.name() == name) { |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 917 | data_sources_.erase(it); |
| 918 | return; |
| 919 | } |
| 920 | } |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 921 | |
| 922 | PERFETTO_DLOG( |
| 923 | "Tried to unregister a non-existent data source \"%s\" for " |
| 924 | "producer %" PRIu16, |
| 925 | name.c_str(), producer_id); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 926 | PERFETTO_DCHECK(false); |
| 927 | } |
| 928 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 929 | void TracingServiceImpl::CreateDataSourceInstance( |
Oystein Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 930 | const TraceConfig::DataSource& cfg_data_source, |
Isabelle Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 931 | const TraceConfig::ProducerConfig& producer_config, |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 932 | const RegisteredDataSource& data_source, |
Oystein Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 933 | TracingSession* tracing_session) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 934 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 935 | ProducerEndpointImpl* producer = GetProducer(data_source.producer_id); |
| 936 | PERFETTO_DCHECK(producer); |
Florian Mayer | 61c5548 | 2018-03-06 14:43:54 +0000 | [diff] [blame] | 937 | // An existing producer that is not ftrace could have registered itself as |
| 938 | // ftrace, we must not enable it in that case. |
Primiano Tucci | 5e33cad | 2018-04-30 14:41:25 +0100 | [diff] [blame] | 939 | if (lockdown_mode_ && producer->uid_ != uid_) { |
Florian Mayer | 61c5548 | 2018-03-06 14:43:54 +0000 | [diff] [blame] | 940 | PERFETTO_DLOG("Lockdown mode: not enabling producer %hu", producer->id_); |
| 941 | return; |
| 942 | } |
Isabelle Taylor | 02f46be | 2018-03-29 10:34:08 +0100 | [diff] [blame] | 943 | // 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 Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 956 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 957 | // 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 Mayer | eef8b24 | 2018-02-20 10:21:20 +0000 | [diff] [blame] | 965 | ds_config.set_trace_duration_ms(tracing_session->config.duration_ms()); |
Primiano Tucci | 03de28f | 2018-08-01 11:29:46 +0100 | [diff] [blame] | 966 | ds_config.set_tracing_session_id(tracing_session->id); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 967 | auto relative_buffer_id = ds_config.target_buffer(); |
| 968 | if (relative_buffer_id >= tracing_session->num_buffers()) { |
| 969 | PERFETTO_LOG( |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 970 | "The TraceConfig for DataSource %s specified a target_buffer out of " |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 971 | "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 Eftevaag | 1269b4a | 2018-01-10 16:29:38 -0800 | [diff] [blame] | 979 | DataSourceInstanceID inst_id = ++last_data_source_instance_id_; |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 980 | tracing_session->data_source_instances.emplace( |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 981 | producer->id_, |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 982 | DataSourceInstance{inst_id, data_source.descriptor.name(), |
| 983 | data_source.descriptor.will_notify_on_stop()}); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 984 | PERFETTO_DLOG("Starting data source %s with target buffer %" PRIu16, |
| 985 | ds_config.name().c_str(), global_id); |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 986 | if (!producer->shared_memory()) { |
Primiano Tucci | 1a1951d | 2018-04-04 21:08:16 +0200 | [diff] [blame] | 987 | // 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 Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 993 | |
Primiano Tucci | 1a1951d | 2018-04-04 21:08:16 +0200 | [diff] [blame] | 994 | // 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 Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 1004 | 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 Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1011 | producer->OnTracingSetup(); |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 1012 | UpdateMemoryGuardrail(); |
| 1013 | } |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1014 | producer->CreateDataSourceInstance(inst_id, ds_config); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1015 | } |
| 1016 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1017 | // 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1020 | void 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 Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1030 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Hector Dearman | 6214c8f | 2018-03-27 16:16:22 +0100 | [diff] [blame] | 1031 | TraceBuffer* buf = GetBufferByID(buffer_id); |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1032 | if (!buf) { |
| 1033 | PERFETTO_DLOG("Could not find target buffer %" PRIu16 |
| 1034 | " for producer %" PRIu16, |
| 1035 | buffer_id, producer_id_trusted); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1036 | return; |
| 1037 | } |
| 1038 | |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1039 | // 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 Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1045 | buf->CopyChunkUntrusted(producer_id_trusted, producer_uid_trusted, writer_id, |
| 1046 | chunk_id, num_fragments, chunk_flags, src, size); |
| 1047 | } |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1048 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1049 | void TracingServiceImpl::ApplyChunkPatches( |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1050 | 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 Dearman | 6214c8f | 2018-03-27 16:16:22 +0100 | [diff] [blame] | 1057 | TraceBuffer* buf = |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1058 | 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 Dearman | 6214c8f | 2018-03-27 16:16:22 +0100 | [diff] [blame] | 1070 | std::array<TraceBuffer::Patch, 1024> patches; // Uninitialized. |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1071 | 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 Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1094 | } |
| 1095 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1096 | TracingServiceImpl::TracingSession* TracingServiceImpl::GetTracingSession( |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1097 | TracingSessionID tsid) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1098 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1099 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1105 | ProducerID TracingServiceImpl::GetNextProducerID() { |
Primiano Tucci | 081d46a | 2018-02-28 11:09:43 +0000 | [diff] [blame] | 1106 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1115 | TraceBuffer* TracingServiceImpl::GetBufferByID(BufferID buffer_id) { |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1116 | auto buf_iter = buffers_.find(buffer_id); |
| 1117 | if (buf_iter == buffers_.end()) |
| 1118 | return nullptr; |
| 1119 | return &*buf_iter->second; |
| 1120 | } |
| 1121 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1122 | void TracingServiceImpl::UpdateMemoryGuardrail() { |
Primiano Tucci | 09db827 | 2018-03-08 17:47:47 +0000 | [diff] [blame] | 1123 | #if !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD) && \ |
| 1124 | !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) |
Lalit Maganti | 485faff | 2018-03-06 11:51:35 +0000 | [diff] [blame] | 1125 | uint64_t total_buffer_bytes = 0; |
| 1126 | |
| 1127 | // Sum up all the shared memory buffers. |
| 1128 | for (const auto& id_to_producer : producers_) { |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 1129 | if (id_to_producer.second->shared_memory()) |
| 1130 | total_buffer_bytes += id_to_producer.second->shared_memory()->size(); |
Lalit Maganti | 485faff | 2018-03-06 11:51:35 +0000 | [diff] [blame] | 1131 | } |
| 1132 | |
| 1133 | // Sum up all the trace buffers. |
| 1134 | for (const auto& id_to_buffer : buffers_) { |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1135 | total_buffer_bytes += id_to_buffer.second->size(); |
Lalit Maganti | 485faff | 2018-03-06 11:51:35 +0000 | [diff] [blame] | 1136 | } |
| 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 Tucci | 9754d0d | 2018-09-15 12:41:46 +0100 | [diff] [blame^] | 1145 | void 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 Eftevaag | 4966fdc | 2018-03-28 10:20:59 -0700 | [diff] [blame] | 1159 | |
Primiano Tucci | 9754d0d | 2018-09-15 12:41:46 +0100 | [diff] [blame^] | 1160 | 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 | |
| 1170 | void TracingServiceImpl::SnapshotClocks(std::vector<TracePacket>* packets) { |
Primiano Tucci | 07e104d | 2018-04-03 20:45:35 +0200 | [diff] [blame] | 1171 | protos::TrustedPacket packet; |
Oystein Eftevaag | 4966fdc | 2018-03-28 10:20:59 -0700 | [diff] [blame] | 1172 | protos::ClockSnapshot* clock_snapshot = packet.mutable_clock_snapshot(); |
| 1173 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1174 | #if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) && \ |
| 1175 | !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
Sami Kyostila | fbccb3c | 2018-03-21 14:00:47 +0000 | [diff] [blame] | 1176 | struct { |
| 1177 | clockid_t id; |
| 1178 | protos::ClockSnapshot::Clock::Type type; |
| 1179 | struct timespec ts; |
| 1180 | } clocks[] = { |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 1181 | {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 Kyostila | fbccb3c | 2018-03-21 14:00:47 +0000 | [diff] [blame] | 1199 | }; |
Sami Kyostila | fbccb3c | 2018-03-21 14:00:47 +0000 | [diff] [blame] | 1200 | // 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 1208 | c->set_timestamp( |
| 1209 | static_cast<uint64_t>(base::FromPosixTimespec(clock.ts).count())); |
Sami Kyostila | fbccb3c | 2018-03-21 14:00:47 +0000 | [diff] [blame] | 1210 | } |
Oystein Eftevaag | 4966fdc | 2018-03-28 10:20:59 -0700 | [diff] [blame] | 1211 | #else // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) |
| 1212 | protos::ClockSnapshot::Clock* c = clock_snapshot->add_clocks(); |
| 1213 | c->set_type(protos::ClockSnapshot::Clock::MONOTONIC); |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 1214 | c->set_timestamp(static_cast<uint64_t>(base::GetWallTimeNs().count())); |
Oystein Eftevaag | 4966fdc | 2018-03-28 10:20:59 -0700 | [diff] [blame] | 1215 | #endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) |
| 1216 | |
Primiano Tucci | 5e33cad | 2018-04-30 14:41:25 +0100 | [diff] [blame] | 1217 | 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 Tucci | 9754d0d | 2018-09-15 12:41:46 +0100 | [diff] [blame^] | 1224 | void TracingServiceImpl::SnapshotStats(TracingSession* tracing_session, |
| 1225 | std::vector<TracePacket>* packets) { |
Primiano Tucci | 5e33cad | 2018-04-30 14:41:25 +0100 | [diff] [blame] | 1226 | 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 Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 1258 | Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize())); |
Sami Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 1259 | PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data())); |
| 1260 | packets->emplace_back(); |
| 1261 | packets->back().AddSlice(std::move(slice)); |
| 1262 | } |
| 1263 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1264 | void TracingServiceImpl::MaybeEmitTraceConfig( |
| 1265 | TracingSession* tracing_session, |
| 1266 | std::vector<TracePacket>* packets) { |
Sami Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 1267 | if (tracing_session->did_emit_config) |
| 1268 | return; |
| 1269 | tracing_session->did_emit_config = true; |
Primiano Tucci | 07e104d | 2018-04-03 20:45:35 +0200 | [diff] [blame] | 1270 | protos::TrustedPacket packet; |
Sami Kyostila | 200bd2e | 2018-03-26 12:24:10 +0100 | [diff] [blame] | 1271 | tracing_session->config.ToProto(packet.mutable_trace_config()); |
Primiano Tucci | 5e33cad | 2018-04-30 14:41:25 +0100 | [diff] [blame] | 1272 | packet.set_trusted_uid(static_cast<int32_t>(uid_)); |
Primiano Tucci | 3cbb10a | 2018-04-10 17:52:40 +0100 | [diff] [blame] | 1273 | Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize())); |
Sami Kyostila | fbccb3c | 2018-03-21 14:00:47 +0000 | [diff] [blame] | 1274 | PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data())); |
| 1275 | packets->emplace_back(); |
| 1276 | packets->back().AddSlice(std::move(slice)); |
| 1277 | } |
| 1278 | |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1279 | //////////////////////////////////////////////////////////////////////////////// |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1280 | // TracingServiceImpl::ConsumerEndpointImpl implementation |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1281 | //////////////////////////////////////////////////////////////////////////////// |
| 1282 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1283 | TracingServiceImpl::ConsumerEndpointImpl::ConsumerEndpointImpl( |
| 1284 | TracingServiceImpl* service, |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 1285 | base::TaskRunner* task_runner, |
| 1286 | Consumer* consumer) |
| 1287 | : task_runner_(task_runner), |
| 1288 | service_(service), |
| 1289 | consumer_(consumer), |
| 1290 | weak_ptr_factory_(this) {} |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1291 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1292 | TracingServiceImpl::ConsumerEndpointImpl::~ConsumerEndpointImpl() { |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1293 | service_->DisconnectConsumer(this); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 1294 | consumer_->OnDisconnect(); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1295 | } |
| 1296 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1297 | void TracingServiceImpl::ConsumerEndpointImpl::NotifyOnTracingDisabled() { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1298 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 1299 | auto weak_this = GetWeakPtr(); |
| 1300 | task_runner_->PostTask([weak_this] { |
| 1301 | if (weak_this) |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1302 | weak_this->consumer_->OnTracingDisabled(); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 1303 | }); |
| 1304 | } |
| 1305 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1306 | void TracingServiceImpl::ConsumerEndpointImpl::EnableTracing( |
| 1307 | const TraceConfig& cfg, |
| 1308 | base::ScopedFile fd) { |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 1309 | PERFETTO_DCHECK_THREAD(thread_checker_); |
| 1310 | if (!service_->EnableTracing(this, cfg, std::move(fd))) |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1311 | NotifyOnTracingDisabled(); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1312 | } |
| 1313 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1314 | void TracingServiceImpl::ConsumerEndpointImpl::DisableTracing() { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1315 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1316 | if (!tracing_session_id_) { |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1317 | PERFETTO_LOG("Consumer called DisableTracing() but tracing was not active"); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1318 | return; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1319 | } |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1320 | service_->DisableTracing(tracing_session_id_); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1321 | } |
| 1322 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1323 | void TracingServiceImpl::ConsumerEndpointImpl::ReadBuffers() { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1324 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1325 | if (!tracing_session_id_) { |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1326 | PERFETTO_LOG("Consumer called ReadBuffers() but tracing was not active"); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1327 | return; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1328 | } |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1329 | service_->ReadBuffers(tracing_session_id_, this); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1330 | } |
| 1331 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1332 | void TracingServiceImpl::ConsumerEndpointImpl::FreeBuffers() { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1333 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1334 | if (!tracing_session_id_) { |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1335 | PERFETTO_LOG("Consumer called FreeBuffers() but tracing was not active"); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1336 | return; |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1337 | } |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1338 | service_->FreeBuffers(tracing_session_id_); |
| 1339 | tracing_session_id_ = 0; |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1340 | } |
| 1341 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1342 | void TracingServiceImpl::ConsumerEndpointImpl::Flush(uint32_t timeout_ms, |
| 1343 | FlushCallback callback) { |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 1344 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1352 | base::WeakPtr<TracingServiceImpl::ConsumerEndpointImpl> |
| 1353 | TracingServiceImpl::ConsumerEndpointImpl::GetWeakPtr() { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1354 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 42e2de1 | 2017-12-07 16:46:04 +0000 | [diff] [blame] | 1355 | return weak_ptr_factory_.GetWeakPtr(); |
| 1356 | } |
| 1357 | |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1358 | //////////////////////////////////////////////////////////////////////////////// |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1359 | // TracingServiceImpl::ProducerEndpointImpl implementation |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1360 | //////////////////////////////////////////////////////////////////////////////// |
| 1361 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1362 | TracingServiceImpl::ProducerEndpointImpl::ProducerEndpointImpl( |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1363 | ProducerID id, |
Sami Kyostila | 32e0b54 | 2018-02-14 08:55:43 +0000 | [diff] [blame] | 1364 | uid_t uid, |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1365 | TracingServiceImpl* service, |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1366 | base::TaskRunner* task_runner, |
Isabelle Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 1367 | Producer* producer, |
| 1368 | const std::string& producer_name) |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1369 | : id_(id), |
Sami Kyostila | 32e0b54 | 2018-02-14 08:55:43 +0000 | [diff] [blame] | 1370 | uid_(uid), |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1371 | service_(service), |
| 1372 | task_runner_(task_runner), |
Isabelle Taylor | 86262cb | 2018-03-27 16:00:54 +0100 | [diff] [blame] | 1373 | producer_(producer), |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1374 | name_(producer_name), |
| 1375 | weak_ptr_factory_(this) {} |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1376 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1377 | TracingServiceImpl::ProducerEndpointImpl::~ProducerEndpointImpl() { |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1378 | service_->DisconnectProducer(id_); |
Sami Kyostila | 06487a2 | 2018-02-27 13:48:38 +0000 | [diff] [blame] | 1379 | producer_->OnDisconnect(); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1380 | } |
| 1381 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1382 | void TracingServiceImpl::ProducerEndpointImpl::RegisterDataSource( |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 1383 | const DataSourceDescriptor& desc) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1384 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 1385 | if (desc.name().empty()) { |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1386 | PERFETTO_DLOG("Received RegisterDataSource() with empty name"); |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 1387 | return; |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1388 | } |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 1389 | |
| 1390 | service_->RegisterDataSource(id_, desc); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1391 | } |
| 1392 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1393 | void TracingServiceImpl::ProducerEndpointImpl::UnregisterDataSource( |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 1394 | const std::string& name) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1395 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 9daa483 | 2018-03-28 23:28:17 +0100 | [diff] [blame] | 1396 | service_->UnregisterDataSource(id_, name); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1397 | } |
| 1398 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1399 | void TracingServiceImpl::ProducerEndpointImpl::CommitData( |
Primiano Tucci | 3e69ed9 | 2018-03-14 14:52:29 +0000 | [diff] [blame] | 1400 | const CommitDataRequest& req_untrusted, |
| 1401 | CommitDataCallback callback) { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1402 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 79f3f91 | 2018-03-02 12:00:31 +0000 | [diff] [blame] | 1403 | |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 1404 | 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 Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1410 | for (const auto& entry : req_untrusted.chunks_to_move()) { |
| 1411 | const uint32_t page_idx = entry.page(); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1412 | if (page_idx >= shmem_abi_.num_pages()) |
Primiano Tucci | 79f3f91 | 2018-03-02 12:00:31 +0000 | [diff] [blame] | 1413 | continue; // A buggy or malicious producer. |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1414 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1415 | 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 Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1420 | continue; |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1421 | } |
Primiano Tucci | 79f3f91 | 2018-03-02 12:00:31 +0000 | [diff] [blame] | 1422 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1423 | // 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 Tucci | 79f3f91 | 2018-03-02 12:00:31 +0000 | [diff] [blame] | 1435 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1436 | service_->CopyProducerPageIntoLogBuffer( |
| 1437 | id_, uid_, writer_id, chunk_id, buffer_id, num_fragments, chunk_flags, |
| 1438 | chunk.payload_begin(), chunk.payload_size()); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1439 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1440 | // This one has release-store semantics. |
| 1441 | shmem_abi_.ReleaseChunkAsFree(std::move(chunk)); |
| 1442 | } // for(chunks_to_move) |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1443 | |
Primiano Tucci | ecf9e4a | 2018-03-14 14:51:58 +0000 | [diff] [blame] | 1444 | service_->ApplyChunkPatches(id_, req_untrusted.chunks_to_patch()); |
Primiano Tucci | 3e69ed9 | 2018-03-14 14:52:29 +0000 | [diff] [blame] | 1445 | |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 1446 | if (req_untrusted.flush_request_id()) { |
| 1447 | service_->NotifyFlushDoneForProducer(id_, req_untrusted.flush_request_id()); |
| 1448 | } |
| 1449 | |
Primiano Tucci | 3e69ed9 | 2018-03-14 14:52:29 +0000 | [diff] [blame] | 1450 | // 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 Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1455 | } |
| 1456 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1457 | void TracingServiceImpl::ProducerEndpointImpl::SetSharedMemory( |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 1458 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1466 | SharedMemory* TracingServiceImpl::ProducerEndpointImpl::shared_memory() const { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1467 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1468 | return shared_memory_.get(); |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1469 | } |
| 1470 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1471 | size_t TracingServiceImpl::ProducerEndpointImpl::shared_buffer_page_size_kb() |
| 1472 | const { |
Isabelle Taylor | 69faa90 | 2018-03-21 15:42:03 +0000 | [diff] [blame] | 1473 | return shared_buffer_page_size_kb_; |
| 1474 | } |
| 1475 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1476 | void TracingServiceImpl::ProducerEndpointImpl::TearDownDataSource( |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1477 | 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 Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 1481 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1482 | 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 | |
| 1489 | SharedMemoryArbiterImpl* |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1490 | TracingServiceImpl::ProducerEndpointImpl::GetOrCreateShmemArbiter() { |
Florian Mayer | cd08ec6 | 2018-01-31 17:49:25 +0000 | [diff] [blame] | 1491 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | 2ffd1a5 | 2018-03-27 01:01:30 +0100 | [diff] [blame] | 1492 | 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 Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1497 | return inproc_shmem_arbiter_.get(); |
| 1498 | } |
| 1499 | |
| 1500 | std::unique_ptr<TraceWriter> |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1501 | TracingServiceImpl::ProducerEndpointImpl::CreateTraceWriter(BufferID buf_id) { |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1502 | PERFETTO_DCHECK_THREAD(thread_checker_); |
| 1503 | return GetOrCreateShmemArbiter()->CreateTraceWriter(buf_id); |
| 1504 | } |
| 1505 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1506 | void TracingServiceImpl::ProducerEndpointImpl::OnTracingSetup() { |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1507 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1514 | void TracingServiceImpl::ProducerEndpointImpl::Flush( |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 1515 | 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 Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1527 | void TracingServiceImpl::ProducerEndpointImpl::CreateDataSourceInstance( |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1528 | DataSourceInstanceID ds_id, |
| 1529 | const DataSourceConfig& config) { |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 1530 | PERFETTO_DCHECK_THREAD(thread_checker_); |
Primiano Tucci | dca727d | 2018-04-04 11:31:55 +0200 | [diff] [blame] | 1531 | 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 Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1536 | } |
| 1537 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1538 | void TracingServiceImpl::ProducerEndpointImpl::NotifyFlushComplete( |
| 1539 | FlushRequestID id) { |
Primiano Tucci | d52e627 | 2018-04-06 19:06:53 +0200 | [diff] [blame] | 1540 | PERFETTO_DCHECK_THREAD(thread_checker_); |
| 1541 | return GetOrCreateShmemArbiter()->NotifyFlushComplete(id); |
| 1542 | } |
| 1543 | |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 1544 | void TracingServiceImpl::ProducerEndpointImpl::NotifyDataSourceStopped( |
| 1545 | DataSourceInstanceID data_source_id) { |
| 1546 | PERFETTO_DCHECK_THREAD(thread_checker_); |
| 1547 | service_->NotifyDataSourceStopped(id_, data_source_id); |
| 1548 | } |
| 1549 | |
Primiano Tucci | 5358933 | 2017-12-19 11:31:13 +0100 | [diff] [blame] | 1550 | //////////////////////////////////////////////////////////////////////////////// |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1551 | // TracingServiceImpl::TracingSession implementation |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1552 | //////////////////////////////////////////////////////////////////////////////// |
| 1553 | |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1554 | TracingServiceImpl::TracingSession::TracingSession( |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 1555 | TracingSessionID session_id, |
Florian Mayer | 6a1a4d5 | 2018-06-08 16:47:07 +0100 | [diff] [blame] | 1556 | ConsumerEndpointImpl* consumer_ptr, |
| 1557 | const TraceConfig& new_config) |
Primiano Tucci | baeecf1 | 2018-07-25 12:02:20 +0100 | [diff] [blame] | 1558 | : id(session_id), consumer(consumer_ptr), config(new_config) {} |
Primiano Tucci | 20d441d | 2018-01-16 09:25:51 +0000 | [diff] [blame] | 1559 | |
Primiano Tucci | 4f9b6d7 | 2017-12-05 20:59:16 +0000 | [diff] [blame] | 1560 | } // namespace perfetto |