1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/metrics/content/content_stability_metrics_provider.h"
6 
7 #include "base/memory/raw_ptr.h"
8 #include "base/test/metrics/histogram_tester.h"
9 #include "build/build_config.h"
10 #include "components/metrics/content/extensions_helper.h"
11 #include "components/prefs/pref_service.h"
12 #include "components/prefs/scoped_user_pref_update.h"
13 #include "components/prefs/testing_pref_service.h"
14 #include "components/variations/hashing.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/child_process_data.h"
17 #include "content/public/browser/child_process_termination_info.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/site_instance.h"
20 #include "content/public/common/process_type.h"
21 #include "content/public/test/browser_task_environment.h"
22 #include "content/public/test/mock_render_process_host.h"
23 #include "content/public/test/test_browser_context.h"
24 #include "extensions/buildflags/buildflags.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "third_party/metrics_proto/system_profile.pb.h"
27 
28 namespace metrics {
29 
30 namespace {
31 
32 const char kTestUtilityProcessName[] = "test_utility_process";
33 
34 class MockExtensionsHelper : public ExtensionsHelper {
35  public:
36   MockExtensionsHelper() = default;
37   MockExtensionsHelper(const MockExtensionsHelper&) = delete;
38   MockExtensionsHelper& operator=(const MockExtensionsHelper&) = delete;
39   ~MockExtensionsHelper() override = default;
40 
set_extension_host(content::RenderProcessHost * host)41   void set_extension_host(content::RenderProcessHost* host) { host_ = host; }
42   // ExtensionsHelper:
IsExtensionProcess(content::RenderProcessHost * render_process_host)43   bool IsExtensionProcess(
44       content::RenderProcessHost* render_process_host) override {
45     return render_process_host == host_;
46   }
47 
48  private:
49   raw_ptr<content::RenderProcessHost> host_ = nullptr;
50 };
51 
52 }  // namespace
53 
54 class ContentStabilityMetricsProviderTest : public testing::Test {
55  protected:
ContentStabilityMetricsProviderTest()56   ContentStabilityMetricsProviderTest()
57       : prefs_(std::make_unique<TestingPrefServiceSimple>()) {
58     metrics::StabilityMetricsHelper::RegisterPrefs(prefs()->registry());
59   }
60   ContentStabilityMetricsProviderTest(
61       const ContentStabilityMetricsProviderTest&) = delete;
62   ContentStabilityMetricsProviderTest& operator=(
63       const ContentStabilityMetricsProviderTest&) = delete;
64   ~ContentStabilityMetricsProviderTest() override = default;
65 
prefs()66   TestingPrefServiceSimple* prefs() { return prefs_.get(); }
67 
68  private:
69   std::unique_ptr<TestingPrefServiceSimple> prefs_;
70   content::BrowserTaskEnvironment task_environment_;
71 };
72 
TEST_F(ContentStabilityMetricsProviderTest,BrowserChildProcessObserverUtility)73 TEST_F(ContentStabilityMetricsProviderTest,
74        BrowserChildProcessObserverUtility) {
75   base::HistogramTester histogram_tester;
76   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
77 
78   content::ChildProcessData child_process_data(content::PROCESS_TYPE_UTILITY);
79   child_process_data.metrics_name = kTestUtilityProcessName;
80 
81   provider.BrowserChildProcessLaunchedAndConnected(child_process_data);
82   const int kExitCode = 1;
83   content::ChildProcessTerminationInfo abnormal_termination_info;
84   abnormal_termination_info.status =
85       base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
86   abnormal_termination_info.exit_code = kExitCode;
87   provider.BrowserChildProcessCrashed(child_process_data,
88                                       abnormal_termination_info);
89   provider.BrowserChildProcessCrashed(child_process_data,
90                                       abnormal_termination_info);
91 
92   // Verify metrics.
93   histogram_tester.ExpectUniqueSample(
94       "ChildProcess.Launched.UtilityProcessHash",
95       variations::HashName(kTestUtilityProcessName), 1);
96   histogram_tester.ExpectBucketCount("Stability.Counts2",
97                                      StabilityEventType::kUtilityLaunch, 1);
98   histogram_tester.ExpectUniqueSample(
99       "ChildProcess.Crashed.UtilityProcessHash",
100       variations::HashName(kTestUtilityProcessName), 2);
101   histogram_tester.ExpectUniqueSample(
102       "ChildProcess.Crashed.UtilityProcessExitCode", kExitCode, 2);
103   histogram_tester.ExpectBucketCount("Stability.Counts2",
104                                      StabilityEventType::kUtilityCrash, 2);
105 }
106 
107 #if !BUILDFLAG(IS_ANDROID)
TEST_F(ContentStabilityMetricsProviderTest,RenderProcessObserver)108 TEST_F(ContentStabilityMetricsProviderTest, RenderProcessObserver) {
109   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
110   content::TestBrowserContext browser_context;
111   content::MockRenderProcessHostFactory rph_factory;
112   scoped_refptr<content::SiteInstance> site_instance(
113       content::SiteInstance::Create(&browser_context));
114 
115   // Owned by rph_factory.
116   content::RenderProcessHost* host(rph_factory.CreateRenderProcessHost(
117       &browser_context, site_instance.get()));
118 
119   base::HistogramTester histogram_tester;
120 
121   // Crash and abnormal termination should increment renderer crash count.
122   content::ChildProcessTerminationInfo crash_details;
123   crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
124   crash_details.exit_code = 1;
125   provider.OnRenderProcessHostCreated(host);
126   provider.RenderProcessExited(host, crash_details);
127 
128   content::ChildProcessTerminationInfo term_details;
129   term_details.status = base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
130   term_details.exit_code = 1;
131   provider.OnRenderProcessHostCreated(host);
132   provider.RenderProcessExited(host, term_details);
133 
134   // Kill does not increment renderer crash count.
135   content::ChildProcessTerminationInfo kill_details;
136   kill_details.status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED;
137   kill_details.exit_code = 1;
138   provider.OnRenderProcessHostCreated(host);
139   provider.RenderProcessExited(host, kill_details);
140 
141   // Failed launch increments failed launch count.
142   content::ChildProcessTerminationInfo failed_launch_details;
143   failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
144   failed_launch_details.exit_code = 1;
145   provider.OnRenderProcessHostCreated(host);
146   provider.RenderProcessExited(host, failed_launch_details);
147 
148   // Verify metrics.
149   histogram_tester.ExpectBucketCount("Stability.Counts2",
150                                      StabilityEventType::kRendererCrash, 2);
151   histogram_tester.ExpectBucketCount(
152       "Stability.Counts2", StabilityEventType::kRendererFailedLaunch, 1);
153   histogram_tester.ExpectBucketCount("Stability.Counts2",
154                                      StabilityEventType::kExtensionCrash, 0);
155 }
156 
TEST_F(ContentStabilityMetricsProviderTest,MetricsServicesWebContentsObserver)157 TEST_F(ContentStabilityMetricsProviderTest,
158        MetricsServicesWebContentsObserver) {
159   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
160   base::HistogramTester histogram_tester;
161   histogram_tester.ExpectBucketCount("Stability.Counts2",
162                                      StabilityEventType::kPageLoad, 0);
163 
164   // Simulate page loads.
165   const auto expected_page_load_count = 4;
166   for (int i = 0; i < expected_page_load_count; i++) {
167     provider.OnPageLoadStarted();
168   }
169 
170   // Verify metrics.
171   histogram_tester.ExpectBucketCount("Stability.Counts2",
172                                      StabilityEventType::kPageLoad,
173                                      expected_page_load_count);
174 }
175 
176 #endif  // !BUILDFLAG(IS_ANDROID)
177 
178 // Assertions for an extension related crash.
179 // This test only works if extensions are enabled as there is a DCHECK in
180 // StabilityMetricsHelper that it is only called with a value of true for
181 // extension process if extensions are enabled.
182 #if BUILDFLAG(ENABLE_EXTENSIONS)
TEST_F(ContentStabilityMetricsProviderTest,ExtensionsNotificationObserver)183 TEST_F(ContentStabilityMetricsProviderTest, ExtensionsNotificationObserver) {
184   content::TestBrowserContext browser_context;
185   content::MockRenderProcessHostFactory rph_factory;
186   scoped_refptr<content::SiteInstance> site_instance(
187       content::SiteInstance::Create(&browser_context));
188 
189   // Owned by rph_factory.
190   content::RenderProcessHost* extension_host =
191       rph_factory.CreateRenderProcessHost(&browser_context,
192                                           site_instance.get());
193   auto extensions_helper = std::make_unique<MockExtensionsHelper>();
194   extensions_helper->set_extension_host(extension_host);
195   metrics::ContentStabilityMetricsProvider provider(
196       prefs(), std::move(extensions_helper));
197 
198   base::HistogramTester histogram_tester;
199 
200   // Crash and abnormal termination should increment extension crash count.
201   content::ChildProcessTerminationInfo crash_details;
202   crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
203   crash_details.exit_code = 1;
204   provider.OnRenderProcessHostCreated(extension_host);
205   provider.RenderProcessExited(extension_host, crash_details);
206 
207   // Failed launch increments failed launch count.
208   content::ChildProcessTerminationInfo failed_launch_details;
209   failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
210   failed_launch_details.exit_code = 1;
211   provider.OnRenderProcessHostCreated(extension_host);
212   provider.RenderProcessExited(extension_host, failed_launch_details);
213 
214   // Verify metrics.
215   histogram_tester.ExpectBucketCount("Stability.Counts2",
216                                      StabilityEventType::kRendererCrash, 0);
217   histogram_tester.ExpectBucketCount("Stability.Counts2",
218                                      StabilityEventType::kExtensionCrash, 1);
219   histogram_tester.ExpectBucketCount(
220       "Stability.Counts2", StabilityEventType::kExtensionRendererFailedLaunch,
221       1);
222 }
223 #endif
224 
225 }  // namespace metrics
226