• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CdmMetricsNameToUmaPrefix(const std::string & metrics_name)90 std::string CdmMetricsNameToUmaPrefix(const std::string& metrics_name) {
91   const std::string uma_prefix = "Stability.Media.";
92 
93   if (metrics_name == "media.mojom.CdmServiceBroker") {
94     return uma_prefix + "CdmServiceBroker.";
95   } else if (metrics_name == "media.mojom.MediaFoundationServiceBroker") {
96     return uma_prefix + "MediaFoundationServiceBroker.";
97   }
98 
99   NOTREACHED();
100 }
101 
102 }  // namespace
103 
StabilityMetricsHelper(PrefService * local_state)104 StabilityMetricsHelper::StabilityMetricsHelper(PrefService* local_state)
105     : local_state_(local_state) {
106   DCHECK(local_state_);
107 }
108 
109 StabilityMetricsHelper::~StabilityMetricsHelper() = default;
110 
111 #if BUILDFLAG(IS_ANDROID)
ProvideStabilityMetrics(SystemProfileProto * system_profile_proto)112 void StabilityMetricsHelper::ProvideStabilityMetrics(
113     SystemProfileProto* system_profile_proto) {
114   SystemProfileProto_Stability* stability_proto =
115       system_profile_proto->mutable_stability();
116 
117   int count = local_state_->GetInteger(prefs::kStabilityPageLoadCount);
118   if (count) {
119     stability_proto->set_page_load_count(count);
120     local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
121   }
122   count = local_state_->GetInteger(prefs::kStabilityRendererLaunchCount);
123   if (count) {
124     stability_proto->set_renderer_launch_count(count);
125     local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
126   }
127 }
128 
ClearSavedStabilityMetrics()129 void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
130   local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
131   local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
132 }
133 #endif  // BUILDFLAG(IS_ANDROID)
134 
135 // static
RegisterPrefs(PrefRegistrySimple * registry)136 void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
137 #if BUILDFLAG(IS_ANDROID)
138   registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
139   registry->RegisterIntegerPref(prefs::kStabilityRendererLaunchCount, 0);
140 #endif  // BUILDFLAG(IS_ANDROID)
141 }
142 
IncreaseRendererCrashCount()143 void StabilityMetricsHelper::IncreaseRendererCrashCount() {
144   RecordStabilityEvent(StabilityEventType::kRendererCrash);
145 }
146 
IncreaseGpuCrashCount()147 void StabilityMetricsHelper::IncreaseGpuCrashCount() {
148   RecordStabilityEvent(StabilityEventType::kGpuCrash);
149 }
150 
BrowserUtilityProcessLaunched(const std::string & metrics_name)151 void StabilityMetricsHelper::BrowserUtilityProcessLaunched(
152     const std::string& metrics_name) {
153   uint32_t hash = variations::HashName(metrics_name);
154   base::UmaHistogramSparse("ChildProcess.Launched.UtilityProcessHash", hash);
155   RecordStabilityEvent(StabilityEventType::kUtilityLaunch);
156 }
157 
BrowserUtilityProcessCrashed(const std::string & metrics_name,int exit_code)158 void StabilityMetricsHelper::BrowserUtilityProcessCrashed(
159     const std::string& metrics_name,
160     int exit_code) {
161   uint32_t hash = variations::HashName(metrics_name);
162   base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessHash", hash);
163   base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessExitCode",
164                            exit_code);
165   RecordStabilityEvent(StabilityEventType::kUtilityCrash);
166 }
167 
BrowserUtilityProcessLaunchFailed(const std::string & metrics_name,int launch_error_code,DWORD last_error)168 void StabilityMetricsHelper::BrowserUtilityProcessLaunchFailed(
169     const std::string& metrics_name,
170     int launch_error_code
171 #if BUILDFLAG(IS_WIN)
172     ,
173     DWORD last_error
174 #endif
175 ) {
176   uint32_t hash = variations::HashName(metrics_name);
177   base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessHash",
178                            hash);
179   base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessErrorCode",
180                            launch_error_code);
181 #if BUILDFLAG(IS_WIN)
182   base::UmaHistogramSparse("ChildProcess.LaunchFailed.WinLastError",
183                            last_error);
184 #endif
185   // TODO(wfh): Decide if this utility process launch failure should also
186   // trigger a Stability Event.
187 }
188 
CdmUtilityProcessLaunched(const std::string & metrics_name)189 void StabilityMetricsHelper::CdmUtilityProcessLaunched(
190     const std::string& metrics_name) {
191   DVLOG(3) << __func__ << ": metrics_name=" << metrics_name;
192 
193   // If failed to launch, we will record the same UMA as False in
194   // `CdmUtilityProcessLaunchFailed()` method.
195   base::UmaHistogramBoolean(CdmMetricsNameToUmaPrefix(metrics_name) + "Launch",
196                             true);
197 }
198 
CdmUtilityProcessCrashed(const std::string & metrics_name,int exit_code)199 void StabilityMetricsHelper::CdmUtilityProcessCrashed(
200     const std::string& metrics_name,
201     int exit_code) {
202   DVLOG(3) << __func__ << ": metrics_name=" << metrics_name
203            << ", exit_code=" << exit_code;
204 
205   base::UmaHistogramSparse(
206       CdmMetricsNameToUmaPrefix(metrics_name) + "Crash.ExitCode", exit_code);
207 }
208 
CdmUtilityProcessLaunchFailed(const std::string & metrics_name,int launch_error_code,DWORD last_error)209 void StabilityMetricsHelper::CdmUtilityProcessLaunchFailed(
210     const std::string& metrics_name,
211     int launch_error_code
212 #if BUILDFLAG(IS_WIN)
213     ,
214     DWORD last_error
215 #endif
216 ) {
217   DVLOG(3) << __func__ << ": metrics_name=" << metrics_name
218 #if BUILDFLAG(IS_WIN)
219            << ", launch_error_code=" << launch_error_code
220            << ", last_error=" << last_error;
221 #else
222            << ", launch_error_code=" << launch_error_code;
223 #endif
224 
225   base::UmaHistogramBoolean(CdmMetricsNameToUmaPrefix(metrics_name) + "Launch",
226                             false);
227   base::UmaHistogramSparse(
228       CdmMetricsNameToUmaPrefix(metrics_name) + "Launch.LaunchErrorCode",
229       launch_error_code);
230 #if BUILDFLAG(IS_WIN)
231   base::UmaHistogramSparse(
232       CdmMetricsNameToUmaPrefix(metrics_name) + "Launch.WinLastError",
233       last_error);
234 #endif
235 }
236 
LogLoadStarted()237 void StabilityMetricsHelper::LogLoadStarted() {
238 #if BUILDFLAG(IS_ANDROID)
239   IncrementPrefValue(prefs::kStabilityPageLoadCount);
240 #endif
241   RecordStabilityEvent(StabilityEventType::kPageLoad);
242 }
243 
244 #if BUILDFLAG(IS_IOS)
LogRendererCrash()245 void StabilityMetricsHelper::LogRendererCrash() {
246   // The actual exit code isn't provided on iOS; use a dummy value.
247   constexpr int kDummyExitCode = 105;
248   LogRendererCrashImpl(CoarseRendererType::kRenderer, kDummyExitCode);
249 }
250 #elif !BUILDFLAG(IS_ANDROID)
LogRendererCrash(RendererHostedContentType hosted_content_type,base::TerminationStatus status,int exit_code)251 void StabilityMetricsHelper::LogRendererCrash(
252     RendererHostedContentType hosted_content_type,
253     base::TerminationStatus status,
254     int exit_code) {
255   RecordRendererAbnormalTerminationByHostedContentType(hosted_content_type,
256                                                        status);
257 
258   CoarseRendererType coarse_renderer_type =
259       hosted_content_type == RendererHostedContentType::kExtension
260           ? CoarseRendererType::kExtension
261           : CoarseRendererType::kRenderer;
262 
263   switch (status) {
264     case base::TERMINATION_STATUS_NORMAL_TERMINATION:
265       break;
266     case base::TERMINATION_STATUS_PROCESS_CRASHED:
267     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
268     case base::TERMINATION_STATUS_OOM:
269       LogRendererCrashImpl(coarse_renderer_type, exit_code);
270       break;
271 #if BUILDFLAG(IS_CHROMEOS)
272     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
273       base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildKills.OOM",
274                                     coarse_renderer_type);
275       [[fallthrough]];
276 #endif  // BUILDFLAG(IS_CHROMEOS)
277     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
278       base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildKills",
279                                     coarse_renderer_type);
280       break;
281     case base::TERMINATION_STATUS_STILL_RUNNING:
282       base::UmaHistogramEnumeration(
283           "BrowserRenderProcessHost.DisconnectedAlive", coarse_renderer_type);
284       break;
285     case base::TERMINATION_STATUS_LAUNCH_FAILED:
286       // TODO(rkaplow): See if we can remove this histogram as we have
287       // Stability.Counts2 which has the same metrics.
288       base::UmaHistogramEnumeration(
289           "BrowserRenderProcessHost.ChildLaunchFailures", coarse_renderer_type);
290       base::UmaHistogramSparse(
291           "BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
292       RecordStabilityEvent(
293           hosted_content_type == RendererHostedContentType::kExtension
294               ? StabilityEventType::kExtensionRendererFailedLaunch
295               : StabilityEventType::kRendererFailedLaunch);
296       break;
297 #if BUILDFLAG(IS_WIN)
298     case base::TERMINATION_STATUS_INTEGRITY_FAILURE:
299       base::UmaHistogramEnumeration(
300           "BrowserRenderProcessHost.ChildCodeIntegrityFailures",
301           coarse_renderer_type);
302       break;
303 #endif
304     case base::TERMINATION_STATUS_MAX_ENUM:
305       NOTREACHED();
306   }
307 }
308 #endif  // !BUILDFLAG(IS_ANDROID)
309 
LogRendererLaunched(bool was_extension_process)310 void StabilityMetricsHelper::LogRendererLaunched(bool was_extension_process) {
311   auto metric = was_extension_process
312                     ? StabilityEventType::kExtensionRendererLaunch
313                     : StabilityEventType::kRendererLaunch;
314   RecordStabilityEvent(metric);
315 #if BUILDFLAG(IS_ANDROID)
316   if (!was_extension_process)
317     IncrementPrefValue(prefs::kStabilityRendererLaunchCount);
318 #endif  // BUILDFLAG(IS_ANDROID)
319 }
320 
IncrementPrefValue(const char * path)321 void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
322   int value = local_state_->GetInteger(path);
323   local_state_->SetInteger(path, value + 1);
324 }
325 
326 // static
RecordStabilityEvent(StabilityEventType stability_event_type)327 void StabilityMetricsHelper::RecordStabilityEvent(
328     StabilityEventType stability_event_type) {
329   UMA_STABILITY_HISTOGRAM_ENUMERATION("Stability.Counts2",
330                                       stability_event_type);
331 }
332 
333 #if !BUILDFLAG(IS_ANDROID)
LogRendererCrashImpl(CoarseRendererType renderer_type,int exit_code)334 void StabilityMetricsHelper::LogRendererCrashImpl(
335     CoarseRendererType renderer_type,
336     int exit_code) {
337   if (renderer_type == CoarseRendererType::kExtension) {
338 #if BUILDFLAG(ENABLE_EXTENSIONS)
339     RecordStabilityEvent(StabilityEventType::kExtensionCrash);
340     base::UmaHistogramSparse("CrashExitCodes.Extension",
341                              MapCrashExitCodeForHistogram(exit_code));
342 #else
343     NOTREACHED();
344 #endif
345   } else {
346     IncreaseRendererCrashCount();
347     base::UmaHistogramSparse("CrashExitCodes.Renderer",
348                              MapCrashExitCodeForHistogram(exit_code));
349   }
350 
351   base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildCrashes",
352                                 renderer_type);
353 }
354 #endif  // !BUILDFLAG(IS_ANDROID)
355 
356 }  // namespace metrics
357