| // 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/tracing_service.h" |
| |
| #include <map> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/stl_util.h" |
| #include "base/timer/timer.h" |
| #include "services/service_manager/public/mojom/service_manager.mojom.h" |
| #include "services/tracing/agent_registry.h" |
| #include "services/tracing/coordinator.h" |
| #include "services/tracing/perfetto/consumer_host.h" |
| #include "services/tracing/perfetto/perfetto_service.h" |
| #include "services/tracing/perfetto/perfetto_tracing_coordinator.h" |
| #include "services/tracing/public/cpp/tracing_features.h" |
| #include "services/tracing/public/mojom/traced_process.mojom.h" |
| |
| namespace tracing { |
| |
| // Listener used to connect to every other service and |
| // pass them the needed interface pointers to connect |
| // back and register with the tracing service. |
| class ServiceListener : public service_manager::mojom::ServiceManagerListener { |
| public: |
| ServiceListener(service_manager::Connector* connector, |
| AgentRegistry* agent_registry, |
| Coordinator* coordinator) |
| : connector_(connector), |
| agent_registry_(agent_registry), |
| coordinator_(coordinator) { |
| service_manager::mojom::ServiceManagerPtr service_manager; |
| connector_->BindInterface(service_manager::mojom::kServiceName, |
| &service_manager); |
| service_manager::mojom::ServiceManagerListenerPtr listener; |
| service_manager::mojom::ServiceManagerListenerRequest request( |
| mojo::MakeRequest(&listener)); |
| service_manager->AddListener(std::move(listener)); |
| binding_.Bind(std::move(request)); |
| } |
| |
| size_t CountServicesWithPID(uint32_t pid) { |
| return std::count_if(service_pid_map_.begin(), service_pid_map_.end(), |
| [pid](const auto& p) { return p.second == pid; }); |
| } |
| |
| void ServiceAddedWithPID(const service_manager::Identity& identity, |
| uint32_t pid) { |
| service_pid_map_[identity] = pid; |
| |
| // Not the first service added for this PID, and the process has already |
| // accepted a connection request. |
| if (base::Contains(connected_pids_, pid)) |
| return; |
| |
| // Let the Coordinator and the perfetto service know it should be expecting |
| // a connection from this process. |
| coordinator_->AddExpectedPID(pid); |
| PerfettoService::GetInstance()->AddActiveServicePid(pid); |
| |
| // NOTE: If multiple service instances are running in the same process, we |
| // may send multiple ConnectToTracingService calls to the same process in |
| // the time it takes the first call to be received and acknowledged. This is |
| // OK, because any given client process will only bind a single |
| // TracedProcess endpoint as long as this instance of the tracing service |
| // remains alive. Subsequent TracedProcess endpoints will be dropped and |
| // their calls will never be processed. |
| |
| mojom::TracedProcessPtr traced_process; |
| connector_->BindInterface( |
| service_manager::ServiceFilter::ForExactIdentity(identity), |
| mojo::MakeRequest(&traced_process), |
| service_manager::mojom::BindInterfacePriority::kBestEffort); |
| |
| auto new_connection_request = mojom::ConnectToTracingRequest::New(); |
| auto service_request = |
| mojo::MakeRequest(&new_connection_request->perfetto_service); |
| auto registry_request = |
| mojo::MakeRequest(&new_connection_request->agent_registry); |
| mojom::TracedProcess* raw_traced_process = traced_process.get(); |
| raw_traced_process->ConnectToTracingService( |
| std::move(new_connection_request), |
| base::BindOnce(&ServiceListener::OnProcessConnected, |
| base::Unretained(this), std::move(traced_process), pid, |
| std::move(service_request), |
| std::move(registry_request))); |
| } |
| |
| void ServiceRemoved(const service_manager::Identity& identity) { |
| auto entry = service_pid_map_.find(identity); |
| if (entry != service_pid_map_.end()) { |
| uint32_t pid = entry->second; |
| service_pid_map_.erase(entry); |
| // Last entry with this PID removed; stop expecting it |
| // to connect to the tracing service. |
| if (CountServicesWithPID(pid) == 0) { |
| coordinator_->RemoveExpectedPID(pid); |
| PerfettoService::GetInstance()->RemoveActiveServicePid(pid); |
| connected_pids_.erase(pid); |
| } |
| } |
| } |
| |
| // service_manager::mojom::ServiceManagerListener implementation. |
| void OnInit(std::vector<service_manager::mojom::RunningServiceInfoPtr> |
| running_services) override { |
| for (auto& service : running_services) { |
| if (service->pid) { |
| ServiceAddedWithPID(service->identity, service->pid); |
| } |
| } |
| |
| coordinator_->FinishedReceivingRunningPIDs(); |
| PerfettoService::GetInstance()->SetActiveServicePidsInitialized(); |
| } |
| |
| void OnServicePIDReceived(const service_manager::Identity& identity, |
| uint32_t pid) override { |
| ServiceAddedWithPID(identity, pid); |
| } |
| |
| void OnServiceFailedToStart( |
| const service_manager::Identity& identity) override { |
| ServiceRemoved(identity); |
| } |
| |
| void OnServiceStopped(const service_manager::Identity& identity) override { |
| ServiceRemoved(identity); |
| } |
| |
| void OnServiceStarted(const service_manager::Identity& identity, |
| uint32_t pid) override { |
| } |
| |
| void OnServiceCreated( |
| service_manager::mojom::RunningServiceInfoPtr service) override {} |
| |
| private: |
| void OnProcessConnected(mojom::TracedProcessPtr traced_process, |
| uint32_t pid, |
| mojom::PerfettoServiceRequest service_request, |
| mojom::AgentRegistryRequest registry_request) { |
| auto result = connected_pids_.insert(pid); |
| if (!result.second) { |
| // The PID was already connected. Nothing more to do. |
| return; |
| } |
| |
| connected_pids_.insert(pid); |
| PerfettoService::GetInstance()->BindRequest(std::move(service_request), |
| pid); |
| agent_registry_->BindAgentRegistryRequest(std::move(registry_request)); |
| } |
| |
| mojo::Binding<service_manager::mojom::ServiceManagerListener> binding_{this}; |
| service_manager::Connector* const connector_; |
| AgentRegistry* const agent_registry_; |
| Coordinator* const coordinator_; |
| std::map<service_manager::Identity, uint32_t> service_pid_map_; |
| std::set<uint32_t> connected_pids_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ServiceListener); |
| }; |
| |
| TracingService::TracingService(service_manager::mojom::ServiceRequest request) |
| : service_binding_(this, std::move(request)) {} |
| |
| TracingService::~TracingService() = default; |
| |
| void TracingService::OnDisconnected() { |
| CloseAgentConnectionsAndTerminate(); |
| } |
| |
| void TracingService::OnStart() { |
| tracing_agent_registry_ = std::make_unique<AgentRegistry>(); |
| |
| if (TracingUsesPerfettoBackend()) { |
| auto perfetto_coordinator = std::make_unique<PerfettoTracingCoordinator>( |
| tracing_agent_registry_.get(), |
| base::BindRepeating(&TracingService::OnCoordinatorConnectionClosed, |
| base::Unretained(this))); |
| registry_.AddInterface( |
| base::BindRepeating(&PerfettoTracingCoordinator::BindCoordinatorRequest, |
| base::Unretained(perfetto_coordinator.get()))); |
| tracing_coordinator_ = std::move(perfetto_coordinator); |
| } else { |
| auto tracing_coordinator = std::make_unique<Coordinator>( |
| tracing_agent_registry_.get(), |
| base::BindRepeating(&TracingService::OnCoordinatorConnectionClosed, |
| base::Unretained(this))); |
| registry_.AddInterface( |
| base::BindRepeating(&Coordinator::BindCoordinatorRequest, |
| base::Unretained(tracing_coordinator.get()))); |
| tracing_coordinator_ = std::move(tracing_coordinator); |
| } |
| |
| registry_.AddInterface( |
| base::BindRepeating(&ConsumerHost::BindConsumerRequest, |
| base::Unretained(PerfettoService::GetInstance()))); |
| |
| service_listener_ = std::make_unique<ServiceListener>( |
| service_binding_.GetConnector(), tracing_agent_registry_.get(), |
| tracing_coordinator_.get()); |
| } |
| |
| void TracingService::OnBindInterface( |
| const service_manager::BindSourceInfo& source_info, |
| const std::string& interface_name, |
| mojo::ScopedMessagePipeHandle interface_pipe) { |
| registry_.BindInterface(interface_name, std::move(interface_pipe), |
| source_info); |
| } |
| |
| void TracingService::OnCoordinatorConnectionClosed() { |
| service_binding_.RequestClose(); |
| } |
| |
| void TracingService::CloseAgentConnectionsAndTerminate() { |
| tracing_agent_registry_->DisconnectAllAgents(); |
| Terminate(); |
| } |
| |
| } // namespace tracing |