123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/tracing/perfetto/producer_host.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/process/process.h"
- #include "base/tracing/perfetto_task_runner.h"
- #include "build/build_config.h"
- #include "services/tracing/perfetto/perfetto_service.h"
- #include "services/tracing/public/cpp/perfetto/producer_client.h"
- #include "services/tracing/public/cpp/perfetto/shared_memory.h"
- #include "third_party/perfetto/include/perfetto/ext/tracing/core/commit_data_request.h"
- #include "third_party/perfetto/include/perfetto/tracing/core/data_source_descriptor.h"
- #include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
- namespace tracing {
- ProducerHost::ProducerHost(base::tracing::PerfettoTaskRunner* task_runner)
- : task_runner_(task_runner) {}
- ProducerHost::~ProducerHost() {
- // Manually reset to prevent any callbacks from the ProducerEndpoint
- // when we're in a half-destructed state.
- producer_endpoint_.reset();
- }
- ProducerHost::InitializationResult ProducerHost::Initialize(
- mojo::PendingRemote<mojom::ProducerClient> producer_client,
- perfetto::TracingService* service,
- const std::string& name,
- base::UnsafeSharedMemoryRegion shared_memory,
- uint64_t shared_memory_buffer_page_size_bytes) {
- DCHECK(service);
- DCHECK(!producer_endpoint_);
- producer_client_.Bind(std::move(producer_client));
- auto shm = std::make_unique<ChromeBaseSharedMemory>(std::move(shared_memory));
- // We may fail to map the buffer provided by the ProducerClient.
- if (!shm->start()) {
- return InitializationResult::kSmbMappingFailed;
- }
- size_t shm_size = shm->size();
- ChromeBaseSharedMemory* shm_raw = shm.get();
- // TODO(oysteine): Figure out a uid once we need it.
- producer_endpoint_ = service->ConnectProducer(
- this, 0 /* uid */, /*pid=*/::perfetto::base::kInvalidPid, name, shm_size,
- /*in_process=*/false,
- perfetto::TracingService::ProducerSMBScrapingMode::kDefault,
- shared_memory_buffer_page_size_bytes, std::move(shm));
- // In some cases, the service may deny the producer connection (e.g. if too
- // many producers are registered).
- if (!producer_endpoint_) {
- return InitializationResult::kProducerEndpointConstructionFailed;
- }
- // The service will adopt the shared memory buffer provided by the
- // ProducerClient as long as it is correctly sized.
- if (producer_endpoint_->shared_memory() != shm_raw) {
- return InitializationResult::kSmbNotAdopted;
- }
- // TODO(skyostil): Implement arbiter binding for the client API.
- #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- // When we are in-process, we don't use the in-process arbiter perfetto would
- // provide (thus pass |in_process = false| to ConnectProducer), but rather
- // bind the ProducerClient's arbiter to the service's endpoint and task runner
- // directly. This allows us to use startup tracing via an unbound SMA, while
- // avoiding some cross-sequence PostTasks when committing chunks (since we
- // bypass mojo).
- base::ProcessId pid;
- if (PerfettoService::ParsePidFromProducerName(name, &pid)) {
- bool in_process = (pid == base::Process::Current().Pid());
- if (in_process) {
- PerfettoTracedProcess::Get()
- ->producer_client()
- ->BindInProcessSharedMemoryArbiter(producer_endpoint_.get(),
- task_runner_);
- }
- }
- #endif // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- return InitializationResult::kSuccess;
- }
- void ProducerHost::OnConnect() {
- }
- void ProducerHost::OnDisconnect() {
- // Deliberately empty, this is invoked by the |service_| business logic after
- // we destroy the |producer_endpoint|.
- }
- void ProducerHost::OnTracingSetup() {
- producer_client_->OnTracingStart();
- }
- void ProducerHost::SetupDataSource(perfetto::DataSourceInstanceID,
- const perfetto::DataSourceConfig&) {
- // TODO(primiano): plumb call through mojo.
- }
- void ProducerHost::StartDataSource(perfetto::DataSourceInstanceID id,
- const perfetto::DataSourceConfig& config) {
- // The type traits will send the base fields in the DataSourceConfig and also
- // the ChromeConfig other configs are dropped.
- producer_client_->StartDataSource(
- id, config,
- base::BindOnce(
- [](ProducerHost* producer_host, perfetto::DataSourceInstanceID id) {
- producer_host->producer_endpoint_->NotifyDataSourceStarted(id);
- },
- base::Unretained(this), id));
- }
- void ProducerHost::StopDataSource(perfetto::DataSourceInstanceID id) {
- if (producer_client_) {
- producer_client_->StopDataSource(
- id,
- base::BindOnce(
- [](ProducerHost* producer_host, perfetto::DataSourceInstanceID id) {
- producer_host->producer_endpoint_->NotifyDataSourceStopped(id);
- },
- base::Unretained(this), id));
- }
- }
- void ProducerHost::Flush(
- perfetto::FlushRequestID id,
- const perfetto::DataSourceInstanceID* raw_data_source_ids,
- size_t num_data_sources) {
- DCHECK(producer_client_);
- std::vector<uint64_t> data_source_ids(raw_data_source_ids,
- raw_data_source_ids + num_data_sources);
- DCHECK_EQ(data_source_ids.size(), num_data_sources);
- producer_client_->Flush(id, data_source_ids);
- }
- void ProducerHost::ClearIncrementalState(const perfetto::DataSourceInstanceID*,
- size_t) {
- DCHECK(producer_client_);
- producer_client_->ClearIncrementalState();
- }
- // This data can come from a malicious child process. We don't do any
- // sanitization here because ProducerEndpoint::CommitData() (And any other
- // ProducerEndpoint methods) are designed to deal with malformed / malicious
- // inputs.
- void ProducerHost::CommitData(const perfetto::CommitDataRequest& data_request,
- CommitDataCallback callback) {
- if (on_commit_callback_for_testing_) {
- on_commit_callback_for_testing_.Run(data_request);
- }
- // This assumes that CommitData() will execute the callback synchronously.
- producer_endpoint_->CommitData(data_request, [&callback]() {
- std::move(callback).Run();
- });
- DCHECK(!callback); // Should have been run synchronously above.
- }
- void ProducerHost::RegisterDataSource(
- const perfetto::DataSourceDescriptor& registration_info) {
- producer_endpoint_->RegisterDataSource(registration_info);
- }
- void ProducerHost::RegisterTraceWriter(uint32_t writer_id,
- uint32_t target_buffer) {
- producer_endpoint_->RegisterTraceWriter(writer_id, target_buffer);
- }
- void ProducerHost::UnregisterTraceWriter(uint32_t writer_id) {
- producer_endpoint_->UnregisterTraceWriter(writer_id);
- }
- } // namespace tracing
|