blob: 47acf1306a9a24eb3572238834a5c41800a05e81 [file] [log] [blame]
// 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 "components/metrics/content/content_stability_metrics_provider.h"
#include "base/memory/raw_ptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
#include "components/metrics/content/extensions_helper.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/prefs/testing_pref_service.h"
#include "components/variations/hashing.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/child_process_termination_info.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/common/process_type.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "extensions/buildflags/buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/system_profile.pb.h"
namespace metrics {
namespace {
const char kTestUtilityProcessName[] = "test_utility_process";
class MockExtensionsHelper : public ExtensionsHelper {
public:
MockExtensionsHelper() = default;
MockExtensionsHelper(const MockExtensionsHelper&) = delete;
MockExtensionsHelper& operator=(const MockExtensionsHelper&) = delete;
~MockExtensionsHelper() override = default;
void set_extension_host(content::RenderProcessHost* host) { host_ = host; }
// ExtensionsHelper:
bool IsExtensionProcess(
content::RenderProcessHost* render_process_host) override {
return render_process_host == host_;
}
private:
raw_ptr<content::RenderProcessHost> host_ = nullptr;
};
} // namespace
class ContentStabilityMetricsProviderTest : public testing::Test {
protected:
ContentStabilityMetricsProviderTest()
: prefs_(std::make_unique<TestingPrefServiceSimple>()) {
metrics::StabilityMetricsHelper::RegisterPrefs(prefs()->registry());
}
ContentStabilityMetricsProviderTest(
const ContentStabilityMetricsProviderTest&) = delete;
ContentStabilityMetricsProviderTest& operator=(
const ContentStabilityMetricsProviderTest&) = delete;
~ContentStabilityMetricsProviderTest() override = default;
TestingPrefServiceSimple* prefs() { return prefs_.get(); }
private:
std::unique_ptr<TestingPrefServiceSimple> prefs_;
content::BrowserTaskEnvironment task_environment_;
};
TEST_F(ContentStabilityMetricsProviderTest,
BrowserChildProcessObserverUtility) {
base::HistogramTester histogram_tester;
metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
content::ChildProcessData child_process_data(content::PROCESS_TYPE_UTILITY);
child_process_data.metrics_name = kTestUtilityProcessName;
provider.BrowserChildProcessLaunchedAndConnected(child_process_data);
const int kExitCode = 1;
content::ChildProcessTerminationInfo abnormal_termination_info;
abnormal_termination_info.status =
base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
abnormal_termination_info.exit_code = kExitCode;
provider.BrowserChildProcessCrashed(child_process_data,
abnormal_termination_info);
provider.BrowserChildProcessCrashed(child_process_data,
abnormal_termination_info);
// Verify metrics.
histogram_tester.ExpectUniqueSample(
"ChildProcess.Launched.UtilityProcessHash",
variations::HashName(kTestUtilityProcessName), 1);
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kUtilityLaunch, 1);
histogram_tester.ExpectUniqueSample(
"ChildProcess.Crashed.UtilityProcessHash",
variations::HashName(kTestUtilityProcessName), 2);
histogram_tester.ExpectUniqueSample(
"ChildProcess.Crashed.UtilityProcessExitCode", kExitCode, 2);
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kUtilityCrash, 2);
}
#if !BUILDFLAG(IS_ANDROID)
TEST_F(ContentStabilityMetricsProviderTest, RenderProcessObserver) {
metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
content::TestBrowserContext browser_context;
content::MockRenderProcessHostFactory rph_factory;
scoped_refptr<content::SiteInstance> site_instance(
content::SiteInstance::Create(&browser_context));
// Owned by rph_factory.
content::RenderProcessHost* host(rph_factory.CreateRenderProcessHost(
&browser_context, site_instance.get()));
base::HistogramTester histogram_tester;
// Crash and abnormal termination should increment renderer crash count.
content::ChildProcessTerminationInfo crash_details;
crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
crash_details.exit_code = 1;
provider.OnRenderProcessHostCreated(host);
provider.RenderProcessExited(host, crash_details);
content::ChildProcessTerminationInfo term_details;
term_details.status = base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
term_details.exit_code = 1;
provider.OnRenderProcessHostCreated(host);
provider.RenderProcessExited(host, term_details);
// Kill does not increment renderer crash count.
content::ChildProcessTerminationInfo kill_details;
kill_details.status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED;
kill_details.exit_code = 1;
provider.OnRenderProcessHostCreated(host);
provider.RenderProcessExited(host, kill_details);
// Failed launch increments failed launch count.
content::ChildProcessTerminationInfo failed_launch_details;
failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
failed_launch_details.exit_code = 1;
provider.OnRenderProcessHostCreated(host);
provider.RenderProcessExited(host, failed_launch_details);
// Verify metrics.
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kRendererCrash, 2);
histogram_tester.ExpectBucketCount(
"Stability.Counts2", StabilityEventType::kRendererFailedLaunch, 1);
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kExtensionCrash, 0);
}
TEST_F(ContentStabilityMetricsProviderTest,
MetricsServicesWebContentsObserver) {
metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
base::HistogramTester histogram_tester;
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kPageLoad, 0);
// Simulate page loads.
const auto expected_page_load_count = 4;
for (int i = 0; i < expected_page_load_count; i++) {
provider.OnPageLoadStarted();
}
// Verify metrics.
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kPageLoad,
expected_page_load_count);
}
#endif // !BUILDFLAG(IS_ANDROID)
// Assertions for an extension related crash.
// This test only works if extensions are enabled as there is a DCHECK in
// StabilityMetricsHelper that it is only called with a value of true for
// extension process if extensions are enabled.
#if BUILDFLAG(ENABLE_EXTENSIONS)
TEST_F(ContentStabilityMetricsProviderTest, ExtensionsNotificationObserver) {
content::TestBrowserContext browser_context;
content::MockRenderProcessHostFactory rph_factory;
scoped_refptr<content::SiteInstance> site_instance(
content::SiteInstance::Create(&browser_context));
// Owned by rph_factory.
content::RenderProcessHost* extension_host =
rph_factory.CreateRenderProcessHost(&browser_context,
site_instance.get());
auto extensions_helper = std::make_unique<MockExtensionsHelper>();
extensions_helper->set_extension_host(extension_host);
metrics::ContentStabilityMetricsProvider provider(
prefs(), std::move(extensions_helper));
base::HistogramTester histogram_tester;
// Crash and abnormal termination should increment extension crash count.
content::ChildProcessTerminationInfo crash_details;
crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
crash_details.exit_code = 1;
provider.OnRenderProcessHostCreated(extension_host);
provider.RenderProcessExited(extension_host, crash_details);
// Failed launch increments failed launch count.
content::ChildProcessTerminationInfo failed_launch_details;
failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
failed_launch_details.exit_code = 1;
provider.OnRenderProcessHostCreated(extension_host);
provider.RenderProcessExited(extension_host, failed_launch_details);
// Verify metrics.
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kRendererCrash, 0);
histogram_tester.ExpectBucketCount("Stability.Counts2",
StabilityEventType::kExtensionCrash, 1);
histogram_tester.ExpectBucketCount(
"Stability.Counts2", StabilityEventType::kExtensionRendererFailedLaunch,
1);
}
#endif
} // namespace metrics