blob: 6046f20a28ce0e60d5a9d178879bbf6459afee7f [file] [log] [blame]
// Copyright 2019 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 "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/tracing/common/trace_startup_config.h"
#include "components/tracing/common/tracing_switches.h"
#include "content/browser/tracing/perfetto_file_tracer.h"
#include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "services/tracing/perfetto/privacy_filtering_check.h"
#include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
#include "services/tracing/public/cpp/trace_startup.h"
#include "services/tracing/public/cpp/tracing_features.h"
namespace content {
namespace {
// Wait until |condition| returns true.
void WaitForCondition(base::RepeatingCallback<bool()> condition,
const std::string& description) {
const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(15);
const base::TimeTicks start_time = base::TimeTicks::Now();
while (!condition.Run() && (base::TimeTicks::Now() - start_time < kTimeout)) {
base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
run_loop.Run();
}
ASSERT_TRUE(condition.Run())
<< "Timeout waiting for condition: " << description;
}
} // namespace
class CommandlineStartupTracingTest : public ContentBrowserTest {
public:
CommandlineStartupTracingTest() = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
base::CreateTemporaryFile(&temp_file_path_);
command_line->AppendSwitch(switches::kTraceStartup);
command_line->AppendSwitchASCII(switches::kTraceStartupDuration, "3");
command_line->AppendSwitchASCII(switches::kTraceStartupFile,
temp_file_path_.AsUTF8Unsafe());
#if defined(OS_ANDROID)
// On Android the startup tracing is initialized as soon as library load
// time, earlier than this point. So, reset the config and enable startup
// tracing here.
tracing::TraceStartupConfig::GetInstance()->EnableFromCommandLine();
tracing::EnableStartupTracingIfNeeded();
#endif
}
protected:
base::FilePath temp_file_path_;
private:
DISALLOW_COPY_AND_ASSIGN(CommandlineStartupTracingTest);
};
IN_PROC_BROWSER_TEST_F(CommandlineStartupTracingTest, TestStartupTracing) {
NavigateToURL(shell(), GetTestUrl("", "title1.html"));
WaitForCondition(base::BindRepeating([]() {
return !TracingController::GetInstance()->IsTracing();
}),
"trace end");
EXPECT_FALSE(tracing::TraceStartupConfig::GetInstance()->IsEnabled());
EXPECT_FALSE(TracingController::GetInstance()->IsTracing());
WaitForCondition(base::BindRepeating([]() {
return tracing::TraceStartupConfig::GetInstance()
->finished_writing_to_file_for_testing();
}),
"finish file write");
std::string trace;
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(temp_file_path_, &trace));
EXPECT_TRUE(
trace.find("TracingControllerImpl::InitStartupTracingForDuration") !=
std::string::npos);
}
class StartupTracingInProcessTest : public ContentBrowserTest {
public:
StartupTracingInProcessTest() {
scoped_feature_list_.InitWithFeatures(
/*enabled_features=*/{features::kTracingPerfettoBackend,
features::kTracingServiceInProcess},
/*disabled_features=*/{});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
class LargeTraceEventData : public base::trace_event::ConvertableToTraceFormat {
public:
LargeTraceEventData() = default;
~LargeTraceEventData() override = default;
const size_t kLargeMessageSize = 100 * 1024;
void AppendAsTraceFormat(std::string* out) const override {
std::string large_string(kLargeMessageSize, '.');
out->append(large_string);
}
private:
DISALLOW_COPY_AND_ASSIGN(LargeTraceEventData);
};
// This will fill a massive amount of startup tracing data into a
// StartupTraceWriter, which Perfetto will then have to sync copy into
// the SMB once the full tracing service starts up. This is to catch common
// deadlocks.
IN_PROC_BROWSER_TEST_F(StartupTracingInProcessTest, TestFilledStartupBuffer) {
tracing::TraceEventDataSource::GetInstance()->SetupStartupTracing(
/*privacy_filtering_enabled=*/false);
auto config = tracing::TraceStartupConfig::GetInstance()
->GetDefaultBrowserStartupConfig();
uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
base::trace_event::TraceLog::GetInstance()->SetEnabled(config, modes);
for (int i = 0; i < 1024; ++i) {
auto data = std::make_unique<LargeTraceEventData>();
TRACE_EVENT1("toplevel", "bar", "data", std::move(data));
}
config.SetTraceBufferSizeInKb(12);
base::RunLoop wait_for_tracing;
TracingControllerImpl::GetInstance()->StartTracing(
config, wait_for_tracing.QuitClosure());
wait_for_tracing.Run();
NavigateToURL(shell(), GetTestUrl("", "title1.html"));
base::RunLoop wait_for_stop;
TracingControllerImpl::GetInstance()->StopTracing(
TracingController::CreateStringEndpoint(base::BindRepeating(
[](base::RepeatingClosure quit_callback,
std::unique_ptr<const base::DictionaryValue> metadata,
base::RefCountedString* data) { quit_callback.Run(); },
wait_for_stop.QuitClosure())));
wait_for_stop.Run();
}
class BackgroundStartupTracingTest : public ContentBrowserTest {
public:
BackgroundStartupTracingTest() = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
base::CreateTemporaryFile(&temp_file_path_);
auto* startup_config = tracing::TraceStartupConfig::GetInstance();
startup_config->enable_background_tracing_for_testing_ = true;
startup_config->EnableFromBackgroundTracing();
startup_config->startup_duration_ = 3;
tracing::EnableStartupTracingIfNeeded();
command_line->AppendSwitchASCII(switches::kPerfettoOutputFile,
temp_file_path_.AsUTF8Unsafe());
}
protected:
base::FilePath temp_file_path_;
private:
DISALLOW_COPY_AND_ASSIGN(BackgroundStartupTracingTest);
};
#if !defined(OS_ANDROID)
#define MAYBE_TestStartupTracing DISABLED_TestStartupTracing
#else
#define MAYBE_TestStartupTracing TestStartupTracing
#endif
IN_PROC_BROWSER_TEST_F(BackgroundStartupTracingTest, MAYBE_TestStartupTracing) {
NavigateToURL(shell(), GetTestUrl("", "title1.html"));
EXPECT_FALSE(tracing::TraceStartupConfig::GetInstance()->IsEnabled());
EXPECT_FALSE(TracingController::GetInstance()->IsTracing());
WaitForCondition(base::BindRepeating([]() {
return TracingControllerImpl::GetInstance()
->perfetto_file_tracer_for_testing()
->is_finished_for_testing();
}),
"finish file write");
std::string trace;
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(temp_file_path_, &trace));
tracing::PrivacyFilteringCheck checker;
checker.CheckProtoForUnexpectedFields(trace);
EXPECT_GT(checker.stats().track_event, 0u);
EXPECT_EQ(checker.stats().process_desc, 0u);
EXPECT_GT(checker.stats().thread_desc, 0u);
EXPECT_TRUE(checker.stats().has_interned_names);
EXPECT_TRUE(checker.stats().has_interned_categories);
EXPECT_TRUE(checker.stats().has_interned_source_locations);
}
} // namespace content