xref: /aosp_15_r20/external/cronet/components/metrics/content/content_stability_metrics_provider.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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