blob: 504ae7a8db68d6a785219ffc20d1bbf2b556262a [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2019 The Chromium Authors
Ken Rockotcbead332019-11-21 04:35:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/tracing/tracing_service_controller.h"
6
7#include <utility>
8
David Sandersde533fce2021-12-15 14:59:439#include "base/no_destructor.h"
Gabriel Charette9fb704a2020-02-26 16:10:2110#include "base/task/thread_pool.h"
Ken Rockotcbead332019-11-21 04:35:4711#include "content/public/browser/browser_task_traits.h"
12#include "content/public/browser/browser_thread.h"
Greg Thompson59bf58e2024-11-27 18:46:3513#include "content/public/browser/content_browser_client.h"
Ken Rockotcbead332019-11-21 04:35:4714#include "content/public/browser/service_process_host.h"
15#include "content/public/browser/tracing_service.h"
Greg Thompson59bf58e2024-11-27 18:46:3516#include "content/public/common/content_client.h"
Ken Rockotcbead332019-11-21 04:35:4717#include "mojo/public/cpp/bindings/pending_receiver.h"
18#include "mojo/public/cpp/bindings/remote.h"
19#include "mojo/public/cpp/bindings/self_owned_receiver.h"
20#include "services/tracing/public/cpp/traced_process.h"
21#include "services/tracing/public/cpp/tracing_features.h"
Alex Gough9b452062021-08-12 23:19:4822#include "services/tracing/public/mojom/tracing_service.mojom.h"
Ken Rockotcbead332019-11-21 04:35:4723#include "services/tracing/tracing_service.h"
24
25namespace content {
26
27namespace {
28
29void BindNewInProcessInstance(
30 mojo::PendingReceiver<tracing::mojom::TracingService> receiver) {
31 mojo::MakeSelfOwnedReceiver(std::make_unique<tracing::TracingService>(),
32 std::move(receiver));
33}
34
35} // namespace
36
37TracingServiceController::ClientRegistration::ClientRegistration(
Peter Kasting796cde22020-11-18 21:06:5338 base::PassKey<TracingServiceController>,
Ken Rockotcbead332019-11-21 04:35:4739 base::OnceClosure unregister)
40 : unregister_(std::move(unregister)) {}
41
42TracingServiceController::ClientRegistration::~ClientRegistration() {
43 std::move(unregister_).Run();
44}
45
46TracingServiceController::TracingServiceController() = default;
47
48TracingServiceController::~TracingServiceController() = default;
49
50// static
51TracingServiceController& TracingServiceController::Get() {
52 static base::NoDestructor<TracingServiceController> controller;
53 return *controller;
54}
55
56std::unique_ptr<TracingServiceController::ClientRegistration>
57TracingServiceController::RegisterClient(base::ProcessId pid,
58 EnableTracingCallback callback) {
59 base::OnceClosure unregister =
60 base::BindOnce(&TracingServiceController::RemoveClient,
61 base::Unretained(&TracingServiceController::Get()), pid);
62 auto registration = std::make_unique<ClientRegistration>(
Peter Kasting796cde22020-11-18 21:06:5363 base::PassKey<TracingServiceController>(), std::move(unregister));
Ken Rockotcbead332019-11-21 04:35:4764
65 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
66 // Force registration to happen on the UI thread.
Gabriel Charettee7cdc5cd2020-05-27 23:35:0567 GetUIThreadTaskRunner({})->PostTask(
68 FROM_HERE,
Ken Rockotcbead332019-11-21 04:35:4769 base::BindOnce(&TracingServiceController::RegisterClientOnUIThread,
70 base::Unretained(this), pid, std::move(callback)));
71 } else {
72 RegisterClientOnUIThread(pid, std::move(callback));
73 }
74
75 return registration;
76}
77
78tracing::mojom::TracingService& TracingServiceController::GetService() {
79 DCHECK_CURRENTLY_ON(BrowserThread::UI);
80
81 if (!service_) {
82 auto receiver = service_.BindNewPipeAndPassReceiver();
83 if (base::FeatureList::IsEnabled(features::kTracingServiceInProcess)) {
Gabriel Charette9fb704a2020-02-26 16:10:2184 base::ThreadPool::CreateSequencedTaskRunner(
85 {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
Ken Rockotcbead332019-11-21 04:35:4786 base::WithBaseSyncPrimitives(), base::TaskPriority::USER_BLOCKING})
87 ->PostTask(FROM_HERE, base::BindOnce(&BindNewInProcessInstance,
88 std::move(receiver)));
89 } else {
90 ServiceProcessHost::Launch(
91 std::move(receiver),
92 ServiceProcessHost::Options()
Ken Rockotcbead332019-11-21 04:35:4793 .WithDisplayName("Tracing Service")
94 .Pass());
95 }
Greg Thompson59bf58e2024-11-27 18:46:3596 // Unretained is safe because `this` owns `service_`.
97 service_.set_disconnect_handler(
98 base::BindOnce(&TracingServiceController::OnTracingServiceDisconnected,
99 base::Unretained(this)));
Ken Rockotcbead332019-11-21 04:35:47100
101 // Initialize the new service instance by pushing a pipe to each currently
102 // registered client, including the browser process itself.
103 std::vector<tracing::mojom::ClientInfoPtr> initial_clients;
104 mojo::PendingRemote<tracing::mojom::TracedProcess> browser_remote;
105 tracing::TracedProcess::ResetTracedProcessReceiver();
106 tracing::TracedProcess::OnTracedProcessRequest(
107 browser_remote.InitWithNewPipeAndPassReceiver());
108 initial_clients.push_back(tracing::mojom::ClientInfo::New(
109 base::GetCurrentProcId(), std::move(browser_remote)));
Nico Weber6dcde5b2020-02-22 20:49:20110 for (const std::pair<const base::ProcessId, EnableTracingCallback>& entry :
Ken Rockotcbead332019-11-21 04:35:47111 clients_) {
112 mojo::PendingRemote<tracing::mojom::TracedProcess> remote_process;
113 entry.second.Run(remote_process.InitWithNewPipeAndPassReceiver());
114 initial_clients.push_back(tracing::mojom::ClientInfo::New(
115 /*pid=*/entry.first, std::move(remote_process)));
116 }
117 service_->Initialize(std::move(initial_clients));
Greg Thompson59bf58e2024-11-27 18:46:35118
119 GetContentClient()->browser()->OnTracingServiceStarted();
Ken Rockotcbead332019-11-21 04:35:47120 }
121
122 return *service_.get();
123}
124
Greg Thompson59bf58e2024-11-27 18:46:35125void TracingServiceController::OnTracingServiceDisconnected() {
126 DCHECK_CURRENTLY_ON(BrowserThread::UI);
127 service_.reset();
128 GetContentClient()->browser()->OnTracingServiceStopped();
129}
130
Ken Rockotcbead332019-11-21 04:35:47131void TracingServiceController::RegisterClientOnUIThread(
132 base::ProcessId pid,
133 EnableTracingCallback callback) {
134 DCHECK_CURRENTLY_ON(BrowserThread::UI);
135
136 // If the service is currently running, immediately connect the new client.
137 if (service_) {
138 mojo::PendingRemote<tracing::mojom::TracedProcess> remote_process;
139 callback.Run(remote_process.InitWithNewPipeAndPassReceiver());
140 service_->AddClient(
141 tracing::mojom::ClientInfo::New(pid, std::move(remote_process)));
142 }
143
144 clients_.emplace(pid, std::move(callback));
145}
146
147void TracingServiceController::RemoveClient(base::ProcessId pid) {
148 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:05149 GetUIThreadTaskRunner({})->PostTask(
150 FROM_HERE, base::BindOnce(&TracingServiceController::RemoveClient,
Ken Rockotcbead332019-11-21 04:35:47151 base::Unretained(this), pid));
152 return;
153 }
154
155 DCHECK_CURRENTLY_ON(BrowserThread::UI);
156 clients_.erase(pid);
157}
158
159tracing::mojom::TracingService& GetTracingService() {
160 DCHECK_CURRENTLY_ON(BrowserThread::UI);
161 return TracingServiceController::Get().GetService();
162}
163
164} // namespace content