• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/check.h"
8 #include "base/notreached.h"
9 #include "build/build_config.h"
10 #include "components/metrics/content/extensions_helper.h"
11 #include "content/public/browser/browser_child_process_observer.h"
12 #include "content/public/browser/child_process_data.h"
13 #include "content/public/browser/child_process_termination_info.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/common/page_visibility_state.h"
17 #include "content/public/common/process_type.h"
18 #include "ppapi/buildflags/buildflags.h"
19 
20 #if BUILDFLAG(IS_ANDROID)
21 #include "components/crash/content/browser/crash_metrics_reporter_android.h"
22 #endif
23 
24 namespace metrics {
25 
26 namespace {
27 
28 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
29 // Determines which value of RendererHostedContentType correctly describes the
30 // type of content hosted by `host`.
DetermineHostedContentType(content::RenderProcessHost * host,ExtensionsHelper * extensions_helper)31 RendererHostedContentType DetermineHostedContentType(
32     content::RenderProcessHost* host,
33     ExtensionsHelper* extensions_helper) {
34   if (extensions_helper && extensions_helper->IsExtensionProcess(host)) {
35     return RendererHostedContentType::kExtension;
36   }
37 
38   // Iterate through `host`'s frames to identify these frame types:
39   bool has_active_foreground_main_frame = false;
40   bool has_active_foreground_subframe = false;
41   bool has_active_background_frame = false;
42   bool has_inactive_frame = false;
43 
44   host->ForEachRenderFrameHost(
45       [&](content::RenderFrameHost* render_frame_host) {
46         if (render_frame_host->IsActive()) {
47           if (render_frame_host->GetVisibilityState() ==
48               blink::mojom::PageVisibilityState::kVisible) {
49             if (render_frame_host->GetMainFrame() == render_frame_host) {
50               has_active_foreground_main_frame = true;
51             } else {
52               has_active_foreground_subframe = true;
53             }
54           } else {
55             has_active_background_frame = true;
56           }
57         } else {
58           has_inactive_frame = true;
59         }
60       });
61 
62   // Derive a `RendererHostedContentType` from the frame types hosted by `host`.
63   if (has_active_foreground_main_frame) {
64     return RendererHostedContentType::kForegroundMainFrame;
65   }
66   if (has_active_foreground_subframe) {
67     return RendererHostedContentType::kForegroundSubframe;
68   } else if (has_active_background_frame) {
69     return RendererHostedContentType::kBackgroundFrame;
70   } else if (has_inactive_frame) {
71     return RendererHostedContentType::kInactiveFrame;
72   }
73 
74   return RendererHostedContentType::kNoFrameOrExtension;
75 }
76 #endif  // !BUILDFLAG(IS_ANDROID)
77 
IsCdmUtilityProcess(const content::ChildProcessData & data)78 bool IsCdmUtilityProcess(const content::ChildProcessData& data) {
79   return (data.process_type == content::PROCESS_TYPE_UTILITY &&
80           (data.sandbox_type == sandbox::mojom::Sandbox::kCdm
81 #if BUILDFLAG(IS_WIN)
82            || data.sandbox_type == sandbox::mojom::Sandbox::kMediaFoundationCdm
83 #endif
84            ));
85 }
86 
87 }  // namespace
88 
ContentStabilityMetricsProvider(PrefService * local_state,std::unique_ptr<ExtensionsHelper> extensions_helper)89 ContentStabilityMetricsProvider::ContentStabilityMetricsProvider(
90     PrefService* local_state,
91     std::unique_ptr<ExtensionsHelper> extensions_helper)
92     : helper_(local_state), extensions_helper_(std::move(extensions_helper)) {
93   BrowserChildProcessObserver::Add(this);
94 
95 #if BUILDFLAG(IS_ANDROID)
96   auto* crash_manager = crash_reporter::CrashMetricsReporter::GetInstance();
97   DCHECK(crash_manager);
98   scoped_observation_.Observe(crash_manager);
99 #endif  // BUILDFLAG(IS_ANDROID)
100 }
101 
~ContentStabilityMetricsProvider()102 ContentStabilityMetricsProvider::~ContentStabilityMetricsProvider() {
103   BrowserChildProcessObserver::Remove(this);
104 }
105 
OnRecordingEnabled()106 void ContentStabilityMetricsProvider::OnRecordingEnabled() {}
107 
OnRecordingDisabled()108 void ContentStabilityMetricsProvider::OnRecordingDisabled() {}
109 
110 #if BUILDFLAG(IS_ANDROID)
ProvideStabilityMetrics(SystemProfileProto * system_profile_proto)111 void ContentStabilityMetricsProvider::ProvideStabilityMetrics(
112     SystemProfileProto* system_profile_proto) {
113   helper_.ProvideStabilityMetrics(system_profile_proto);
114 }
115 
ClearSavedStabilityMetrics()116 void ContentStabilityMetricsProvider::ClearSavedStabilityMetrics() {
117   helper_.ClearSavedStabilityMetrics();
118 }
119 #endif  // BUILDFLAG(IS_ANDROID)
120 
OnRenderProcessHostCreated(content::RenderProcessHost * host)121 void ContentStabilityMetricsProvider::OnRenderProcessHostCreated(
122     content::RenderProcessHost* host) {
123   bool was_extension_process =
124       extensions_helper_ && extensions_helper_->IsExtensionProcess(host);
125   helper_.LogRendererLaunched(was_extension_process);
126   if (!host_observation_.IsObservingSource(host)) {
127     host_observation_.AddObservation(host);
128   }
129 }
130 
OnRenderProcessHostCreationFailed(content::RenderProcessHost * host,const content::ChildProcessTerminationInfo & info)131 void ContentStabilityMetricsProvider::OnRenderProcessHostCreationFailed(
132     content::RenderProcessHost* host,
133     const content::ChildProcessTerminationInfo& info) {
134 #if BUILDFLAG(IS_IOS)
135   helper_.LogRendererCrash();
136 #elif !BUILDFLAG(IS_ANDROID)
137   helper_.LogRendererCrash(
138       DetermineHostedContentType(host, extensions_helper_.get()), info.status,
139       info.exit_code);
140 #endif
141 }
142 
RenderProcessExited(content::RenderProcessHost * host,const content::ChildProcessTerminationInfo & info)143 void ContentStabilityMetricsProvider::RenderProcessExited(
144     content::RenderProcessHost* host,
145     const content::ChildProcessTerminationInfo& info) {
146   // On Android, the renderer crashes are recorded in
147   // `OnCrashDumpProcessed`.
148 #if BUILDFLAG(IS_IOS)
149   helper_.LogRendererCrash();
150 #elif !BUILDFLAG(IS_ANDROID)
151   helper_.LogRendererCrash(
152       DetermineHostedContentType(host, extensions_helper_.get()), info.status,
153       info.exit_code);
154 #endif
155 }
156 
RenderProcessHostDestroyed(content::RenderProcessHost * host)157 void ContentStabilityMetricsProvider::RenderProcessHostDestroyed(
158     content::RenderProcessHost* host) {
159   // In single-process mode, RenderProcessExited isn't called, so we ensure
160   // we remove observations here rather than there, to avoid later use-after-
161   // frees in single process mode.
162   host_observation_.RemoveObservation(host);
163 }
164 
BrowserChildProcessCrashed(const content::ChildProcessData & data,const content::ChildProcessTerminationInfo & info)165 void ContentStabilityMetricsProvider::BrowserChildProcessCrashed(
166     const content::ChildProcessData& data,
167     const content::ChildProcessTerminationInfo& info) {
168   DCHECK(!data.metrics_name.empty());
169   if (data.process_type == content::PROCESS_TYPE_UTILITY)
170     helper_.BrowserUtilityProcessCrashed(data.metrics_name, info.exit_code);
171 
172   if (IsCdmUtilityProcess(data)) {
173     helper_.CdmUtilityProcessCrashed(data.metrics_name, info.exit_code);
174   }
175 }
176 
BrowserChildProcessLaunchedAndConnected(const content::ChildProcessData & data)177 void ContentStabilityMetricsProvider::BrowserChildProcessLaunchedAndConnected(
178     const content::ChildProcessData& data) {
179   DCHECK(!data.metrics_name.empty());
180   if (data.process_type == content::PROCESS_TYPE_UTILITY)
181     helper_.BrowserUtilityProcessLaunched(data.metrics_name);
182 
183   if (IsCdmUtilityProcess(data)) {
184     helper_.CdmUtilityProcessLaunched(data.metrics_name);
185   }
186 }
187 
BrowserChildProcessLaunchFailed(const content::ChildProcessData & data,const content::ChildProcessTerminationInfo & info)188 void ContentStabilityMetricsProvider::BrowserChildProcessLaunchFailed(
189     const content::ChildProcessData& data,
190     const content::ChildProcessTerminationInfo& info) {
191   DCHECK(!data.metrics_name.empty());
192   DCHECK_EQ(info.status, base::TERMINATION_STATUS_LAUNCH_FAILED);
193   if (data.process_type == content::PROCESS_TYPE_UTILITY)
194     helper_.BrowserUtilityProcessLaunchFailed(data.metrics_name, info.exit_code
195 #if BUILDFLAG(IS_WIN)
196                                               ,
197                                               info.last_error
198 #endif
199     );
200 
201   if (IsCdmUtilityProcess(data)) {
202     helper_.CdmUtilityProcessLaunchFailed(data.metrics_name, info.exit_code
203 #if BUILDFLAG(IS_WIN)
204                                           ,
205                                           info.last_error
206 #endif
207     );
208   }
209 }
210 
211 #if BUILDFLAG(IS_ANDROID)
OnCrashDumpProcessed(int rph_id,const crash_reporter::CrashMetricsReporter::ReportedCrashTypeSet & reported_counts)212 void ContentStabilityMetricsProvider::OnCrashDumpProcessed(
213     int rph_id,
214     const crash_reporter::CrashMetricsReporter::ReportedCrashTypeSet&
215         reported_counts) {
216   if (reported_counts.count(crash_reporter::CrashMetricsReporter::
217                                 ProcessedCrashCounts::kRendererCrashAll)) {
218     helper_.IncreaseRendererCrashCount();
219   }
220   if (reported_counts.count(crash_reporter::CrashMetricsReporter::
221                                 ProcessedCrashCounts::kGpuCrashAll)) {
222     helper_.IncreaseGpuCrashCount();
223   }
224 }
225 #endif  // BUILDFLAG(IS_ANDROID)
226 
OnPageLoadStarted()227 void ContentStabilityMetricsProvider::OnPageLoadStarted() {
228   helper_.LogLoadStarted();
229 }
230 
231 }  // namespace metrics
232