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