blob: 3e0b57e84ffc51c475dc7aba555d1417bddad5f4 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/tracing/public/cpp/trace_startup.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/memory/shared_memory_switch.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_log.h"
#include "base/trace_event/trace_session_observer.h"
#include "build/build_config.h"
#include "components/tracing/common/tracing_switches.h"
#include "services/tracing/public/cpp/perfetto/perfetto_config.h"
#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
#include "services/tracing/public/cpp/perfetto/shared_memory.h"
#include "services/tracing/public/cpp/perfetto/traced_value_proto_writer.h"
#include "services/tracing/public/cpp/trace_event_args_allowlist.h"
#include "services/tracing/public/cpp/trace_startup_config.h"
#include "services/tracing/public/cpp/tracing_features.h"
#include "third_party/perfetto/include/perfetto/tracing/track.h"
#if BUILDFLAG(IS_WIN)
#include "components/tracing/common/etw_export_win.h"
#endif
#if BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_IOS_TVOS)
#include "base/apple/mach_port_rendezvous.h"
#endif
namespace tracing {
namespace {
#if BUILDFLAG(IS_APPLE)
using base::shared_memory::SharedMemoryMachPortRendezvousKey;
constexpr SharedMemoryMachPortRendezvousKey kTraceConfigRendezvousKey = 'trcc';
constexpr SharedMemoryMachPortRendezvousKey kTraceBufferRendezvousKey = 'trbc';
#endif
using base::trace_event::TraceConfig;
using base::trace_event::TraceLog;
class StartupTrackEventConfigObserver
: public perfetto::TrackEventSessionObserver {
public:
static StartupTrackEventConfigObserver& GetInstance() {
static base::NoDestructor<StartupTrackEventConfigObserver> instance;
return *instance;
}
StartupTrackEventConfigObserver() {
base::TrackEvent::AddSessionObserver(this);
}
// perfetto::TrackEventSessionObserver implementation.
void OnSetup(const perfetto::DataSourceBase::SetupArgs& args) override {
if (args.backend_type != perfetto::kCustomBackend ||
args.config->has_interceptor_config()) {
return;
}
base::AutoLock lock(lock_);
track_event_sessions_.emplace(args.internal_instance_index,
TrackEventSession(false, *args.config));
}
void OnStart(const perfetto::DataSourceBase::StartArgs& args) override {
base::AutoLock lock(lock_);
auto it = track_event_sessions_.find(args.internal_instance_index);
if (it != track_event_sessions_.end()) {
it->second.started = true;
}
}
void OnStop(const perfetto::DataSourceBase::StopArgs& args) override {
base::AutoLock lock(lock_);
track_event_sessions_.erase(args.internal_instance_index);
}
std::optional<perfetto::DataSourceConfig> GetTrackEventConfig() {
base::AutoLock lock(lock_);
for (const auto& [session_id, session] : track_event_sessions_) {
if (session.started) {
return session.config;
}
}
return std::nullopt;
}
private:
~StartupTrackEventConfigObserver() override {
base::TrackEvent::RemoveSessionObserver(this);
}
struct TrackEventSession {
bool started;
perfetto::DataSourceConfig config;
};
base::Lock lock_;
base::flat_map<uint32_t, TrackEventSession> track_event_sessions_
GUARDED_BY(lock_);
};
} // namespace
bool g_tracing_initialized = false;
bool IsTracingInitialized() {
return g_tracing_initialized;
}
void InitTracing(
bool enable_consumer,
bool will_trace_thread_restart,
bool enable_system_backend,
base::RepeatingCallback<bool()> allow_system_tracing_consumer) {
DCHECK(!g_tracing_initialized);
g_tracing_initialized = true;
base::TimeTicks init_start = base::TimeTicks::Now();
std::optional<uint64_t> maybe_process_track_uuid;
auto* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kTraceProcessTrackUuid)) {
uint64_t process_track_uuid;
if (base::StringToUint64(
command_line->GetSwitchValueASCII(switches::kTraceProcessTrackUuid),
&process_track_uuid)) {
maybe_process_track_uuid = process_track_uuid;
}
}
// Create the PerfettoTracedProcess.
auto& traced_process =
PerfettoTracedProcess::MaybeCreateInstance(will_trace_thread_restart);
if (allow_system_tracing_consumer) {
traced_process.SetAllowSystemTracingConsumerCallback(
std::move(allow_system_tracing_consumer));
}
traced_process.SetupClientLibrary(enable_consumer, enable_system_backend,
maybe_process_track_uuid);
RegisterTracedValueProtoWriter();
// Ensure TraceLog is initialized first.
// https://crbug.com/764357
TraceLog::GetInstance();
StartupTrackEventConfigObserver::GetInstance();
base::trace_event::TraceSessionObserverList::Initialize();
#if BUILDFLAG(IS_WIN)
tracing::EnableETWExport();
#endif // BUILDFLAG(IS_WIN)
auto& startup_config = TraceStartupConfig::GetInstance();
if (startup_config.IsEnabled()) {
auto perfetto_config = startup_config.GetPerfettoConfig();
perfetto::Tracing::SetupStartupTracingOpts opts;
opts.timeout_ms = kStartupTracingTimeoutMs;
// TODO(khokhlov): Support startup tracing with the system backend in the
// SDK build.
opts.backend = perfetto::kCustomBackend;
perfetto::Tracing::SetupStartupTracingBlocking(perfetto_config, opts);
}
base::UmaHistogramTimes("Tracing.Init.InitTracing",
base::TimeTicks::Now() - init_start);
}
void InitTracingPostFeatureList(
bool enable_consumer,
bool will_trace_thread_restart,
base::RepeatingCallback<bool()> allow_system_tracing_consumer) {
DCHECK(base::FeatureList::GetInstance());
InitTracing(enable_consumer, will_trace_thread_restart,
ShouldSetupSystemTracing(),
std::move(allow_system_tracing_consumer));
}
base::ReadOnlySharedMemoryRegion CreateTracingConfigSharedMemory() {
const auto& startup_config = TraceStartupConfig::GetInstance();
perfetto::TraceConfig trace_config;
if (startup_config.IsEnabled()) {
trace_config = startup_config.GetPerfettoConfig();
} else if (auto maybe_config = StartupTrackEventConfigObserver::GetInstance()
.GetTrackEventConfig();
maybe_config.has_value()) {
*trace_config.add_data_sources()->mutable_config() = *maybe_config;
} else {
return base::ReadOnlySharedMemoryRegion();
}
std::vector<uint8_t> serialized_config = trace_config.SerializeAsArray();
base::MappedReadOnlyRegion shm =
base::ReadOnlySharedMemoryRegion::Create(serialized_config.size());
if (!shm.IsValid()) {
return base::ReadOnlySharedMemoryRegion();
}
base::span(shm.mapping).copy_from(serialized_config);
return std::move(shm.region);
}
base::UnsafeSharedMemoryRegion CreateTracingOutputSharedMemory() {
auto shm = base::UnsafeSharedMemoryRegion::Create(
features::kPerfettoSharedMemorySizeBytes.Get());
if (!shm.IsValid()) {
return base::UnsafeSharedMemoryRegion();
}
return shm;
}
void COMPONENT_EXPORT(TRACING_CPP) AddTraceConfigToLaunchParameters(
const base::ReadOnlySharedMemoryRegion& read_only_memory_region,
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
base::GlobalDescriptors::Key descriptor_key,
base::ScopedFD& out_descriptor_to_share,
#endif
base::CommandLine* command_line,
base::LaunchOptions* launch_options) {
base::shared_memory::AddToLaunchParameters(switches::kTraceConfigHandle,
read_only_memory_region,
#if BUILDFLAG(IS_APPLE)
kTraceConfigRendezvousKey,
#elif BUILDFLAG(IS_POSIX)
descriptor_key,
out_descriptor_to_share,
#endif
command_line, launch_options);
}
void COMPONENT_EXPORT(TRACING_CPP) AddTraceOutputToLaunchParameters(
const base::UnsafeSharedMemoryRegion& unsafe_memory_region,
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
base::GlobalDescriptors::Key descriptor_key,
base::ScopedFD& out_descriptor_to_share,
#endif
base::CommandLine* command_line,
base::LaunchOptions* launch_options) {
base::shared_memory::AddToLaunchParameters(switches::kTraceBufferHandle,
unsafe_memory_region,
#if BUILDFLAG(IS_APPLE)
kTraceBufferRendezvousKey,
#elif BUILDFLAG(IS_POSIX)
descriptor_key,
out_descriptor_to_share,
#endif
command_line, launch_options);
}
} // namespace tracing