xref: /aosp_15_r20/external/cronet/components/metrics/stability_metrics_helper.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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/stability_metrics_helper.h"
6 
7 #include <stdint.h>
8 
9 #include <string>
10 
11 #include "base/check.h"
12 #include "base/containers/contains.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/notreached.h"
16 #include "base/strings/strcat.h"
17 #include "base/system/sys_info.h"
18 #include "build/build_config.h"
19 #include "build/buildflag.h"
20 #include "components/metrics/metrics_pref_names.h"
21 #include "components/prefs/pref_registry_simple.h"
22 #include "components/prefs/pref_service.h"
23 #include "components/variations/hashing.h"
24 #include "extensions/buildflags/buildflags.h"
25 #include "third_party/metrics_proto/system_profile.pb.h"
26 
27 #if BUILDFLAG(IS_WIN)
28 #include <windows.h>  // Needed for STATUS_* codes
29 #endif
30 
31 #if BUILDFLAG(IS_ANDROID)
32 #include "base/android/application_status_listener.h"
33 #endif
34 
35 namespace metrics {
36 namespace {
37 
38 #if !BUILDFLAG(IS_ANDROID)
39 // Converts an exit code into something that can be inserted into our
40 // histograms (which expect non-negative numbers less than MAX_INT).
MapCrashExitCodeForHistogram(int exit_code)41 int MapCrashExitCodeForHistogram(int exit_code) {
42 #if BUILDFLAG(IS_WIN)
43   // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
44   // histograms.cc. Solve this by remapping it to a smaller value, which
45   // hopefully doesn't conflict with other codes.
46   if (static_cast<DWORD>(exit_code) == STATUS_GUARD_PAGE_VIOLATION)
47     return 0x1FCF7EC3;  // Randomly picked number.
48 #endif
49 
50   return std::abs(exit_code);
51 }
52 #endif  // !BUILDFLAG(IS_ANDROID)
53 
54 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
HostedContentTypeToString(RendererHostedContentType hosted_content_type)55 const char* HostedContentTypeToString(
56     RendererHostedContentType hosted_content_type) {
57   switch (hosted_content_type) {
58     case metrics::RendererHostedContentType::kExtension:
59       return "Extension";
60     case metrics::RendererHostedContentType::kForegroundMainFrame:
61       return "ForegroundMainFrame";
62     case metrics::RendererHostedContentType::kForegroundSubframe:
63       return "ForegroundSubframe";
64     case metrics::RendererHostedContentType::kBackgroundFrame:
65       return "BackgroundFrame";
66     case metrics::RendererHostedContentType::kInactiveFrame:
67       return "InactiveFrame";
68     case metrics::RendererHostedContentType::kNoFrameOrExtension:
69       return "NoFrameOrExtension";
70   }
71 }
72 
RecordRendererAbnormalTerminationByHostedContentType(RendererHostedContentType hosted_content_type,base::TerminationStatus status)73 void RecordRendererAbnormalTerminationByHostedContentType(
74     RendererHostedContentType hosted_content_type,
75     base::TerminationStatus status) {
76   if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION) {
77     return;
78   }
79 
80   base::UmaHistogramEnumeration(
81       "Stability.RendererAbnormalTermination2.HostedContentType",
82       hosted_content_type);
83   base::UmaHistogramEnumeration(
84       base::StrCat({"Stability.RendererAbnormalTermination2.",
85                     HostedContentTypeToString(hosted_content_type)}),
86       status, base::TERMINATION_STATUS_MAX_ENUM);
87 }
88 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
89 
90 }  // namespace
91 
StabilityMetricsHelper(PrefService * local_state)92 StabilityMetricsHelper::StabilityMetricsHelper(PrefService* local_state)
93     : local_state_(local_state) {
94   DCHECK(local_state_);
95 }
96 
~StabilityMetricsHelper()97 StabilityMetricsHelper::~StabilityMetricsHelper() {}
98 
99 #if BUILDFLAG(IS_ANDROID)
ProvideStabilityMetrics(SystemProfileProto * system_profile_proto)100 void StabilityMetricsHelper::ProvideStabilityMetrics(
101     SystemProfileProto* system_profile_proto) {
102   SystemProfileProto_Stability* stability_proto =
103       system_profile_proto->mutable_stability();
104 
105   int count = local_state_->GetInteger(prefs::kStabilityPageLoadCount);
106   if (count) {
107     stability_proto->set_page_load_count(count);
108     local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
109   }
110   count = local_state_->GetInteger(prefs::kStabilityRendererLaunchCount);
111   if (count) {
112     stability_proto->set_renderer_launch_count(count);
113     local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
114   }
115 }
116 
ClearSavedStabilityMetrics()117 void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
118   local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
119   local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
120 }
121 #endif  // BUILDFLAG(IS_ANDROID)
122 
123 // static
RegisterPrefs(PrefRegistrySimple * registry)124 void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
125 #if BUILDFLAG(IS_ANDROID)
126   registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
127   registry->RegisterIntegerPref(prefs::kStabilityRendererLaunchCount, 0);
128 #endif  // BUILDFLAG(IS_ANDROID)
129 }
130 
IncreaseRendererCrashCount()131 void StabilityMetricsHelper::IncreaseRendererCrashCount() {
132   RecordStabilityEvent(StabilityEventType::kRendererCrash);
133 }
134 
IncreaseGpuCrashCount()135 void StabilityMetricsHelper::IncreaseGpuCrashCount() {
136   RecordStabilityEvent(StabilityEventType::kGpuCrash);
137 }
138 
BrowserUtilityProcessLaunched(const std::string & metrics_name)139 void StabilityMetricsHelper::BrowserUtilityProcessLaunched(
140     const std::string& metrics_name) {
141   uint32_t hash = variations::HashName(metrics_name);
142   base::UmaHistogramSparse("ChildProcess.Launched.UtilityProcessHash", hash);
143   RecordStabilityEvent(StabilityEventType::kUtilityLaunch);
144 }
145 
BrowserUtilityProcessCrashed(const std::string & metrics_name,int exit_code)146 void StabilityMetricsHelper::BrowserUtilityProcessCrashed(
147     const std::string& metrics_name,
148     int exit_code) {
149   uint32_t hash = variations::HashName(metrics_name);
150   base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessHash", hash);
151   base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessExitCode",
152                            exit_code);
153   RecordStabilityEvent(StabilityEventType::kUtilityCrash);
154 }
155 
BrowserUtilityProcessLaunchFailed(const std::string & metrics_name,int launch_error_code,DWORD last_error)156 void StabilityMetricsHelper::BrowserUtilityProcessLaunchFailed(
157     const std::string& metrics_name,
158     int launch_error_code
159 #if BUILDFLAG(IS_WIN)
160     ,
161     DWORD last_error
162 #endif
163 ) {
164   uint32_t hash = variations::HashName(metrics_name);
165   base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessHash",
166                            hash);
167   base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessErrorCode",
168                            launch_error_code);
169 #if BUILDFLAG(IS_WIN)
170   base::UmaHistogramSparse("ChildProcess.LaunchFailed.WinLastError",
171                            last_error);
172 #endif
173   // TODO(wfh): Decide if this utility process launch failure should also
174   // trigger a Stability Event.
175 }
176 
LogLoadStarted()177 void StabilityMetricsHelper::LogLoadStarted() {
178 #if BUILDFLAG(IS_ANDROID)
179   IncrementPrefValue(prefs::kStabilityPageLoadCount);
180 #endif
181   RecordStabilityEvent(StabilityEventType::kPageLoad);
182 }
183 
184 #if BUILDFLAG(IS_IOS)
LogRendererCrash()185 void StabilityMetricsHelper::LogRendererCrash() {
186   // The actual exit code isn't provided on iOS; use a dummy value.
187   constexpr int kDummyExitCode = 105;
188   LogRendererCrashImpl(CoarseRendererType::kRenderer, kDummyExitCode);
189 }
190 #elif !BUILDFLAG(IS_ANDROID)
LogRendererCrash(RendererHostedContentType hosted_content_type,base::TerminationStatus status,int exit_code)191 void StabilityMetricsHelper::LogRendererCrash(
192     RendererHostedContentType hosted_content_type,
193     base::TerminationStatus status,
194     int exit_code) {
195   RecordRendererAbnormalTerminationByHostedContentType(hosted_content_type,
196                                                        status);
197 
198   CoarseRendererType coarse_renderer_type =
199       hosted_content_type == RendererHostedContentType::kExtension
200           ? CoarseRendererType::kExtension
201           : CoarseRendererType::kRenderer;
202 
203   switch (status) {
204     case base::TERMINATION_STATUS_NORMAL_TERMINATION:
205       break;
206     case base::TERMINATION_STATUS_PROCESS_CRASHED:
207     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
208     case base::TERMINATION_STATUS_OOM:
209       LogRendererCrashImpl(coarse_renderer_type, exit_code);
210       break;
211 #if BUILDFLAG(IS_CHROMEOS)
212     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
213       base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildKills.OOM",
214                                     coarse_renderer_type);
215       [[fallthrough]];
216 #endif  // BUILDFLAG(IS_CHROMEOS)
217     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
218       base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildKills",
219                                     coarse_renderer_type);
220       break;
221     case base::TERMINATION_STATUS_STILL_RUNNING:
222       base::UmaHistogramEnumeration(
223           "BrowserRenderProcessHost.DisconnectedAlive", coarse_renderer_type);
224       break;
225     case base::TERMINATION_STATUS_LAUNCH_FAILED:
226       // TODO(rkaplow): See if we can remove this histogram as we have
227       // Stability.Counts2 which has the same metrics.
228       base::UmaHistogramEnumeration(
229           "BrowserRenderProcessHost.ChildLaunchFailures", coarse_renderer_type);
230       base::UmaHistogramSparse(
231           "BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
232       RecordStabilityEvent(
233           hosted_content_type == RendererHostedContentType::kExtension
234               ? StabilityEventType::kExtensionRendererFailedLaunch
235               : StabilityEventType::kRendererFailedLaunch);
236       break;
237 #if BUILDFLAG(IS_WIN)
238     case base::TERMINATION_STATUS_INTEGRITY_FAILURE:
239       base::UmaHistogramEnumeration(
240           "BrowserRenderProcessHost.ChildCodeIntegrityFailures",
241           coarse_renderer_type);
242       break;
243 #endif
244     case base::TERMINATION_STATUS_MAX_ENUM:
245       NOTREACHED();
246       break;
247   }
248 }
249 #endif  // !BUILDFLAG(IS_ANDROID)
250 
LogRendererLaunched(bool was_extension_process)251 void StabilityMetricsHelper::LogRendererLaunched(bool was_extension_process) {
252   auto metric = was_extension_process
253                     ? StabilityEventType::kExtensionRendererLaunch
254                     : StabilityEventType::kRendererLaunch;
255   RecordStabilityEvent(metric);
256 #if BUILDFLAG(IS_ANDROID)
257   if (!was_extension_process)
258     IncrementPrefValue(prefs::kStabilityRendererLaunchCount);
259 #endif  // BUILDFLAG(IS_ANDROID)
260 }
261 
IncrementPrefValue(const char * path)262 void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
263   int value = local_state_->GetInteger(path);
264   local_state_->SetInteger(path, value + 1);
265 }
266 
267 // static
RecordStabilityEvent(StabilityEventType stability_event_type)268 void StabilityMetricsHelper::RecordStabilityEvent(
269     StabilityEventType stability_event_type) {
270   UMA_STABILITY_HISTOGRAM_ENUMERATION("Stability.Counts2",
271                                       stability_event_type);
272 }
273 
274 #if !BUILDFLAG(IS_ANDROID)
LogRendererCrashImpl(CoarseRendererType renderer_type,int exit_code)275 void StabilityMetricsHelper::LogRendererCrashImpl(
276     CoarseRendererType renderer_type,
277     int exit_code) {
278   if (renderer_type == CoarseRendererType::kExtension) {
279 #if !BUILDFLAG(ENABLE_EXTENSIONS)
280     NOTREACHED();
281 #endif
282     RecordStabilityEvent(StabilityEventType::kExtensionCrash);
283     base::UmaHistogramSparse("CrashExitCodes.Extension",
284                              MapCrashExitCodeForHistogram(exit_code));
285   } else {
286     IncreaseRendererCrashCount();
287     base::UmaHistogramSparse("CrashExitCodes.Renderer",
288                              MapCrashExitCodeForHistogram(exit_code));
289   }
290 
291   base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildCrashes",
292                                 renderer_type);
293 }
294 #endif  // !BUILDFLAG(IS_ANDROID)
295 
296 }  // namespace metrics
297