• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 const char kTestCdmServiceUtilityProcessName[] = "media.mojom.CdmServiceBroker";
34 #if BUILDFLAG(IS_WIN)
35 const char kTestMediaFoundationServiceUtilityProcessName[] =
36     "media.mojom.MediaFoundationServiceBroker";
37 #endif
38 
39 class MockExtensionsHelper : public ExtensionsHelper {
40  public:
41   MockExtensionsHelper() = default;
42   MockExtensionsHelper(const MockExtensionsHelper&) = delete;
43   MockExtensionsHelper& operator=(const MockExtensionsHelper&) = delete;
44   ~MockExtensionsHelper() override = default;
45 
set_extension_host(content::RenderProcessHost * host)46   void set_extension_host(content::RenderProcessHost* host) { host_ = host; }
47   // ExtensionsHelper:
IsExtensionProcess(content::RenderProcessHost * render_process_host)48   bool IsExtensionProcess(
49       content::RenderProcessHost* render_process_host) override {
50     return render_process_host == host_;
51   }
52 
53  private:
54   raw_ptr<content::RenderProcessHost> host_ = nullptr;
55 };
56 
57 }  // namespace
58 
59 class ContentStabilityMetricsProviderTest : public testing::Test {
60  protected:
ContentStabilityMetricsProviderTest()61   ContentStabilityMetricsProviderTest()
62       : prefs_(std::make_unique<TestingPrefServiceSimple>()) {
63     metrics::StabilityMetricsHelper::RegisterPrefs(prefs()->registry());
64   }
65   ContentStabilityMetricsProviderTest(
66       const ContentStabilityMetricsProviderTest&) = delete;
67   ContentStabilityMetricsProviderTest& operator=(
68       const ContentStabilityMetricsProviderTest&) = delete;
69   ~ContentStabilityMetricsProviderTest() override = default;
70 
prefs()71   TestingPrefServiceSimple* prefs() { return prefs_.get(); }
72 
73  private:
74   std::unique_ptr<TestingPrefServiceSimple> prefs_;
75   content::BrowserTaskEnvironment task_environment_;
76 };
77 
TEST_F(ContentStabilityMetricsProviderTest,BrowserChildProcessObserverUtility)78 TEST_F(ContentStabilityMetricsProviderTest,
79        BrowserChildProcessObserverUtility) {
80   base::HistogramTester histogram_tester;
81   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
82 
83   content::ChildProcessData child_process_data(content::PROCESS_TYPE_UTILITY);
84   child_process_data.metrics_name = kTestUtilityProcessName;
85 
86   provider.BrowserChildProcessLaunchedAndConnected(child_process_data);
87   const int kExitCode = 1;
88   content::ChildProcessTerminationInfo abnormal_termination_info;
89   abnormal_termination_info.status =
90       base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
91   abnormal_termination_info.exit_code = kExitCode;
92   provider.BrowserChildProcessCrashed(child_process_data,
93                                       abnormal_termination_info);
94   provider.BrowserChildProcessCrashed(child_process_data,
95                                       abnormal_termination_info);
96 
97   // Verify metrics.
98   histogram_tester.ExpectUniqueSample(
99       "ChildProcess.Launched.UtilityProcessHash",
100       variations::HashName(kTestUtilityProcessName), 1);
101   histogram_tester.ExpectBucketCount("Stability.Counts2",
102                                      StabilityEventType::kUtilityLaunch, 1);
103   histogram_tester.ExpectUniqueSample(
104       "ChildProcess.Crashed.UtilityProcessHash",
105       variations::HashName(kTestUtilityProcessName), 2);
106   histogram_tester.ExpectUniqueSample(
107       "ChildProcess.Crashed.UtilityProcessExitCode", kExitCode, 2);
108   histogram_tester.ExpectBucketCount("Stability.Counts2",
109                                      StabilityEventType::kUtilityCrash, 2);
110 }
111 
TEST_F(ContentStabilityMetricsProviderTest,CdmServiceProcessObserverUtility)112 TEST_F(ContentStabilityMetricsProviderTest, CdmServiceProcessObserverUtility) {
113   base::HistogramTester histogram_tester;
114   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
115 
116   content::ChildProcessData child_process_data(content::PROCESS_TYPE_UTILITY);
117   child_process_data.metrics_name = kTestCdmServiceUtilityProcessName;
118   child_process_data.sandbox_type = sandbox::mojom::Sandbox::kCdm;
119 
120   provider.BrowserChildProcessLaunchedAndConnected(child_process_data);
121   const int kExitCode = 333;
122   content::ChildProcessTerminationInfo abnormal_termination_info;
123   abnormal_termination_info.status =
124       base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
125   abnormal_termination_info.exit_code = kExitCode;
126   provider.BrowserChildProcessCrashed(child_process_data,
127                                       abnormal_termination_info);
128   provider.BrowserChildProcessCrashed(child_process_data,
129                                       abnormal_termination_info);
130 
131   // Verify metrics.
132   histogram_tester.ExpectUniqueSample(
133       "Stability.Media.CdmServiceBroker.Crash.ExitCode", kExitCode, 2);
134 }
135 
TEST_F(ContentStabilityMetricsProviderTest,CdmServiceProcessObserverUtilityLaunchFailed)136 TEST_F(ContentStabilityMetricsProviderTest,
137        CdmServiceProcessObserverUtilityLaunchFailed) {
138   base::HistogramTester histogram_tester;
139   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
140 
141   content::ChildProcessData child_process_data(content::PROCESS_TYPE_UTILITY);
142   child_process_data.metrics_name = kTestCdmServiceUtilityProcessName;
143   child_process_data.sandbox_type = sandbox::mojom::Sandbox::kCdm;
144 
145   const int kExitCode = 777;
146   content::ChildProcessTerminationInfo abnormal_termination_info;
147   abnormal_termination_info.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
148   abnormal_termination_info.exit_code = kExitCode;
149 #if BUILDFLAG(IS_WIN)
150   const int kLastError = 9;
151   abnormal_termination_info.last_error = kLastError;
152 #endif
153   provider.BrowserChildProcessLaunchFailed(child_process_data,
154                                            abnormal_termination_info);
155 
156   // Verify metrics.
157   histogram_tester.ExpectUniqueSample("Stability.Media.CdmServiceBroker.Launch",
158                                       false, 1);
159   histogram_tester.ExpectUniqueSample(
160       "Stability.Media.CdmServiceBroker.Launch.LaunchErrorCode", kExitCode, 1);
161 #if BUILDFLAG(IS_WIN)
162   histogram_tester.ExpectUniqueSample(
163       "Stability.Media.CdmServiceBroker.Launch.WinLastError", kLastError, 1);
164 #endif
165 }
166 
167 #if BUILDFLAG(IS_WIN)
TEST_F(ContentStabilityMetricsProviderTest,MediaFoundationServiceProcessObserverUtility)168 TEST_F(ContentStabilityMetricsProviderTest,
169        MediaFoundationServiceProcessObserverUtility) {
170   base::HistogramTester histogram_tester;
171   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
172 
173   content::ChildProcessData child_process_data(content::PROCESS_TYPE_UTILITY);
174   child_process_data.metrics_name =
175       kTestMediaFoundationServiceUtilityProcessName;
176   child_process_data.sandbox_type =
177       sandbox::mojom::Sandbox::kMediaFoundationCdm;
178 
179   provider.BrowserChildProcessLaunchedAndConnected(child_process_data);
180   const int kExitCode = 555;
181   content::ChildProcessTerminationInfo abnormal_termination_info;
182   abnormal_termination_info.status =
183       base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
184   abnormal_termination_info.exit_code = kExitCode;
185   provider.BrowserChildProcessCrashed(child_process_data,
186                                       abnormal_termination_info);
187   provider.BrowserChildProcessCrashed(child_process_data,
188                                       abnormal_termination_info);
189 
190   // Verify metrics.
191   histogram_tester.ExpectUniqueSample(
192       "Stability.Media.MediaFoundationServiceBroker.Crash.ExitCode", kExitCode,
193       2);
194 }
195 #endif  // BUILDFLAG(IS_WIN)
196 
197 #if !BUILDFLAG(IS_ANDROID)
TEST_F(ContentStabilityMetricsProviderTest,RenderProcessObserver)198 TEST_F(ContentStabilityMetricsProviderTest, RenderProcessObserver) {
199   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
200   content::TestBrowserContext browser_context;
201   content::MockRenderProcessHostFactory rph_factory;
202   scoped_refptr<content::SiteInstance> site_instance(
203       content::SiteInstance::Create(&browser_context));
204 
205   // Owned by rph_factory.
206   content::RenderProcessHost* host(rph_factory.CreateRenderProcessHost(
207       &browser_context, site_instance.get()));
208 
209   base::HistogramTester histogram_tester;
210 
211   // Crash and abnormal termination should increment renderer crash count.
212   content::ChildProcessTerminationInfo crash_details;
213   crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
214   crash_details.exit_code = 1;
215   provider.OnRenderProcessHostCreated(host);
216   provider.RenderProcessExited(host, crash_details);
217 
218   content::ChildProcessTerminationInfo term_details;
219   term_details.status = base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
220   term_details.exit_code = 1;
221   provider.OnRenderProcessHostCreated(host);
222   provider.RenderProcessExited(host, term_details);
223 
224   // Kill does not increment renderer crash count.
225   content::ChildProcessTerminationInfo kill_details;
226   kill_details.status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED;
227   kill_details.exit_code = 1;
228   provider.OnRenderProcessHostCreated(host);
229   provider.RenderProcessExited(host, kill_details);
230 
231   // Failed launch increments failed launch count.
232   content::ChildProcessTerminationInfo failed_launch_details;
233   failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
234   failed_launch_details.exit_code = 1;
235   provider.OnRenderProcessHostCreationFailed(host, failed_launch_details);
236 
237   // Verify metrics.
238   histogram_tester.ExpectBucketCount("Stability.Counts2",
239                                      StabilityEventType::kRendererCrash, 2);
240   histogram_tester.ExpectBucketCount(
241       "Stability.Counts2", StabilityEventType::kRendererFailedLaunch, 1);
242   histogram_tester.ExpectBucketCount("Stability.Counts2",
243                                      StabilityEventType::kExtensionCrash, 0);
244 }
245 
TEST_F(ContentStabilityMetricsProviderTest,MetricsServicesWebContentsObserver)246 TEST_F(ContentStabilityMetricsProviderTest,
247        MetricsServicesWebContentsObserver) {
248   metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
249   base::HistogramTester histogram_tester;
250   histogram_tester.ExpectBucketCount("Stability.Counts2",
251                                      StabilityEventType::kPageLoad, 0);
252 
253   // Simulate page loads.
254   const auto expected_page_load_count = 4;
255   for (int i = 0; i < expected_page_load_count; i++) {
256     provider.OnPageLoadStarted();
257   }
258 
259   // Verify metrics.
260   histogram_tester.ExpectBucketCount("Stability.Counts2",
261                                      StabilityEventType::kPageLoad,
262                                      expected_page_load_count);
263 }
264 
265 #endif  // !BUILDFLAG(IS_ANDROID)
266 
267 // Assertions for an extension related crash.
268 // This test only works if extensions are enabled as there is a DCHECK in
269 // StabilityMetricsHelper that it is only called with a value of true for
270 // extension process if extensions are enabled.
271 #if BUILDFLAG(ENABLE_EXTENSIONS)
TEST_F(ContentStabilityMetricsProviderTest,ExtensionsNotificationObserver)272 TEST_F(ContentStabilityMetricsProviderTest, ExtensionsNotificationObserver) {
273   content::TestBrowserContext browser_context;
274   content::MockRenderProcessHostFactory rph_factory;
275   scoped_refptr<content::SiteInstance> site_instance(
276       content::SiteInstance::Create(&browser_context));
277 
278   // Owned by rph_factory.
279   content::RenderProcessHost* extension_host =
280       rph_factory.CreateRenderProcessHost(&browser_context,
281                                           site_instance.get());
282   auto extensions_helper = std::make_unique<MockExtensionsHelper>();
283   extensions_helper->set_extension_host(extension_host);
284   metrics::ContentStabilityMetricsProvider provider(
285       prefs(), std::move(extensions_helper));
286 
287   base::HistogramTester histogram_tester;
288 
289   // Crash and abnormal termination should increment extension crash count.
290   content::ChildProcessTerminationInfo crash_details;
291   crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
292   crash_details.exit_code = 1;
293   provider.OnRenderProcessHostCreated(extension_host);
294   provider.RenderProcessExited(extension_host, crash_details);
295 
296   // Failed launch increments failed launch count.
297   content::ChildProcessTerminationInfo failed_launch_details;
298   failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
299   failed_launch_details.exit_code = 1;
300   provider.OnRenderProcessHostCreationFailed(extension_host,
301                                              failed_launch_details);
302 
303   // Verify metrics.
304   histogram_tester.ExpectBucketCount("Stability.Counts2",
305                                      StabilityEventType::kRendererCrash, 0);
306   histogram_tester.ExpectBucketCount("Stability.Counts2",
307                                      StabilityEventType::kExtensionCrash, 1);
308   histogram_tester.ExpectBucketCount(
309       "Stability.Counts2", StabilityEventType::kExtensionRendererFailedLaunch,
310       1);
311 }
312 #endif
313 
314 }  // namespace metrics
315