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 17 #ifndef SRC_TRACING_CORE_TRACING_SERVICE_IMPL_H_ 18 #define SRC_TRACING_CORE_TRACING_SERVICE_IMPL_H_ 19 20 #include <functional> 21 #include <map> 22 #include <memory> 23 #include <mutex> 24 #include <set> 25 #include <vector> 26 27 #include "perfetto/base/gtest_prod_util.h" 28 #include "perfetto/base/logging.h" 29 #include "perfetto/base/optional.h" 30 #include "perfetto/base/time.h" 31 #include "perfetto/base/weak_ptr.h" 32 #include "perfetto/tracing/core/basic_types.h" 33 #include "perfetto/tracing/core/commit_data_request.h" 34 #include "perfetto/tracing/core/data_source_descriptor.h" 35 #include "perfetto/tracing/core/observable_events.h" 36 #include "perfetto/tracing/core/shared_memory_abi.h" 37 #include "perfetto/tracing/core/trace_config.h" 38 #include "perfetto/tracing/core/trace_stats.h" 39 #include "perfetto/tracing/core/tracing_service.h" 40 #include "src/tracing/core/id_allocator.h" 41 42 namespace perfetto { 43 44 namespace base { 45 class TaskRunner; 46 } // namespace base 47 48 class Consumer; 49 class DataSourceConfig; 50 class Producer; 51 class SharedMemory; 52 class SharedMemoryArbiterImpl; 53 class TraceBuffer; 54 class TraceConfig; 55 class TracePacket; 56 57 // The tracing service business logic. 58 class TracingServiceImpl : public TracingService { 59 private: 60 struct DataSourceInstance; 61 62 public: 63 static constexpr size_t kDefaultShmSize = 256 * 1024ul; 64 static constexpr size_t kMaxShmSize = 32 * 1024 * 1024ul; 65 static constexpr uint32_t kDataSourceStopTimeoutMs = 5000; 66 static constexpr uint8_t kSyncMarker[] = {0x82, 0x47, 0x7a, 0x76, 0xb2, 0x8d, 67 0x42, 0xba, 0x81, 0xdc, 0x33, 0x32, 68 0x6d, 0x57, 0xa0, 0x79}; 69 70 // The implementation behind the service endpoint exposed to each producer. 71 class ProducerEndpointImpl : public TracingService::ProducerEndpoint { 72 public: 73 ProducerEndpointImpl(ProducerID, 74 uid_t uid, 75 TracingServiceImpl*, 76 base::TaskRunner*, 77 Producer*, 78 const std::string& producer_name, 79 bool in_process, 80 bool smb_scraping_enabled); 81 ~ProducerEndpointImpl() override; 82 83 // TracingService::ProducerEndpoint implementation. 84 void RegisterDataSource(const DataSourceDescriptor&) override; 85 void UnregisterDataSource(const std::string& name) override; 86 void RegisterTraceWriter(uint32_t writer_id, 87 uint32_t target_buffer) override; 88 void UnregisterTraceWriter(uint32_t writer_id) override; 89 void CommitData(const CommitDataRequest&, CommitDataCallback) override; 90 void SetSharedMemory(std::unique_ptr<SharedMemory>); 91 std::unique_ptr<TraceWriter> CreateTraceWriter(BufferID) override; 92 SharedMemoryArbiter* GetInProcessShmemArbiter() override; 93 void NotifyFlushComplete(FlushRequestID) override; 94 void NotifyDataSourceStarted(DataSourceInstanceID) override; 95 void NotifyDataSourceStopped(DataSourceInstanceID) override; 96 SharedMemory* shared_memory() const override; 97 size_t shared_buffer_page_size_kb() const override; 98 void ActivateTriggers(const std::vector<std::string>&) override; 99 100 void OnTracingSetup(); 101 void SetupDataSource(DataSourceInstanceID, const DataSourceConfig&); 102 void StartDataSource(DataSourceInstanceID, const DataSourceConfig&); 103 void StopDataSource(DataSourceInstanceID); 104 void Flush(FlushRequestID, const std::vector<DataSourceInstanceID>&); 105 void OnFreeBuffers(const std::vector<BufferID>& target_buffers); 106 void ClearIncrementalState(const std::vector<DataSourceInstanceID>&); 107 is_allowed_target_buffer(BufferID buffer_id)108 bool is_allowed_target_buffer(BufferID buffer_id) const { 109 return allowed_target_buffers_.count(buffer_id); 110 } 111 buffer_id_for_writer(WriterID writer_id)112 base::Optional<BufferID> buffer_id_for_writer(WriterID writer_id) const { 113 const auto it = writers_.find(writer_id); 114 if (it != writers_.end()) 115 return it->second; 116 return base::nullopt; 117 } 118 119 private: 120 friend class TracingServiceImpl; 121 friend class TracingServiceImplTest; 122 friend class TracingIntegrationTest; 123 ProducerEndpointImpl(const ProducerEndpointImpl&) = delete; 124 ProducerEndpointImpl& operator=(const ProducerEndpointImpl&) = delete; 125 126 ProducerID const id_; 127 const uid_t uid_; 128 TracingServiceImpl* const service_; 129 base::TaskRunner* const task_runner_; 130 Producer* producer_; 131 std::unique_ptr<SharedMemory> shared_memory_; 132 size_t shared_buffer_page_size_kb_ = 0; 133 SharedMemoryABI shmem_abi_; 134 size_t shmem_size_hint_bytes_ = 0; 135 const std::string name_; 136 bool in_process_; 137 bool smb_scraping_enabled_; 138 139 // Set of the global target_buffer IDs that the producer is configured to 140 // write into in any active tracing session. 141 std::set<BufferID> allowed_target_buffers_; 142 143 // Maps registered TraceWriter IDs to their target buffers as registered by 144 // the producer. Note that producers aren't required to register their 145 // writers, so we may see commits of chunks with WriterIDs that aren't 146 // contained in this map. However, if a producer does register a writer, the 147 // service will prevent the writer from writing into any other buffer than 148 // the one associated with it here. The BufferIDs stored in this map are 149 // untrusted, so need to be verified against |allowed_target_buffers_| 150 // before use. 151 std::map<WriterID, BufferID> writers_; 152 153 // This is used only in in-process configurations. 154 // SharedMemoryArbiterImpl methods themselves are thread-safe. 155 std::unique_ptr<SharedMemoryArbiterImpl> inproc_shmem_arbiter_; 156 157 PERFETTO_THREAD_CHECKER(thread_checker_) 158 base::WeakPtrFactory<ProducerEndpointImpl> weak_ptr_factory_; // Keep last. 159 }; 160 161 // The implementation behind the service endpoint exposed to each consumer. 162 class ConsumerEndpointImpl : public TracingService::ConsumerEndpoint { 163 public: 164 ConsumerEndpointImpl(TracingServiceImpl*, 165 base::TaskRunner*, 166 Consumer*, 167 uid_t uid); 168 ~ConsumerEndpointImpl() override; 169 170 void NotifyOnTracingDisabled(); 171 base::WeakPtr<ConsumerEndpointImpl> GetWeakPtr(); 172 173 // TracingService::ConsumerEndpoint implementation. 174 void EnableTracing(const TraceConfig&, base::ScopedFile) override; 175 void ChangeTraceConfig(const TraceConfig& cfg) override; 176 void StartTracing() override; 177 void DisableTracing() override; 178 void ReadBuffers() override; 179 void FreeBuffers() override; 180 void Flush(uint32_t timeout_ms, FlushCallback) override; 181 void Detach(const std::string& key) override; 182 void Attach(const std::string& key) override; 183 void GetTraceStats() override; 184 void ObserveEvents(uint32_t enabled_event_types) override; 185 186 // If |observe_data_source_instances == true|, will queue a task to notify 187 // the consumer about the state change. 188 void OnDataSourceInstanceStateChange(const ProducerEndpointImpl&, 189 const DataSourceInstance&); 190 191 private: 192 friend class TracingServiceImpl; 193 ConsumerEndpointImpl(const ConsumerEndpointImpl&) = delete; 194 ConsumerEndpointImpl& operator=(const ConsumerEndpointImpl&) = delete; 195 196 // Returns a pointer to an ObservableEvents object that the caller can fill 197 // and schedules a task to send the ObservableEvents to the consumer. 198 ObservableEvents* AddObservableEvents(); 199 200 base::TaskRunner* const task_runner_; 201 TracingServiceImpl* const service_; 202 Consumer* const consumer_; 203 uid_t const uid_; 204 TracingSessionID tracing_session_id_ = 0; 205 206 // Whether the consumer is interested in DataSourceInstance state change 207 // events. 208 uint32_t enabled_observable_event_types_ = ObservableEventType::kNone; 209 // ObservableEvents that will be sent to the consumer. If set, a task to 210 // flush the events to the consumer has been queued. 211 std::unique_ptr<ObservableEvents> observable_events_; 212 213 PERFETTO_THREAD_CHECKER(thread_checker_) 214 base::WeakPtrFactory<ConsumerEndpointImpl> weak_ptr_factory_; // Keep last. 215 }; 216 217 explicit TracingServiceImpl(std::unique_ptr<SharedMemory::Factory>, 218 base::TaskRunner*); 219 ~TracingServiceImpl() override; 220 221 // Called by ProducerEndpointImpl. 222 void DisconnectProducer(ProducerID); 223 void RegisterDataSource(ProducerID, const DataSourceDescriptor&); 224 void UnregisterDataSource(ProducerID, const std::string& name); 225 void CopyProducerPageIntoLogBuffer(ProducerID, 226 uid_t, 227 WriterID, 228 ChunkID, 229 BufferID, 230 uint16_t num_fragments, 231 uint8_t chunk_flags, 232 bool chunk_complete, 233 const uint8_t* src, 234 size_t size); 235 void ApplyChunkPatches(ProducerID, 236 const std::vector<CommitDataRequest::ChunkToPatch>&); 237 void NotifyFlushDoneForProducer(ProducerID, FlushRequestID); 238 void NotifyDataSourceStarted(ProducerID, const DataSourceInstanceID); 239 void NotifyDataSourceStopped(ProducerID, const DataSourceInstanceID); 240 void ActivateTriggers(ProducerID, const std::vector<std::string>& triggers); 241 242 // Called by ConsumerEndpointImpl. 243 bool DetachConsumer(ConsumerEndpointImpl*, const std::string& key); 244 bool AttachConsumer(ConsumerEndpointImpl*, const std::string& key); 245 void DisconnectConsumer(ConsumerEndpointImpl*); 246 bool EnableTracing(ConsumerEndpointImpl*, 247 const TraceConfig&, 248 base::ScopedFile); 249 void ChangeTraceConfig(ConsumerEndpointImpl*, const TraceConfig&); 250 251 bool StartTracing(TracingSessionID); 252 void DisableTracing(TracingSessionID, bool disable_immediately = false); 253 void Flush(TracingSessionID tsid, 254 uint32_t timeout_ms, 255 ConsumerEndpoint::FlushCallback); 256 void FlushAndDisableTracing(TracingSessionID); 257 void ReadBuffers(TracingSessionID, ConsumerEndpointImpl*); 258 void FreeBuffers(TracingSessionID); 259 260 // Service implementation. 261 std::unique_ptr<TracingService::ProducerEndpoint> ConnectProducer( 262 Producer*, 263 uid_t uid, 264 const std::string& producer_name, 265 size_t shared_memory_size_hint_bytes = 0, 266 bool in_process = false, 267 ProducerSMBScrapingMode smb_scraping_mode = 268 ProducerSMBScrapingMode::kDefault) override; 269 270 std::unique_ptr<TracingService::ConsumerEndpoint> ConnectConsumer( 271 Consumer*, 272 uid_t) override; 273 274 // Set whether SMB scraping should be enabled by default or not. Producers can 275 // override this setting for their own SMBs. SetSMBScrapingEnabled(bool enabled)276 void SetSMBScrapingEnabled(bool enabled) override { 277 smb_scraping_enabled_ = enabled; 278 } 279 280 // Exposed mainly for testing. num_producers()281 size_t num_producers() const { return producers_.size(); } 282 ProducerEndpointImpl* GetProducer(ProducerID) const; 283 284 uint32_t override_data_source_test_timeout_ms_for_testing = 0; 285 286 private: 287 friend class TracingServiceImplTest; 288 friend class TracingIntegrationTest; 289 290 struct RegisteredDataSource { 291 ProducerID producer_id; 292 DataSourceDescriptor descriptor; 293 }; 294 295 // Represents an active data source for a tracing session. 296 struct DataSourceInstance { DataSourceInstanceDataSourceInstance297 DataSourceInstance(DataSourceInstanceID id, 298 const DataSourceConfig& cfg, 299 const std::string& ds_name, 300 bool notify_on_start, 301 bool notify_on_stop, 302 bool handles_incremental_state_invalidation) 303 : instance_id(id), 304 config(cfg), 305 data_source_name(ds_name), 306 will_notify_on_start(notify_on_start), 307 will_notify_on_stop(notify_on_stop), 308 handles_incremental_state_clear( 309 handles_incremental_state_invalidation) {} 310 DataSourceInstance(const DataSourceInstance&) = delete; 311 DataSourceInstance& operator=(const DataSourceInstance&) = delete; 312 313 DataSourceInstanceID instance_id; 314 DataSourceConfig config; 315 std::string data_source_name; 316 bool will_notify_on_start; 317 bool will_notify_on_stop; 318 bool handles_incremental_state_clear; 319 320 enum DataSourceInstanceState { 321 CONFIGURED, 322 STARTING, 323 STARTED, 324 STOPPING, 325 STOPPED 326 }; 327 DataSourceInstanceState state = CONFIGURED; 328 }; 329 330 struct PendingFlush { 331 std::set<ProducerID> producers; 332 ConsumerEndpoint::FlushCallback callback; PendingFlushPendingFlush333 explicit PendingFlush(decltype(callback) cb) : callback(std::move(cb)) {} 334 }; 335 336 // Holds the state of a tracing session. A tracing session is uniquely bound 337 // a specific Consumer. Each Consumer can own one or more sessions. 338 struct TracingSession { 339 enum State { 340 DISABLED = 0, 341 CONFIGURED, 342 STARTED, 343 DISABLING_WAITING_STOP_ACKS 344 }; 345 346 TracingSession(TracingSessionID, ConsumerEndpointImpl*, const TraceConfig&); 347 num_buffersTracingSession348 size_t num_buffers() const { return buffers_index.size(); } 349 delay_to_next_write_period_msTracingSession350 uint32_t delay_to_next_write_period_ms() const { 351 PERFETTO_DCHECK(write_period_ms > 0); 352 return write_period_ms - 353 (base::GetWallTimeMs().count() % write_period_ms); 354 } 355 flush_timeout_msTracingSession356 uint32_t flush_timeout_ms() { 357 uint32_t timeout_ms = config.flush_timeout_ms(); 358 return timeout_ms ? timeout_ms : kDefaultFlushTimeoutMs; 359 } 360 GetPacketSequenceIDTracingSession361 PacketSequenceID GetPacketSequenceID(ProducerID producer_id, 362 WriterID writer_id) { 363 auto key = std::make_pair(producer_id, writer_id); 364 auto it = packet_sequence_ids.find(key); 365 if (it != packet_sequence_ids.end()) 366 return it->second; 367 // We shouldn't run out of sequence IDs (producer ID is 16 bit, writer IDs 368 // are limited to 1024). 369 static_assert(kMaxPacketSequenceID > kMaxProducerID * kMaxWriterID, 370 "PacketSequenceID value space doesn't cover service " 371 "sequence ID and all producer/writer ID combinations!"); 372 PERFETTO_DCHECK(last_packet_sequence_id < kMaxPacketSequenceID); 373 PacketSequenceID sequence_id = ++last_packet_sequence_id; 374 packet_sequence_ids[key] = sequence_id; 375 return sequence_id; 376 } 377 GetDataSourceInstanceTracingSession378 DataSourceInstance* GetDataSourceInstance( 379 ProducerID producer_id, 380 DataSourceInstanceID instance_id) { 381 for (auto& inst_kv : data_source_instances) { 382 if (inst_kv.first != producer_id || 383 inst_kv.second.instance_id != instance_id) { 384 continue; 385 } 386 return &inst_kv.second; 387 } 388 return nullptr; 389 } 390 AllDataSourceInstancesStoppedTracingSession391 bool AllDataSourceInstancesStopped() { 392 for (const auto& inst_kv : data_source_instances) { 393 if (inst_kv.second.state != DataSourceInstance::STOPPED) 394 return false; 395 } 396 return true; 397 } 398 399 const TracingSessionID id; 400 401 // The consumer that started the session. 402 // Can be nullptr if the consumer detached from the session. 403 ConsumerEndpointImpl* consumer_maybe_null; 404 405 // Unix uid of the consumer. This is valid even after the consumer detaches 406 // and does not change for the entire duration of the session. It is used to 407 // prevent that a consumer re-attaches to a session from a different uid. 408 uid_t const consumer_uid; 409 410 // The list of triggers this session received while alive and the time they 411 // were received at. This is used to insert 'fake' packets back to the 412 // consumer so they can tell when some event happened. The order matches the 413 // order they were received. 414 struct TriggerInfo { 415 uint64_t boot_time_ns; 416 std::string trigger_name; 417 std::string producer_name; 418 uid_t producer_uid; 419 }; 420 std::vector<TriggerInfo> received_triggers; 421 422 // The trace config provided by the Consumer when calling 423 // EnableTracing(), plus any updates performed by ChangeTraceConfig. 424 TraceConfig config; 425 426 // List of data source instances that have been enabled on the various 427 // producers for this tracing session. 428 // TODO(rsavitski): at the time of writing, the map structure is unused 429 // (even when the calling code has a key). This is also an opportunity to 430 // consider an alternative data type, e.g. a map of vectors. 431 std::multimap<ProducerID, DataSourceInstance> data_source_instances; 432 433 // For each Flush(N) request, keeps track of the set of producers for which 434 // we are still awaiting a NotifyFlushComplete(N) ack. 435 std::map<FlushRequestID, PendingFlush> pending_flushes; 436 437 // Maps a per-trace-session buffer index into the corresponding global 438 // BufferID (shared namespace amongst all consumers). This vector has as 439 // many entries as |config.buffers_size()|. 440 std::vector<BufferID> buffers_index; 441 442 std::map<std::pair<ProducerID, WriterID>, PacketSequenceID> 443 packet_sequence_ids; 444 PacketSequenceID last_packet_sequence_id = kServicePacketSequenceID; 445 446 // When the last snapshots (clock, stats, sync marker) were emitted into 447 // the output stream. 448 base::TimeMillis last_snapshot_time = {}; 449 450 // Whether we mirrored the trace config back to the trace output yet. 451 bool did_emit_config = false; 452 453 // Whether we put the system info into the trace output yet. 454 bool did_emit_system_info = false; 455 456 // The number of received triggers we've emitted into the trace output. 457 size_t num_triggers_emitted_into_trace = 0; 458 459 // Initial clock snapshot, captured at trace start time (when state goes 460 // to TracingSession::STARTED). Emitted into the trace when the consumer 461 // first begins reading the trace. 462 std::vector<TracePacket> initial_clock_snapshot_; 463 464 State state = DISABLED; 465 466 // If the consumer detached the session, this variable defines the key used 467 // for identifying the session later when reattaching. 468 std::string detach_key; 469 470 // This is set when the Consumer calls sets |write_into_file| == true in the 471 // TraceConfig. In this case this represents the file we should stream the 472 // trace packets into, rather than returning it to the consumer via 473 // OnTraceData(). 474 base::ScopedFile write_into_file; 475 uint32_t write_period_ms = 0; 476 uint64_t max_file_size_bytes = 0; 477 uint64_t bytes_written_into_file = 0; 478 }; 479 480 TracingServiceImpl(const TracingServiceImpl&) = delete; 481 TracingServiceImpl& operator=(const TracingServiceImpl&) = delete; 482 483 DataSourceInstance* SetupDataSource(const TraceConfig::DataSource&, 484 const TraceConfig::ProducerConfig&, 485 const RegisteredDataSource&, 486 TracingSession*); 487 488 // Returns the next available ProducerID that is not in |producers_|. 489 ProducerID GetNextProducerID(); 490 491 // Returns a pointer to the |tracing_sessions_| entry or nullptr if the 492 // session doesn't exists. 493 TracingSession* GetTracingSession(TracingSessionID); 494 495 // Returns a pointer to the |tracing_sessions_| entry, matching the given 496 // uid and detach key, or nullptr if no such session exists. 497 TracingSession* GetDetachedSession(uid_t, const std::string& key); 498 499 // Update the memory guard rail by using the latest information from the 500 // shared memory and trace buffers. 501 void UpdateMemoryGuardrail(); 502 503 void StartDataSourceInstance(ProducerEndpointImpl* producer, 504 TracingSession* tracing_session, 505 DataSourceInstance* instance); 506 void SnapshotSyncMarker(std::vector<TracePacket>*); 507 void SnapshotClocks(std::vector<TracePacket>*, bool set_root_timestamp); 508 void SnapshotStats(TracingSession*, std::vector<TracePacket>*); 509 TraceStats GetTraceStats(TracingSession* tracing_session); 510 void MaybeEmitTraceConfig(TracingSession*, std::vector<TracePacket>*); 511 void MaybeEmitSystemInfo(TracingSession*, std::vector<TracePacket>*); 512 void MaybeEmitReceivedTriggers(TracingSession*, std::vector<TracePacket>*); 513 void OnFlushTimeout(TracingSessionID, FlushRequestID); 514 void OnDisableTracingTimeout(TracingSessionID); 515 void DisableTracingNotifyConsumerAndFlushFile(TracingSession*); 516 void PeriodicFlushTask(TracingSessionID, bool post_next_only); 517 void CompleteFlush(TracingSessionID tsid, 518 ConsumerEndpoint::FlushCallback callback, 519 bool success); 520 void ScrapeSharedMemoryBuffers(TracingSession* tracing_session, 521 ProducerEndpointImpl* producer); 522 void PeriodicClearIncrementalStateTask(TracingSessionID, bool post_next_only); 523 TraceBuffer* GetBufferByID(BufferID); 524 void OnStartTriggersTimeout(TracingSessionID tsid); 525 526 base::TaskRunner* const task_runner_; 527 std::unique_ptr<SharedMemory::Factory> shm_factory_; 528 ProducerID last_producer_id_ = 0; 529 DataSourceInstanceID last_data_source_instance_id_ = 0; 530 TracingSessionID last_tracing_session_id_ = 0; 531 FlushRequestID last_flush_request_id_ = 0; 532 uid_t uid_ = 0; 533 534 // Buffer IDs are global across all consumers (because a Producer can produce 535 // data for more than one trace session, hence more than one consumer). 536 IdAllocator<BufferID> buffer_ids_; 537 538 std::multimap<std::string /*name*/, RegisteredDataSource> data_sources_; 539 std::map<ProducerID, ProducerEndpointImpl*> producers_; 540 std::set<ConsumerEndpointImpl*> consumers_; 541 std::map<TracingSessionID, TracingSession> tracing_sessions_; 542 std::map<BufferID, std::unique_ptr<TraceBuffer>> buffers_; 543 544 bool smb_scraping_enabled_ = false; 545 bool lockdown_mode_ = false; 546 uint32_t min_write_period_ms_ = 100; // Overridable for testing. 547 548 uint8_t sync_marker_packet_[32]; // Lazily initialized. 549 size_t sync_marker_packet_size_ = 0; 550 551 // Stats. 552 uint64_t chunks_discarded_ = 0; 553 uint64_t patches_discarded_ = 0; 554 555 PERFETTO_THREAD_CHECKER(thread_checker_) 556 557 base::WeakPtrFactory<TracingServiceImpl> 558 weak_ptr_factory_; // Keep at the end. 559 }; 560 561 } // namespace perfetto 562 563 #endif // SRC_TRACING_CORE_TRACING_SERVICE_IMPL_H_ 564