#include "services/tracing/perfetto/producer_host.h"
#include <utility>
#include "base/compiler_specific.h"
#include "base/functional/bind.h"
#include "base/process/process.h"
#include "build/build_config.h"
#include "services/tracing/perfetto/perfetto_service.h"
#include "services/tracing/public/cpp/perfetto/shared_memory.h"
#include "third_party/perfetto/include/perfetto/ext/tracing/core/client_identity.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() = default;
ProducerHost::~ProducerHost() {
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));
if (!shm->start()) {
return InitializationResult::kSmbMappingFailed;
}
size_t shm_size = shm->size();
ChromeBaseSharedMemory* shm_raw = shm.get();
producer_endpoint_ = service->ConnectProducer(
this,
perfetto::ClientIdentity(0,
perfetto::base::kInvalidPid),
name, shm_size,
false,
perfetto::TracingService::ProducerSMBScrapingMode::kDefault,
shared_memory_buffer_page_size_bytes, std::move(shm));
if (!producer_endpoint_) {
return InitializationResult::kProducerEndpointConstructionFailed;
}
if (producer_endpoint_->shared_memory() != shm_raw) {
return InitializationResult::kSmbNotAdopted;
}
return InitializationResult::kSuccess;
}
void ProducerHost::OnConnect() {
}
void ProducerHost::OnDisconnect() {
}
void ProducerHost::OnTracingSetup() {
producer_client_->OnTracingStart();
}
void ProducerHost::SetupDataSource(perfetto::DataSourceInstanceID,
const perfetto::DataSourceConfig&) {
}
void ProducerHost::StartDataSource(perfetto::DataSourceInstanceID id,
const perfetto::DataSourceConfig& config) {
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,
perfetto::FlushFlags ) {
DCHECK(producer_client_);
std::vector<uint64_t> data_source_ids(
raw_data_source_ids, UNSAFE_TODO(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();
}
void ProducerHost::CommitData(const perfetto::CommitDataRequest& data_request,
CommitDataCallback callback) {
if (on_commit_callback_for_testing_) {
on_commit_callback_for_testing_.Run(data_request);
}
producer_endpoint_->CommitData(data_request, [&callback]() {
std::move(callback).Run();
});
DCHECK(!callback);
}
void ProducerHost::RegisterDataSource(
const perfetto::DataSourceDescriptor& registration_info) {
producer_endpoint_->RegisterDataSource(registration_info);
}
void ProducerHost::UpdateDataSource(
const perfetto::DataSourceDescriptor& registration_info) {
producer_endpoint_->UpdateDataSource(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);
}
}