0

[tracing] Add a global trace thread for PerfettoTracedProcess

This allows tracing to be logged before ThreadPoolInstance is Set for
child process.

This is [2/3] CL of enabling tracing prior to sandboxing.

Bug: 380411640
Change-Id: I3e0a976d0e8f316d275eca8a6ab7cee2f546fd7c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6180638
Reviewed-by: Colin Blundell <blundell@chromium.org>
Reviewed-by: Alexander Timin <altimin@chromium.org>
Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org>
Commit-Queue: Kramer Ge <fangzhoug@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1421972}
This commit is contained in:
Kramer Ge
2025-02-19 08:14:01 -08:00
committed by Chromium LUCI CQ
parent a4afb7b0b3
commit 5cccc376fe
20 changed files with 134 additions and 38 deletions

@ -56,11 +56,11 @@ std::unique_ptr<perfetto::base::TaskRunner> PerfettoPlatform::CreateTaskRunner(
return perfetto_task_runner;
}
void PerfettoPlatform::ResetTaskRunnerForTesting(
void PerfettoPlatform::ResetTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
task_runner_ = task_runner;
if (perfetto_task_runner_) {
perfetto_task_runner_->ResetTaskRunnerForTesting(task_runner); // IN-TEST
perfetto_task_runner_->ResetTaskRunner(task_runner);
}
}

@ -34,8 +34,7 @@ class BASE_EXPORT PerfettoPlatform : public perfetto::Platform {
// thread IDs.
perfetto::base::PlatformThreadId GetCurrentThreadId() override;
void ResetTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> task_runner);
void ResetTaskRunner(scoped_refptr<base::SequencedTaskRunner> task_runner);
private:
WeakPtr<PerfettoTaskRunner> perfetto_task_runner_;

@ -114,7 +114,7 @@ void PerfettoTaskRunner::RemoveFileDescriptorWatch(
#endif // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
}
void PerfettoTaskRunner::ResetTaskRunnerForTesting(
void PerfettoTaskRunner::ResetTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
task_runner_ = std::move(task_runner);
}

