producer_host.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/tracing/perfetto/producer_host.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/process/process.h"
  8. #include "base/tracing/perfetto_task_runner.h"
  9. #include "build/build_config.h"
  10. #include "services/tracing/perfetto/perfetto_service.h"
  11. #include "services/tracing/public/cpp/perfetto/producer_client.h"
  12. #include "services/tracing/public/cpp/perfetto/shared_memory.h"
  13. #include "third_party/perfetto/include/perfetto/ext/tracing/core/commit_data_request.h"
  14. #include "third_party/perfetto/include/perfetto/tracing/core/data_source_descriptor.h"
  15. #include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
  16. namespace tracing {
  17. ProducerHost::ProducerHost(base::tracing::PerfettoTaskRunner* task_runner)
  18. : task_runner_(task_runner) {}
  19. ProducerHost::~ProducerHost() {
  20. // Manually reset to prevent any callbacks from the ProducerEndpoint
  21. // when we're in a half-destructed state.
  22. producer_endpoint_.reset();
  23. }
  24. ProducerHost::InitializationResult ProducerHost::Initialize(
  25. mojo::PendingRemote<mojom::ProducerClient> producer_client,
  26. perfetto::TracingService* service,
  27. const std::string& name,
  28. base::UnsafeSharedMemoryRegion shared_memory,
  29. uint64_t shared_memory_buffer_page_size_bytes) {
  30. DCHECK(service);
  31. DCHECK(!producer_endpoint_);
  32. producer_client_.Bind(std::move(producer_client));
  33. auto shm = std::make_unique<ChromeBaseSharedMemory>(std::move(shared_memory));
  34. // We may fail to map the buffer provided by the ProducerClient.
  35. if (!shm->start()) {
  36. return InitializationResult::kSmbMappingFailed;
  37. }
  38. size_t shm_size = shm->size();
  39. ChromeBaseSharedMemory* shm_raw = shm.get();
  40. // TODO(oysteine): Figure out a uid once we need it.
  41. producer_endpoint_ = service->ConnectProducer(
  42. this, 0 /* uid */, /*pid=*/::perfetto::base::kInvalidPid, name, shm_size,
  43. /*in_process=*/false,
  44. perfetto::TracingService::ProducerSMBScrapingMode::kDefault,
  45. shared_memory_buffer_page_size_bytes, std::move(shm));
  46. // In some cases, the service may deny the producer connection (e.g. if too
  47. // many producers are registered).
  48. if (!producer_endpoint_) {
  49. return InitializationResult::kProducerEndpointConstructionFailed;
  50. }
  51. // The service will adopt the shared memory buffer provided by the
  52. // ProducerClient as long as it is correctly sized.
  53. if (producer_endpoint_->shared_memory() != shm_raw) {
  54. return InitializationResult::kSmbNotAdopted;
  55. }
  56. // TODO(skyostil): Implement arbiter binding for the client API.
  57. #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
  58. // When we are in-process, we don't use the in-process arbiter perfetto would
  59. // provide (thus pass |in_process = false| to ConnectProducer), but rather
  60. // bind the ProducerClient's arbiter to the service's endpoint and task runner
  61. // directly. This allows us to use startup tracing via an unbound SMA, while
  62. // avoiding some cross-sequence PostTasks when committing chunks (since we
  63. // bypass mojo).
  64. base::ProcessId pid;
  65. if (PerfettoService::ParsePidFromProducerName(name, &pid)) {
  66. bool in_process = (pid == base::Process::Current().Pid());
  67. if (in_process) {
  68. PerfettoTracedProcess::Get()
  69. ->producer_client()
  70. ->BindInProcessSharedMemoryArbiter(producer_endpoint_.get(),
  71. task_runner_);
  72. }
  73. }
  74. #endif // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
  75. return InitializationResult::kSuccess;
  76. }
  77. void ProducerHost::OnConnect() {
  78. }
  79. void ProducerHost::OnDisconnect() {
  80. // Deliberately empty, this is invoked by the |service_| business logic after
  81. // we destroy the |producer_endpoint|.
  82. }
  83. void ProducerHost::OnTracingSetup() {
  84. producer_client_->OnTracingStart();
  85. }
  86. void ProducerHost::SetupDataSource(perfetto::DataSourceInstanceID,
  87. const perfetto::DataSourceConfig&) {
  88. // TODO(primiano): plumb call through mojo.
  89. }
  90. void ProducerHost::StartDataSource(perfetto::DataSourceInstanceID id,
  91. const perfetto::DataSourceConfig& config) {
  92. // The type traits will send the base fields in the DataSourceConfig and also
  93. // the ChromeConfig other configs are dropped.
  94. producer_client_->StartDataSource(
  95. id, config,
  96. base::BindOnce(
  97. [](ProducerHost* producer_host, perfetto::DataSourceInstanceID id) {
  98. producer_host->producer_endpoint_->NotifyDataSourceStarted(id);
  99. },
  100. base::Unretained(this), id));
  101. }
  102. void ProducerHost::StopDataSource(perfetto::DataSourceInstanceID id) {
  103. if (producer_client_) {
  104. producer_client_->StopDataSource(
  105. id,
  106. base::BindOnce(
  107. [](ProducerHost* producer_host, perfetto::DataSourceInstanceID id) {
  108. producer_host->producer_endpoint_->NotifyDataSourceStopped(id);
  109. },
  110. base::Unretained(this), id));
  111. }
  112. }
  113. void ProducerHost::Flush(
  114. perfetto::FlushRequestID id,
  115. const perfetto::DataSourceInstanceID* raw_data_source_ids,
  116. size_t num_data_sources) {
  117. DCHECK(producer_client_);
  118. std::vector<uint64_t> data_source_ids(raw_data_source_ids,
  119. raw_data_source_ids + num_data_sources);
  120. DCHECK_EQ(data_source_ids.size(), num_data_sources);
  121. producer_client_->Flush(id, data_source_ids);
  122. }
  123. void ProducerHost::ClearIncrementalState(const perfetto::DataSourceInstanceID*,
  124. size_t) {
  125. DCHECK(producer_client_);
  126. producer_client_->ClearIncrementalState();
  127. }
  128. // This data can come from a malicious child process. We don't do any
  129. // sanitization here because ProducerEndpoint::CommitData() (And any other
  130. // ProducerEndpoint methods) are designed to deal with malformed / malicious
  131. // inputs.
  132. void ProducerHost::CommitData(const perfetto::CommitDataRequest& data_request,
  133. CommitDataCallback callback) {
  134. if (on_commit_callback_for_testing_) {
  135. on_commit_callback_for_testing_.Run(data_request);
  136. }
  137. // This assumes that CommitData() will execute the callback synchronously.
  138. producer_endpoint_->CommitData(data_request, [&callback]() {
  139. std::move(callback).Run();
  140. });
  141. DCHECK(!callback); // Should have been run synchronously above.
  142. }
  143. void ProducerHost::RegisterDataSource(
  144. const perfetto::DataSourceDescriptor& registration_info) {
  145. producer_endpoint_->RegisterDataSource(registration_info);
  146. }
  147. void ProducerHost::RegisterTraceWriter(uint32_t writer_id,
  148. uint32_t target_buffer) {
  149. producer_endpoint_->RegisterTraceWriter(writer_id, target_buffer);
  150. }
  151. void ProducerHost::UnregisterTraceWriter(uint32_t writer_id) {
  152. producer_endpoint_->UnregisterTraceWriter(writer_id);
  153. }
  154. } // namespace tracing