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