#include "content/web_test/browser/web_test_tracing_controller.h"
#include "base/compiler_specific.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_config.h"
#include "services/tracing/public/cpp/perfetto/perfetto_config.h"
#include "third_party/perfetto/include/perfetto/tracing/tracing.h"
namespace content {
WebTestTracingController::WebTestTracingController(
base::FilePath trace_file_path)
: trace_file_path_(std::move(trace_file_path)) {}
WebTestTracingController::~WebTestTracingController() {
CHECK(!tracing_file_.IsValid());
CHECK(!tracing_session_);
CHECK(!stop_tracing_run_loop_.has_value());
CHECK(!tracing_is_stopping_);
}
void WebTestTracingController::StartTracing() {
CHECK(!tracing_session_);
CHECK(!tracing_file_.IsValid());
perfetto::TraceConfig trace_config =
tracing::GetDefaultPerfettoConfig(base::trace_event::TraceConfig(
"*", base::trace_event::RECORD_UNTIL_FULL));
tracing_session_ =
perfetto::Tracing::NewTrace(perfetto::BackendType::kCustomBackend);
#if BUILDFLAG(IS_WIN)
tracing_session_->Setup(trace_config);
#else
{
base::ScopedAllowBlockingForTesting allow_blocking;
tracing_file_.Initialize(trace_file_path_, base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE);
}
tracing_session_->Setup(trace_config, tracing_file_.GetPlatformFile());
#endif
scoped_refptr<base::SequencedTaskRunner> task_runner(
base::SingleThreadTaskRunner::GetCurrentDefault());
tracing_session_->SetOnStopCallback([this, task_runner]() {
task_runner->PostTask(
FROM_HERE, base::BindOnce(&WebTestTracingController::OnTracingStopped,
base::Unretained(this)));
});
base::RunLoop run_loop;
tracing_session_->SetOnStartCallback([&run_loop]() { run_loop.Quit(); });
tracing_session_->Start();
run_loop.Run();
}
void WebTestTracingController::StopTracing() {
if (tracing_session_) {
CHECK(!stop_tracing_run_loop_.has_value());
stop_tracing_run_loop_.emplace();
if (!tracing_is_stopping_) {
tracing_is_stopping_ = true;
tracing_session_->Stop();
}
stop_tracing_run_loop_->Run();
stop_tracing_run_loop_.reset();
}
}
void WebTestTracingController::OnTracingStopped() {
#if BUILDFLAG(IS_WIN)
tracing_is_stopping_ = true;
{
base::ScopedAllowBlockingForTesting allow_blocking;
tracing_file_.Initialize(trace_file_path_, base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE);
}
tracing_session_->ReadTrace(
[this](perfetto::TracingSession::ReadTraceCallbackArgs args) {
CHECK(tracing_file_.IsValid());
if (args.size > 0) {
UNSAFE_TODO(tracing_file_.WriteAtCurrentPos(args.data, args.size));
}
if (!args.has_more) {
TracingFinished();
}
});
#else
TracingFinished();
#endif
}
void WebTestTracingController::TracingFinished() {
tracing_is_stopping_ = false;
tracing_session_.reset();
{
base::ScopedAllowBlockingForTesting allow_blocking;
tracing_file_.Close();
}
tracing_file_ = base::File();
if (stop_tracing_run_loop_.has_value()) {
stop_tracing_run_loop_->Quit();
}
}
}