| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/tracing/chrome_tracing_delegate.h" |
| |
| #include <string_view> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/files/file_enumerator.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_path_watcher.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/json/json_writer.h" |
| #include "base/path_service.h" |
| #include "base/run_loop.h" |
| #include "base/strings/pattern.h" |
| #include "base/test/bind.h" |
| #include "base/test/test_proto_loader.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/trace_event/named_trigger.h" |
| #include "build/build_config.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "components/metrics/metrics_pref_names.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/tracing/common/background_tracing_state_manager.h" |
| #include "components/tracing/common/pref_names.h" |
| #include "content/public/browser/background_tracing_manager.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/tracing_controller.h" |
| #include "content/public/test/background_tracing_test_support.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/test_utils.h" |
| #include "services/tracing/public/cpp/trace_startup_config.h" |
| #include "services/tracing/public/cpp/tracing_features.h" |
| |
| namespace { |
| |
| class TestBackgroundTracingHelper |
| : public content::BackgroundTracingManager::EnabledStateTestObserver { |
| public: |
| TestBackgroundTracingHelper() { |
| content::AddBackgroundTracingEnabledStateObserverForTesting(this); |
| } |
| |
| ~TestBackgroundTracingHelper() { |
| content::RemoveBackgroundTracingEnabledStateObserverForTesting(this); |
| } |
| |
| void OnScenarioActive(const std::string& scenario_name) override { |
| wait_for_scenario_active_.Quit(); |
| } |
| |
| void OnScenarioIdle(const std::string& scenario_name) override { |
| wait_for_scenario_idle_.Quit(); |
| } |
| |
| void OnTraceReceived(const std::string& proto_content) override { |
| wait_for_trace_received_.Quit(); |
| } |
| |
| void WaitForScenarioActive() { wait_for_scenario_active_.Run(); } |
| void WaitForScenarioIdle() { wait_for_scenario_idle_.Run(); } |
| void WaitForTraceReceived() { wait_for_trace_received_.Run(); } |
| |
| private: |
| base::RunLoop wait_for_scenario_active_; |
| base::RunLoop wait_for_scenario_idle_; |
| base::RunLoop wait_for_trace_received_; |
| }; |
| |
| } // namespace |
| |
| namespace tracing { |
| |
| perfetto::protos::gen::ChromeFieldTracingConfig ParseFieldTracingConfigFromText( |
| const std::string& proto_text) { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| base::TestProtoLoader config_loader( |
| base::PathService::CheckedGet(base::DIR_GEN_TEST_DATA_ROOT) |
| .Append( |
| FILE_PATH_LITERAL("third_party/perfetto/protos/perfetto/" |
| "config/chrome/scenario_config.descriptor")), |
| "perfetto.protos.ChromeFieldTracingConfig"); |
| std::string serialized_message; |
| config_loader.ParseFromText(proto_text, serialized_message); |
| perfetto::protos::gen::ChromeFieldTracingConfig destination; |
| destination.ParseFromString(serialized_message); |
| return destination; |
| } |
| |
| class ChromeTracingDelegateBrowserTest : public InProcessBrowserTest { |
| public: |
| ChromeTracingDelegateBrowserTest() = default; |
| |
| void SetUpOnMainThread() override { |
| InProcessBrowserTest::SetUpOnMainThread(); |
| |
| PrefService* local_state = g_browser_process->local_state(); |
| DCHECK(local_state); |
| local_state->SetBoolean(metrics::prefs::kMetricsReportingEnabled, true); |
| content::TracingController::GetInstance(); // Create tracing agents. |
| } |
| |
| bool StartScenario( |
| content::BackgroundTracingManager::DataFiltering data_filtering) { |
| constexpr const char kScenarioConfig[] = R"pb( |
| scenarios: { |
| scenario_name: "test_scenario" |
| start_rules: { manual_trigger_name: "start_trigger" } |
| upload_rules: { manual_trigger_name: "upload_trigger" } |
| trace_config: { |
| data_sources: { |
| config: { |
| name: "track_event" |
| track_event_config: { |
| disabled_categories: [ "*" ], |
| enabled_categories: [ "toplevel" ] |
| } |
| } |
| } |
| data_sources: { config: { name: "org.chromium.trace_metadata2" } } |
| } |
| } |
| )pb"; |
| |
| EXPECT_TRUE(content::BackgroundTracingManager::GetInstance() |
| .InitializeFieldScenarios( |
| ParseFieldTracingConfigFromText(kScenarioConfig), |
| data_filtering, false, 0)); |
| |
| return base::trace_event::EmitNamedTrigger("start_trigger"); |
| } |
| |
| void TriggerPreemptiveScenario( |
| const std::string& trigger_name = "upload_trigger") { |
| base::trace_event::EmitNamedTrigger(trigger_name); |
| } |
| }; |
| |
| std::string GetSessionStateJson() { |
| PrefService* local_state = g_browser_process->local_state(); |
| DCHECK(local_state); |
| const base::Value::Dict& state = |
| local_state->GetDict(tracing::kBackgroundTracingSessionState); |
| std::string json; |
| EXPECT_TRUE(base::JSONWriter::Write(state, &json)); |
| return json; |
| } |
| |
| void SetSessionState(base::Value::Dict dict) { |
| PrefService* local_state = g_browser_process->local_state(); |
| local_state->Set(tracing::kBackgroundTracingSessionState, |
| base::Value(std::move(dict))); |
| } |
| |
| // If we need a PII-stripped trace, any existing OTR session should block the |
| // trace. |
| IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest, |
| ExistingIncognitoSessionBlockingTraceStart) { |
| EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_NEW_INCOGNITO_WINDOW)); |
| EXPECT_TRUE(BrowserList::IsOffTheRecordBrowserActive()); |
| EXPECT_FALSE( |
| StartScenario(content::BackgroundTracingManager::ANONYMIZE_DATA)); |
| } |
| |
| // If we need a PII-stripped trace, OTR sessions that ended before tracing |
| // should block the trace (because traces could theoretically include stale |
| // memory from those sessions). |
| IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest, |
| FinishedIncognitoSessionBlockingTraceStart) { |
| Browser* incognito_browser = CreateIncognitoBrowser(browser()->profile()); |
| EXPECT_TRUE(BrowserList::IsOffTheRecordBrowserActive()); |
| CloseBrowserSynchronously(incognito_browser); |
| EXPECT_FALSE(BrowserList::IsOffTheRecordBrowserActive()); |
| } |
| |
| // If we need a PII-stripped trace, any new OTR session during tracing should |
| // block the finalization of the trace. |
| IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest, |
| NewIncognitoSessionBlockingTraceFinalization) { |
| TestBackgroundTracingHelper background_tracing_helper; |
| EXPECT_TRUE(StartScenario(content::BackgroundTracingManager::ANONYMIZE_DATA)); |
| background_tracing_helper.WaitForScenarioActive(); |
| |
| EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_NEW_INCOGNITO_WINDOW)); |
| EXPECT_TRUE(BrowserList::IsOffTheRecordBrowserActive()); |
| |
| TriggerPreemptiveScenario(); |
| background_tracing_helper.WaitForScenarioIdle(); |
| } |
| |
| // If we need a PII-stripped trace, any OTR session that starts and ends during |
| // tracing should block the finalization of the trace. |
| IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest, |
| ShortIncognitoSessionBlockingTraceFinalization) { |
| EXPECT_TRUE(StartScenario(content::BackgroundTracingManager::ANONYMIZE_DATA)); |
| |
| Browser* incognito_browser = CreateIncognitoBrowser(browser()->profile()); |
| EXPECT_TRUE(BrowserList::IsOffTheRecordBrowserActive()); |
| CloseBrowserSynchronously(incognito_browser); |
| EXPECT_FALSE(BrowserList::IsOffTheRecordBrowserActive()); |
| |
| TestBackgroundTracingHelper background_tracing_helper; |
| TriggerPreemptiveScenario(); |
| background_tracing_helper.WaitForScenarioIdle(); |
| } |
| |
| } // namespace tracing |