perfetto_service.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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/perfetto_service.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/metrics/histogram_functions.h"
  8. #include "base/no_destructor.h"
  9. #include "base/process/process_handle.h"
  10. #include "base/strings/strcat.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/strings/string_util.h"
  13. #include "build/build_config.h"
  14. #include "mojo/public/cpp/bindings/message.h"
  15. #include "services/tracing/perfetto/consumer_host.h"
  16. #include "services/tracing/perfetto/producer_host.h"
  17. #include "services/tracing/public/cpp/perfetto/shared_memory.h"
  18. #include "third_party/perfetto/include/perfetto/ext/tracing/core/tracing_service.h"
  19. namespace tracing {
  20. namespace {
  21. // Parses the PID from |pid_as_string| and stores the result in |pid|.
  22. // Returns true if the PID was parsed successfully.
  23. bool ParseProcessId(const std::string& pid_as_string, base::ProcessId* pid) {
  24. #if BUILDFLAG(IS_FUCHSIA)
  25. // Fuchsia zx_koid_t is a 64-bit int.
  26. static_assert(sizeof(base::ProcessId) == 8);
  27. return base::StringToUint64(pid_as_string, pid);
  28. #else
  29. // All other platforms use 32-bit ints for their PIDs.
  30. static_assert(sizeof(base::ProcessId) == 4);
  31. return base::StringToUint(pid_as_string, reinterpret_cast<uint32_t*>(pid));
  32. #endif
  33. }
  34. } // namespace
  35. // static
  36. bool PerfettoService::ParsePidFromProducerName(const std::string& producer_name,
  37. base::ProcessId* pid) {
  38. if (!base::StartsWith(producer_name, mojom::kPerfettoProducerNamePrefix,
  39. base::CompareCase::SENSITIVE)) {
  40. LOG(DFATAL) << "Unexpected producer name: " << producer_name;
  41. return false;
  42. }
  43. static const size_t kPrefixLength =
  44. strlen(mojom::kPerfettoProducerNamePrefix);
  45. if (!ParseProcessId(producer_name.substr(kPrefixLength), pid)) {
  46. LOG(DFATAL) << "Unexpected producer name: " << producer_name;
  47. return false;
  48. }
  49. return true;
  50. }
  51. // static
  52. PerfettoService* PerfettoService::GetInstance() {
  53. static base::NoDestructor<PerfettoService> perfetto_service;
  54. return perfetto_service.get();
  55. }
  56. PerfettoService::PerfettoService(
  57. scoped_refptr<base::SequencedTaskRunner> task_runner_for_testing)
  58. : perfetto_task_runner_(task_runner_for_testing
  59. ? std::move(task_runner_for_testing)
  60. : base::SequencedTaskRunnerHandle::Get()) {
  61. service_ = perfetto::TracingService::CreateInstance(
  62. std::make_unique<ChromeBaseSharedMemory::Factory>(),
  63. &perfetto_task_runner_);
  64. // Chromium uses scraping of the shared memory chunks to ensure that data
  65. // from threads without a MessageLoop doesn't get lost.
  66. service_->SetSMBScrapingEnabled(true);
  67. receivers_.set_disconnect_handler(base::BindRepeating(
  68. &PerfettoService::OnServiceDisconnect, base::Unretained(this)));
  69. producer_receivers_.set_disconnect_handler(base::BindRepeating(
  70. &PerfettoService::OnProducerHostDisconnect, base::Unretained(this)));
  71. }
  72. PerfettoService::~PerfettoService() = default;
  73. perfetto::TracingService* PerfettoService::GetService() const {
  74. return service_.get();
  75. }
  76. void PerfettoService::BindReceiver(
  77. mojo::PendingReceiver<mojom::PerfettoService> receiver,
  78. uint32_t pid) {
  79. ++num_active_connections_[pid];
  80. receivers_.Add(this, std::move(receiver), pid);
  81. }
  82. void PerfettoService::ConnectToProducerHost(
  83. mojo::PendingRemote<mojom::ProducerClient> producer_client,
  84. mojo::PendingReceiver<mojom::ProducerHost> producer_host_receiver,
  85. base::UnsafeSharedMemoryRegion shared_memory,
  86. uint64_t shared_memory_buffer_page_size_bytes) {
  87. // `shared_memory` is not marked nullable in the Mojom IDL so the region
  88. // should always be valid.
  89. DCHECK(shared_memory.IsValid());
  90. auto new_producer = std::make_unique<ProducerHost>(&perfetto_task_runner_);
  91. uint32_t producer_pid = receivers_.current_context();
  92. ProducerHost::InitializationResult result = new_producer->Initialize(
  93. std::move(producer_client), service_.get(),
  94. base::StrCat({mojom::kPerfettoProducerNamePrefix,
  95. base::NumberToString(producer_pid)}),
  96. std::move(shared_memory), shared_memory_buffer_page_size_bytes);
  97. base::UmaHistogramEnumeration("Tracing.ProducerHostInitializationResult",
  98. result);
  99. if (result == ProducerHost::InitializationResult::kSmbNotAdopted) {
  100. // When everything else succeeds, but the SMB was not accepted, the producer
  101. // must be misbehaving. SMBs are not accepted only if they are incorrectly
  102. // sized, but SMB/page sizes are constants in Chromium.
  103. mojo::ReportBadMessage("Producer connection request with invalid SMB");
  104. return;
  105. }
  106. if (result != ProducerHost::InitializationResult::kSuccess) {
  107. // In other failure scenarios, the tracing service may have encountered an
  108. // internal error not caused by a misbehaving producer, e.g. we have too
  109. // many producers registered or mapping the SMB failed (crbug/1154344). In
  110. // these cases, we have no choice but to ignore the failure and cancel the
  111. // producer connection by dropping |new_producer|.
  112. return;
  113. }
  114. ++num_active_connections_[producer_pid];
  115. producer_receivers_.Add(std::move(new_producer),
  116. std::move(producer_host_receiver), producer_pid);
  117. }
  118. void PerfettoService::AddActiveServicePid(base::ProcessId pid) {
  119. active_service_pids_.insert(pid);
  120. for (auto* tracing_session : tracing_sessions_) {
  121. tracing_session->OnActiveServicePidAdded(pid);
  122. }
  123. }
  124. void PerfettoService::RemoveActiveServicePid(base::ProcessId pid) {
  125. active_service_pids_.erase(pid);
  126. num_active_connections_.erase(pid);
  127. for (auto* tracing_session : tracing_sessions_) {
  128. tracing_session->OnActiveServicePidRemoved(pid);
  129. }
  130. }
  131. void PerfettoService::RemoveActiveServicePidIfNoActiveConnections(
  132. base::ProcessId pid) {
  133. const auto num_connections_it = num_active_connections_.find(pid);
  134. if (num_connections_it == num_active_connections_.end() ||
  135. num_connections_it->second == 0) {
  136. RemoveActiveServicePid(pid);
  137. }
  138. }
  139. void PerfettoService::SetActiveServicePidsInitialized() {
  140. active_service_pids_initialized_ = true;
  141. for (auto* tracing_session : tracing_sessions_) {
  142. tracing_session->OnActiveServicePidsInitialized();
  143. }
  144. }
  145. void PerfettoService::RegisterTracingSession(
  146. ConsumerHost::TracingSession* tracing_session) {
  147. tracing_sessions_.insert(tracing_session);
  148. }
  149. void PerfettoService::UnregisterTracingSession(
  150. ConsumerHost::TracingSession* tracing_session) {
  151. tracing_sessions_.erase(tracing_session);
  152. }
  153. void PerfettoService::RequestTracingSession(
  154. mojom::TracingClientPriority priority,
  155. base::OnceClosure callback) {
  156. // TODO(oysteine): This currently assumes we only have one concurrent tracing
  157. // session, which is enforced by all ConsumerHost::BeginTracing calls routing
  158. // through RequestTracingSession before creating a new TracingSession.
  159. // Not running the callback means we'll drop any connection requests and deny
  160. // the creation of the tracing session.
  161. for (auto* tracing_session : tracing_sessions_) {
  162. if (!tracing_session->tracing_enabled()) {
  163. continue;
  164. }
  165. if (tracing_session->tracing_priority() > priority) {
  166. return;
  167. }
  168. // If the currently active session is the same or lower priority and it's
  169. // tracing, then we'll disable it and re-try the request once it's shut
  170. // down.
  171. tracing_session->RequestDisableTracing(
  172. base::BindOnce(&PerfettoService::RequestTracingSession,
  173. base::Unretained(PerfettoService::GetInstance()),
  174. priority, std::move(callback)));
  175. return;
  176. }
  177. std::move(callback).Run();
  178. }
  179. void PerfettoService::OnServiceDisconnect() {
  180. OnDisconnectFromProcess(receivers_.current_context());
  181. }
  182. void PerfettoService::OnProducerHostDisconnect() {
  183. OnDisconnectFromProcess(producer_receivers_.current_context());
  184. }
  185. void PerfettoService::OnDisconnectFromProcess(base::ProcessId pid) {
  186. int& num_connections = num_active_connections_[pid];
  187. DCHECK_GT(num_connections, 0);
  188. --num_connections;
  189. if (!num_connections)
  190. RemoveActiveServicePid(pid);
  191. }
  192. } // namespace tracing