@ -49,7 +49,7 @@ class BASE_EXPORT PerfettoTaskRunner : public perfetto::base::TaskRunner {
std::function<void()>) override;
void RemoveFileDescriptorWatch(perfetto::base::PlatformHandle) override;
void ResetTaskRunnerForTesting(scoped_refptr<base::SequencedTaskRunner>);
void ResetTaskRunner(scoped_refptr<base::SequencedTaskRunner>);
WeakPtr<PerfettoTaskRunner> GetWeakPtr() {
return weak_factory_.GetWeakPtr();

@ -128,8 +128,7 @@ bool Delegate::PreRun() {
"elevated_tracing_service");
// Initialize tracing in the process.
tracing::InitTracingPostThreadPoolStartAndFeatureList(
/*enable_consumer=*/false);
tracing::InitTracingPostFeatureList(/*enable_consumer=*/false);
// Create the global SessionRegistry.
session_registry_ = base::MakeRefCounted<SessionRegistry>();

@ -1233,8 +1233,7 @@ int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params,
tracing::PerfettoTracedProcess::Get().SetAllowSystemTracingConsumerCallback(
base::BindRepeating(&ShouldAllowSystemTracingConsumer));
tracing::InitTracingPostThreadPoolStartAndFeatureList(
/* enable_consumer */ true);
tracing::InitTracingPostFeatureList(/*enable_consumer=*/true);
// PowerMonitor is needed in reduced mode. BrowserMainLoop will safely skip
// initializing it again if it has already been initialized.

@ -104,8 +104,7 @@ ChildProcess::ChildProcess(base::ThreadType io_thread_type,
initialized_thread_pool_ = true;
}
tracing::InitTracingPostThreadPoolStartAndFeatureList(
/* enable_consumer */ false);
tracing::InitTracingPostFeatureList(/*enable_consumer=*/false);
// Ensure the visibility tracker is created on the main thread.
ProcessVisibilityTracker::GetInstance();

@ -617,8 +617,7 @@ void BrowserTestBase::SetUp() {
StartBrowserThreadPool();
tracing::InitTracingPostThreadPoolStartAndFeatureList(
/* enable_consumer */ true);
tracing::InitTracingPostFeatureList(/*enable_consumer=*/true);
InitializeBrowserMemoryInstrumentationClient();
}

@ -76,7 +76,7 @@ class CoordinatorImplTest : public testing::Test {
void SetUp() override {
coordinator_ = std::make_unique<NiceMock<FakeCoordinatorImpl>>();
tracing::PerfettoTracedProcess::DataSourceBase::ResetTaskRunnerForTesting(
tracing::PerfettoTracedProcess::DataSourceBase::ResetTaskRunner(
base::SingleThreadTaskRunner::GetCurrentDefault());
}

@ -145,7 +145,7 @@ class MemoryTracingIntegrationTest : public testing::Test {
coordinator_ = std::make_unique<MockCoordinator>(this);
TraceLog::GetInstance()->InitializePerfettoIfNeeded();
tracing::PerfettoTracedProcess::DataSourceBase::ResetTaskRunnerForTesting(
tracing::PerfettoTracedProcess::DataSourceBase::ResetTaskRunner(
base::SingleThreadTaskRunner::GetCurrentDefault());
TracingObserverProto::GetInstance()->ResetForTesting();
}

@ -45,7 +45,7 @@ class TracingObserverProtoTest : public testing::Test {
false);
memory_instrumentation::TracingObserverProto::GetInstance()
->ResetForTesting();
tracing::PerfettoTracedProcess::DataSourceBase::ResetTaskRunnerForTesting(
tracing::PerfettoTracedProcess::DataSourceBase::ResetTaskRunner(
base::SingleThreadTaskRunner::GetCurrentDefault());
}

@ -13,6 +13,7 @@
#include "base/no_destructor.h"
#include "base/pickle.h"
#include "base/process/current_process.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/trace_event/trace_config.h"
@ -254,6 +255,10 @@ void CustomEventRecorder::LogHistograms() {
}
}
void CustomEventRecorder::DetachFromSequence() {
DETACH_FROM_SEQUENCE(perfetto_sequence_checker_);
}
// static
void CustomEventRecorder::OnMetricsSampleCallback(
const char* histogram_name,

@ -53,6 +53,9 @@ class COMPONENT_EXPORT(TRACING_CPP) CustomEventRecorder
uint64_t name_hash,
base::HistogramBase::Sample32 sample);
bool IsPrivacyFilteringEnabled();
// Thread can restart in Linux and ChromeOS when entering sandbox, so rebind
// sequence checker.
void DetachFromSequence();
private:
friend class base::NoDestructor<CustomEventRecorder>;

@ -12,8 +12,10 @@
#include "base/synchronization/waitable_event.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread.h"
#include "base/trace_event/trace_config.h"
#include "base/tracing/perfetto_platform.h"
#include "base/tracing/perfetto_task_runner.h"
#include "build/build_config.h"
#include "services/tracing/public/cpp/perfetto/custom_event_recorder.h"
#include "services/tracing/public/cpp/perfetto/metadata_data_source.h"
@ -163,11 +165,31 @@ PerfettoTracedProcess::DataSourceBase::GetTaskRunner() {
return GetDataSourceTaskRunner().get();
}
void PerfettoTracedProcess::DataSourceBase::ResetTaskRunnerForTesting(
void PerfettoTracedProcess::DataSourceBase::ResetTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
GetDataSourceTaskRunner() = task_runner;
}
// static
void PerfettoTracedProcess::RestartThreadInSandbox() {
base::Thread* trace_thread = PerfettoTracedProcess::GetTraceThread();
if (trace_thread->StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0))) {
DETACH_FROM_SEQUENCE(PerfettoTracedProcess::Get().sequence_checker_);
PerfettoTracedProcess::Get().task_runner_ = trace_thread->task_runner();
PerfettoTracedProcess::Get().platform_->ResetTaskRunner(
trace_thread->task_runner());
DataSourceBase::ResetTaskRunner(trace_thread->task_runner());
PerfettoTracedProcess::Get().tracing_backend_->DetachFromMuxerSequence();
CustomEventRecorder::GetInstance()->DetachFromSequence();
}
}
// static
base::Thread* PerfettoTracedProcess::GetTraceThread() {
return PerfettoTracedProcess::Get().trace_process_thread_.get();
}
// static
PerfettoTracedProcess& PerfettoTracedProcess::MaybeCreateInstance() {
static base::NoDestructor<PerfettoTracedProcess> traced_process(
@ -176,6 +198,12 @@ PerfettoTracedProcess& PerfettoTracedProcess::MaybeCreateInstance() {
return *traced_process;
}
// static
PerfettoTracedProcess& PerfettoTracedProcess::MaybeCreateInstanceWithThread() {
static base::NoDestructor<PerfettoTracedProcess> traced_process{};
return *traced_process;
}
// static
PerfettoTracedProcess& PerfettoTracedProcess::MaybeCreateInstanceForTesting() {
static base::NoDestructor<PerfettoTracedProcess> traced_process(nullptr);
@ -188,6 +216,22 @@ PerfettoTracedProcess& PerfettoTracedProcess::Get() {
return *g_instance;
}
PerfettoTracedProcess::PerfettoTracedProcess()
: trace_process_thread_(std::make_unique<base::Thread>("PerfettoTrace")),
task_runner_(trace_process_thread_->StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0))
? trace_process_thread_->task_runner()
: nullptr),
platform_(
std::make_unique<base::tracing::PerfettoPlatform>(task_runner_)),
tracing_backend_(std::make_unique<PerfettoTracingBackend>()) {
DETACH_FROM_SEQUENCE(sequence_checker_);
CHECK_EQ(g_instance, nullptr);
CHECK(task_runner_);
g_instance = this;
GetDataSourceTaskRunner() = task_runner_;
}
PerfettoTracedProcess::PerfettoTracedProcess(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: task_runner_(task_runner),
@ -227,8 +271,8 @@ void PerfettoTracedProcess::SetupForTesting(
DCHECK(!perfetto::Tracing::IsInitialized());
task_runner_ = std::move(task_runner);
platform_->ResetTaskRunnerForTesting(task_runner_); // IN-TEST
DataSourceBase::ResetTaskRunnerForTesting(task_runner_); // IN-TEST
platform_->ResetTaskRunner(task_runner_);
DataSourceBase::ResetTaskRunner(task_runner_);
tracing_backend_ = std::make_unique<PerfettoTracingBackend>();
OnThreadPoolAvailable(

@ -21,6 +21,7 @@
#include "third_party/perfetto/include/perfetto/tracing/tracing_policy.h"
namespace base {
class Thread;
namespace trace_event {
class TraceConfig;
} // namespace trace_event
@ -98,7 +99,7 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final
// allows overriding that task runner.
virtual base::SequencedTaskRunner* GetTaskRunner();
static void ResetTaskRunnerForTesting(
static void ResetTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner);
protected:
@ -151,8 +152,16 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final
perfetto::DataSourceConfig data_source_config_;
};
// Restart the trace thread and replace the task_runner for tracing.
static void RestartThreadInSandbox();
// Returns the process-wide ptr to the trace thread, returns nullptr if the
// task_runner for tracing is from the thread-pool.
static base::Thread* GetTraceThread();
// Creates the process-wide instance of the PerfettoTracedProcess.
static PerfettoTracedProcess& MaybeCreateInstance();
static PerfettoTracedProcess& MaybeCreateInstanceWithThread();
static PerfettoTracedProcess& MaybeCreateInstanceForTesting();
// Returns the process-wide instance of the PerfettoTracedProcess.
@ -222,8 +231,10 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final
private:
friend class base::NoDestructor<PerfettoTracedProcess>;
PerfettoTracedProcess(
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr);
// Default constructor would create a dedicated thread for tracing
PerfettoTracedProcess();
explicit PerfettoTracedProcess(
scoped_refptr<base::SequencedTaskRunner> task_runner);
// Initialize the Perfetto client library (i.e., perfetto::Tracing) for this
// process.
@ -247,6 +258,7 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final
bool system_consumer_enabled_for_testing_
GUARDED_BY(allow_system_consumer_lock_) = false;
std::unique_ptr<base::Thread> trace_process_thread_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// Platform implementation for the Perfetto client library.

@ -12,6 +12,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/shared_memory_switch.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/tracing/tracing_tls.h"
#include "base/unguessable_token.h"
@ -80,6 +81,8 @@ class ProducerEndpoint : public perfetto::ProducerEndpoint,
return weak_factory_.GetWeakPtr();
}
void DetachFromSequence() { DETACH_FROM_SEQUENCE(sequence_checker_); }
// perfetto::ProducerEndpoint implementation:
void Disconnect() override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@ -757,10 +760,41 @@ void PerfettoTracingBackend::OnProducerConnected(
}
}
void PerfettoTracingBackend::DetachFromMuxerSequence() {
DETACH_FROM_SEQUENCE(muxer_sequence_checker_);
#if DCHECK_IS_ON()
perfetto::base::TaskRunner* task_runner;
{
base::AutoLock lock(task_runner_lock_);
task_runner = muxer_task_runner_;
}
// Must reset sequence_checker on `task_runner`, because `weak_this` and
// `producer_endpoint_` needs to bind there.
task_runner->PostTask([weak_this = weak_factory_.GetWeakPtr()] {
// Can be destroyed in testing.
if (weak_this && weak_this->producer_endpoint_) {
weak_this->producer_endpoint_->DetachFromSequence();
}
});
#endif // DCHECK_IS_ON()
}
void PerfettoTracingBackend::BindProducerConnectionIfNecessary() {
DCHECK_CALLED_ON_VALID_SEQUENCE(muxer_sequence_checker_);
if (!producer_endpoint_)
{
base::AutoLock lock(task_runner_lock_);
// Check service existence first because mojo is initialized after
// `muxer_task_runner_` resets. So we can avoid binding `sequence_checker`
// in `base::WeakPtr` of `producer_endpoint_` before task resets.
if (!perfetto_service_) {
return;
}
}
if (!producer_endpoint_) {
return;
}
mojo::PendingRemote<mojom::PerfettoService> perfetto_service;
{
@ -768,10 +802,8 @@ void PerfettoTracingBackend::BindProducerConnectionIfNecessary() {
perfetto_service = std::move(perfetto_service_);
}
if (perfetto_service) {
producer_endpoint_->BindConnection(muxer_task_runner_,
std::move(perfetto_service));
}
producer_endpoint_->BindConnection(muxer_task_runner_,
std::move(perfetto_service));
}
void PerfettoTracingBackend::CreateConsumerConnection(

@ -50,6 +50,12 @@ class PerfettoTracingBackend : public perfetto::TracingBackend {
void SetConsumerConnectionFactory(ConsumerConnectionFactory,
scoped_refptr<base::SequencedTaskRunner>);
// Only called at maximum once. When the platform thread running
// `muxer_task_runner_` restarts in sandbox, detaches
// `muxer_sequence_checker_` as well as `ProducerEndpoint`'s
// `sequence_checker_`.
void DetachFromMuxerSequence();
// perfetto::TracingBackend implementation:
std::unique_ptr<perfetto::ProducerEndpoint> ConnectProducer(
const ConnectProducerArgs&) override;

@ -46,10 +46,10 @@ using base::trace_event::TraceLog;
} // namespace
bool g_tracing_initialized_after_threadpool_and_featurelist = false;
bool g_tracing_initialized_after_featurelist = false;
bool IsTracingInitialized() {
return g_tracing_initialized_after_threadpool_and_featurelist;
return g_tracing_initialized_after_featurelist;
}
void EnableStartupTracingIfNeeded() {
@ -98,11 +98,11 @@ bool EnableStartupTracingForProcess(
return true;
}
void InitTracingPostThreadPoolStartAndFeatureList(bool enable_consumer) {
if (g_tracing_initialized_after_threadpool_and_featurelist)
void InitTracingPostFeatureList(bool enable_consumer) {
if (g_tracing_initialized_after_featurelist) {
return;
g_tracing_initialized_after_threadpool_and_featurelist = true;
DCHECK(base::ThreadPoolInstance::Get());
}
g_tracing_initialized_after_featurelist = true;
DCHECK(base::FeatureList::GetInstance());
// Create the PerfettoTracedProcess.

@ -22,7 +22,7 @@ class CommandLine;
namespace tracing {
// Returns true if InitTracingPostThreadPoolStartAndFeatureList has been called
// Returns true if `InitTracingPostFeatureList()` has been called
// for this process.
bool COMPONENT_EXPORT(TRACING_CPP) IsTracingInitialized();
@ -52,7 +52,7 @@ bool COMPONENT_EXPORT(TRACING_CPP)
// |enable_consumer| should be true if the system consumer can be enabled.
// Currently this is only the case if this is running in the browser process.
void COMPONENT_EXPORT(TRACING_CPP)
InitTracingPostThreadPoolStartAndFeatureList(bool enable_consumer);
InitTracingPostFeatureList(bool enable_consumer);
// If tracing is enabled, grabs the current trace config & mode and tells the
// child to begin tracing right away via startup tracing command line flags.

@ -68,8 +68,7 @@ MULTIPROCESS_TEST_MAIN(InitFromLaunchParameters) {
#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_FUCHSIA)
base::FeatureList::InitInstance("", "");
base::ThreadPoolInstance::CreateAndStartWithDefaultParams("StartupTraceTest");
tracing::InitTracingPostThreadPoolStartAndFeatureList(
/*enable_consumer=*/false);
tracing::InitTracingPostFeatureList(/*enable_consumer=*/false);
// Simulate launching with the serialized parameters.
EnableStartupTracingIfNeeded();