|  | /* | 
|  | * Copyright (C) 2017 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef SRC_TRACING_CORE_SERVICE_IMPL_H_ | 
|  | #define SRC_TRACING_CORE_SERVICE_IMPL_H_ | 
|  |  | 
|  | #include <functional> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <set> | 
|  |  | 
|  | #include "gtest/gtest_prod.h" | 
|  | #include "perfetto/base/page_allocator.h" | 
|  | #include "perfetto/base/weak_ptr.h" | 
|  | #include "perfetto/tracing/core/basic_types.h" | 
|  | #include "perfetto/tracing/core/data_source_descriptor.h" | 
|  | #include "perfetto/tracing/core/service.h" | 
|  | #include "perfetto/tracing/core/shared_memory_abi.h" | 
|  | #include "perfetto/tracing/core/trace_config.h" | 
|  | #include "src/tracing/core/id_allocator.h" | 
|  |  | 
|  | namespace perfetto { | 
|  |  | 
|  | namespace base { | 
|  | class TaskRunner; | 
|  | }  // namespace base | 
|  |  | 
|  | class Consumer; | 
|  | class DataSourceConfig; | 
|  | class Producer; | 
|  | class SharedMemory; | 
|  | class TraceConfig; | 
|  |  | 
|  | // The tracing service business logic. | 
|  | class ServiceImpl : public Service { | 
|  | public: | 
|  | using TracingSessionID = uint64_t; | 
|  |  | 
|  | // The implementation behind the service endpoint exposed to each producer. | 
|  | class ProducerEndpointImpl : public Service::ProducerEndpoint { | 
|  | public: | 
|  | ProducerEndpointImpl(ProducerID, | 
|  | uid_t uid, | 
|  | ServiceImpl*, | 
|  | base::TaskRunner*, | 
|  | Producer*, | 
|  | std::unique_ptr<SharedMemory>); | 
|  | ~ProducerEndpointImpl() override; | 
|  |  | 
|  | // Service::ProducerEndpoint implementation. | 
|  | void RegisterDataSource(const DataSourceDescriptor&, | 
|  | RegisterDataSourceCallback) override; | 
|  | void UnregisterDataSource(DataSourceID) override; | 
|  | void CommitData(const CommitDataRequest&) override; | 
|  | std::unique_ptr<TraceWriter> CreateTraceWriter(BufferID) override; | 
|  | SharedMemory* shared_memory() const override; | 
|  |  | 
|  | private: | 
|  | friend class ServiceImpl; | 
|  | FRIEND_TEST(ServiceImplTest, RegisterAndUnregister); | 
|  | ProducerEndpointImpl(const ProducerEndpointImpl&) = delete; | 
|  | ProducerEndpointImpl& operator=(const ProducerEndpointImpl&) = delete; | 
|  |  | 
|  | ProducerID const id_; | 
|  | const uid_t uid_; | 
|  | ServiceImpl* const service_; | 
|  | base::TaskRunner* const task_runner_; | 
|  | Producer* producer_; | 
|  | std::unique_ptr<SharedMemory> shared_memory_; | 
|  | SharedMemoryABI shmem_abi_; | 
|  | DataSourceID last_data_source_id_ = 0; | 
|  | PERFETTO_THREAD_CHECKER(thread_checker_) | 
|  | }; | 
|  |  | 
|  | // The implementation behind the service endpoint exposed to each consumer. | 
|  | class ConsumerEndpointImpl : public Service::ConsumerEndpoint { | 
|  | public: | 
|  | ConsumerEndpointImpl(ServiceImpl*, base::TaskRunner*, Consumer*); | 
|  | ~ConsumerEndpointImpl() override; | 
|  |  | 
|  | base::WeakPtr<ConsumerEndpointImpl> GetWeakPtr(); | 
|  |  | 
|  | // Service::ConsumerEndpoint implementation. | 
|  | void EnableTracing(const TraceConfig&) override; | 
|  | void DisableTracing() override; | 
|  | void ReadBuffers() override; | 
|  | void FreeBuffers() override; | 
|  |  | 
|  | private: | 
|  | friend class ServiceImpl; | 
|  | ConsumerEndpointImpl(const ConsumerEndpointImpl&) = delete; | 
|  | ConsumerEndpointImpl& operator=(const ConsumerEndpointImpl&) = delete; | 
|  |  | 
|  | ServiceImpl* const service_; | 
|  | Consumer* const consumer_; | 
|  | TracingSessionID tracing_session_id_ = 0; | 
|  |  | 
|  | PERFETTO_THREAD_CHECKER(thread_checker_) | 
|  |  | 
|  | base::WeakPtrFactory<ConsumerEndpointImpl> weak_ptr_factory_; | 
|  | }; | 
|  |  | 
|  | explicit ServiceImpl(std::unique_ptr<SharedMemory::Factory>, | 
|  | base::TaskRunner*); | 
|  | ~ServiceImpl() override; | 
|  |  | 
|  | // Called by ProducerEndpointImpl. | 
|  | void DisconnectProducer(ProducerID); | 
|  | void RegisterDataSource(ProducerID, | 
|  | DataSourceID, | 
|  | const DataSourceDescriptor&); | 
|  | void UnregisterDataSource(ProducerID, DataSourceID); | 
|  | void CopyProducerPageIntoLogBuffer(ProducerID, | 
|  | BufferID, | 
|  | const uint8_t*, | 
|  | size_t); | 
|  |  | 
|  | // Called by ConsumerEndpointImpl. | 
|  | void DisconnectConsumer(ConsumerEndpointImpl*); | 
|  | void EnableTracing(ConsumerEndpointImpl*, const TraceConfig&); | 
|  | void DisableTracing(TracingSessionID); | 
|  | void ReadBuffers(TracingSessionID, ConsumerEndpointImpl*); | 
|  | void FreeBuffers(TracingSessionID); | 
|  |  | 
|  | // Service implementation. | 
|  | std::unique_ptr<Service::ProducerEndpoint> ConnectProducer( | 
|  | Producer*, | 
|  | uid_t uid, | 
|  | size_t shared_buffer_size_hint_bytes = 0) override; | 
|  |  | 
|  | std::unique_ptr<Service::ConsumerEndpoint> ConnectConsumer( | 
|  | Consumer*) override; | 
|  |  | 
|  | // Exposed mainly for testing. | 
|  | size_t num_producers() const { return producers_.size(); } | 
|  | ProducerEndpointImpl* GetProducer(ProducerID) const; | 
|  |  | 
|  | private: | 
|  | FRIEND_TEST(ServiceImplTest, ProducerIDWrapping); | 
|  |  | 
|  | struct RegisteredDataSource { | 
|  | ProducerID producer_id; | 
|  | DataSourceID data_source_id; | 
|  | DataSourceDescriptor descriptor; | 
|  | }; | 
|  |  | 
|  | // Represents an active data source for a tracing session. | 
|  | struct DataSourceInstance { | 
|  | DataSourceInstanceID instance_id; | 
|  | DataSourceID data_source_id; | 
|  | }; | 
|  |  | 
|  | struct TraceBuffer { | 
|  | TraceBuffer(); | 
|  | ~TraceBuffer(); | 
|  | TraceBuffer(TraceBuffer&&) noexcept; | 
|  | TraceBuffer& operator=(TraceBuffer&&); | 
|  |  | 
|  | bool Create(size_t size_in_bytes); | 
|  | size_t num_pages() const { return size / kBufferPageSize; } | 
|  |  | 
|  | uint8_t* get_page(size_t page) { | 
|  | PERFETTO_DCHECK(page < num_pages()); | 
|  | return reinterpret_cast<uint8_t*>(data.get()) + page * kBufferPageSize; | 
|  | } | 
|  |  | 
|  | uid_t get_page_owner(size_t page) const { | 
|  | PERFETTO_DCHECK(page < num_pages()); | 
|  | return page_owners[page]; | 
|  | } | 
|  |  | 
|  | uint8_t* acquire_next_page(uid_t uid) { | 
|  | size_t cur = cur_page; | 
|  | cur_page = cur_page == num_pages() - 1 ? 0 : cur_page + 1; | 
|  | page_owners[cur] = uid; | 
|  | return get_page(cur); | 
|  | } | 
|  |  | 
|  | size_t size = 0; | 
|  | size_t cur_page = 0;  // Write pointer in the ring buffer. | 
|  | base::PageAllocator::UniquePtr data; | 
|  |  | 
|  | // TODO(primiano): The TraceBuffer is not shared and there is no reason to | 
|  | // use the SharedMemoryABI. This is just a a temporary workaround to reuse | 
|  | // the convenience of SharedMemoryABI for bookkeeping of the buffer when | 
|  | // implementing ReadBuffers(). | 
|  | std::unique_ptr<SharedMemoryABI> abi; | 
|  |  | 
|  | // Trusted uid for each acquired page. | 
|  | std::vector<uid_t> page_owners; | 
|  | }; | 
|  |  | 
|  | // Holds the state of a tracing session. A tracing session is uniquely bound | 
|  | // a specific Consumer. Each Consumer can own one or more sessions. | 
|  | struct TracingSession { | 
|  | explicit TracingSession(const TraceConfig&); | 
|  |  | 
|  | size_t num_buffers() const { return buffers_index.size(); } | 
|  |  | 
|  | // The original trace config provided by the Consumer when calling | 
|  | // EnableTracing(). | 
|  | const TraceConfig config; | 
|  |  | 
|  | // List of data source instances that have been enabled on the various | 
|  | // producers for this tracing session. | 
|  | std::multimap<ProducerID, DataSourceInstance> data_source_instances; | 
|  |  | 
|  | // Maps a per-trace-session buffer index into the corresponding global | 
|  | // BufferID (shared namespace amongst all consumers). This vector has as | 
|  | // many entries as |config.buffers_size()|. | 
|  | std::vector<BufferID> buffers_index; | 
|  | }; | 
|  |  | 
|  | ServiceImpl(const ServiceImpl&) = delete; | 
|  | ServiceImpl& operator=(const ServiceImpl&) = delete; | 
|  |  | 
|  | void CreateDataSourceInstance(const TraceConfig::DataSource&, | 
|  | const RegisteredDataSource&, | 
|  | TracingSession*); | 
|  |  | 
|  | // Returns the next available ProducerID that is not in |producers_|. | 
|  | ProducerID GetNextProducerID(); | 
|  |  | 
|  | // Returns a pointer to the |tracing_sessions_| entry or nullptr if the | 
|  | // session doesn't exists. | 
|  | TracingSession* GetTracingSession(TracingSessionID); | 
|  |  | 
|  | // Update the memory guard rail by using the latest information from the | 
|  | // shared memory and trace buffers. | 
|  | void UpdateMemoryGuardrail(); | 
|  |  | 
|  | base::TaskRunner* const task_runner_; | 
|  | std::unique_ptr<SharedMemory::Factory> shm_factory_; | 
|  | ProducerID last_producer_id_ = 0; | 
|  | DataSourceInstanceID last_data_source_instance_id_ = 0; | 
|  | TracingSessionID last_tracing_session_id_ = 0; | 
|  |  | 
|  | // Buffer IDs are global across all consumers (because a Producer can produce | 
|  | // data for more than one trace session, hence more than one consumer). | 
|  | IdAllocator<BufferID> buffer_ids_; | 
|  |  | 
|  | std::multimap<std::string /*name*/, RegisteredDataSource> data_sources_; | 
|  |  | 
|  | // TODO(primiano): There doesn't seem to be any good reason why |producers_| | 
|  | // is a map indexed by ID and not just a set<ProducerEndpointImpl*>. | 
|  | std::map<ProducerID, ProducerEndpointImpl*> producers_; | 
|  |  | 
|  | std::set<ConsumerEndpointImpl*> consumers_; | 
|  | std::map<TracingSessionID, TracingSession> tracing_sessions_; | 
|  | std::map<BufferID, TraceBuffer> buffers_; | 
|  |  | 
|  | bool lockdown_mode_ = false; | 
|  |  | 
|  | PERFETTO_THREAD_CHECKER(thread_checker_) | 
|  |  | 
|  | base::WeakPtrFactory<ServiceImpl> weak_ptr_factory_;  // Keep at the end. | 
|  | }; | 
|  |  | 
|  | }  // namespace perfetto | 
|  |  | 
|  | #endif  // SRC_TRACING_CORE_SERVICE_IMPL_H_ |