• 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/metrics/histogram_functions.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/system/sys_info.h"
15 #include "build/build_config.h"
16 #include "build/buildflag.h"
17 #include "components/metrics/metrics_pref_names.h"
18 #include "components/prefs/pref_registry_simple.h"
19 #include "components/prefs/pref_service.h"
20 #include "components/variations/hashing.h"
21 #include "extensions/buildflags/buildflags.h"
22 #include "third_party/metrics_proto/system_profile.pb.h"
23 
24 #if BUILDFLAG(IS_WIN)
25 #include <windows.h>  // Needed for STATUS_* codes
26 #endif
27 
28 #if BUILDFLAG(IS_ANDROID)
29 #include "base/android/application_status_listener.h"
30 #endif
31 
32 namespace metrics {
33 namespace {
34 
35 enum RendererType {
36   RENDERER_TYPE_RENDERER = 1,
37   RENDERER_TYPE_EXTENSION,
38   // NOTE: Add new action types only immediately above this line. Also,
39   // make sure the enum list in tools/metrics/histograms/histograms.xml is
40   // updated with any change in here.
41   RENDERER_TYPE_COUNT
42 };
43 
44 #if !BUILDFLAG(IS_ANDROID)
45 // Converts an exit code into something that can be inserted into our
46 // histograms (which expect non-negative numbers less than MAX_INT).
MapCrashExitCodeForHistogram(int exit_code)47 int MapCrashExitCodeForHistogram(int exit_code) {
48 #if BUILDFLAG(IS_WIN)
49   // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
50   // histograms.cc. Solve this by remapping it to a smaller value, which
51   // hopefully doesn't conflict with other codes.
52   if (static_cast<DWORD>(exit_code) == STATUS_GUARD_PAGE_VIOLATION)
53     return 0x1FCF7EC3;  // Randomly picked number.
54 #endif
55 
56   return std::abs(exit_code);
57 }
58 
RecordChildKills(RendererType histogram_type)59 void RecordChildKills(RendererType histogram_type) {
60   base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildKills",
61                                 histogram_type, RENDERER_TYPE_COUNT);
62 }
63 #endif  // !BUILDFLAG(IS_ANDROID)
64 
65 }  // namespace
66 
StabilityMetricsHelper(PrefService * local_state)67 StabilityMetricsHelper::StabilityMetricsHelper(PrefService* local_state)
68     : local_state_(local_state) {
69   DCHECK(local_state_);
70 }
71 
~StabilityMetricsHelper()72 StabilityMetricsHelper::~StabilityMetricsHelper() {}
73 
74 #if BUILDFLAG(IS_ANDROID)
ProvideStabilityMetrics(SystemProfileProto * system_profile_proto)75 void StabilityMetricsHelper::ProvideStabilityMetrics(
76     SystemProfileProto* system_profile_proto) {
77   SystemProfileProto_Stability* stability_proto =
78       system_profile_proto->mutable_stability();
79 
80   int count = local_state_->GetInteger(prefs::kStabilityPageLoadCount);
81   if (count) {
82     stability_proto->set_page_load_count(count);
83     local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
84   }
85   count = local_state_->GetInteger(prefs::kStabilityRendererLaunchCount);
86   if (count) {
87     stability_proto->set_renderer_launch_count(count);
88     local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
89   }
90 }
91 
ClearSavedStabilityMetrics()92 void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
93   local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
94   local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
95 }
96 #endif  // BUILDFLAG(IS_ANDROID)
97 
98 // static
RegisterPrefs(PrefRegistrySimple * registry)99 void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
100 #if BUILDFLAG(IS_ANDROID)
101   registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
102   registry->RegisterIntegerPref(prefs::kStabilityRendererLaunchCount, 0);
103 #endif  // BUILDFLAG(IS_ANDROID)
104 }
105 
IncreaseRendererCrashCount()106 void StabilityMetricsHelper::IncreaseRendererCrashCount() {
107   RecordStabilityEvent(StabilityEventType::kRendererCrash);
108 }
109 
IncreaseGpuCrashCount()110 void StabilityMetricsHelper::IncreaseGpuCrashCount() {
111   RecordStabilityEvent(StabilityEventType::kGpuCrash);
112 }
113 
BrowserUtilityProcessLaunched(const std::string & metrics_name)114 void StabilityMetricsHelper::BrowserUtilityProcessLaunched(
115     const std::string& metrics_name) {
116   uint32_t hash = variations::HashName(metrics_name);
117   base::UmaHistogramSparse("ChildProcess.Launched.UtilityProcessHash", hash);
118   RecordStabilityEvent(StabilityEventType::kUtilityLaunch);
119 }
120 
BrowserUtilityProcessCrashed(const std::string & metrics_name,int exit_code)121 void StabilityMetricsHelper::BrowserUtilityProcessCrashed(
122     const std::string& metrics_name,
123     int exit_code) {
124   uint32_t hash = variations::HashName(metrics_name);
125   base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessHash", hash);
126   base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessExitCode",
127                            exit_code);
128   RecordStabilityEvent(StabilityEventType::kUtilityCrash);
129 }
130 
BrowserUtilityProcessLaunchFailed(const std::string & metrics_name,int launch_error_code,DWORD last_error)131 void StabilityMetricsHelper::BrowserUtilityProcessLaunchFailed(
132     const std::string& metrics_name,
133     int launch_error_code
134 #if BUILDFLAG(IS_WIN)
135     ,
136     DWORD last_error
137 #endif
138 ) {
139   uint32_t hash = variations::HashName(metrics_name);
140   base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessHash",
141                            hash);
142   base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessErrorCode",
143                            launch_error_code);
144 #if BUILDFLAG(IS_WIN)
145   base::UmaHistogramSparse("ChildProcess.LaunchFailed.WinLastError",
146                            last_error);
147 #endif
148   // TODO(wfh): Decide if this utility process launch failure should also
149   // trigger a Stability Event.
150 }
151 
LogLoadStarted()152 void StabilityMetricsHelper::LogLoadStarted() {
153 #if BUILDFLAG(IS_ANDROID)
154   IncrementPrefValue(prefs::kStabilityPageLoadCount);
155 #endif
156   RecordStabilityEvent(StabilityEventType::kPageLoad);
157 }
158 
159 #if !BUILDFLAG(IS_ANDROID)
LogRendererCrash(bool was_extension_process,base::TerminationStatus status,int exit_code)160 void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
161                                               base::TerminationStatus status,
162                                               int exit_code) {
163   RendererType histogram_type =
164       was_extension_process ? RENDERER_TYPE_EXTENSION : RENDERER_TYPE_RENDERER;
165 
166   switch (status) {
167     case base::TERMINATION_STATUS_NORMAL_TERMINATION:
168       break;
169     case base::TERMINATION_STATUS_PROCESS_CRASHED:
170     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
171     case base::TERMINATION_STATUS_OOM:
172       if (was_extension_process) {
173 #if !BUILDFLAG(ENABLE_EXTENSIONS)
174         NOTREACHED();
175 #endif
176         RecordStabilityEvent(StabilityEventType::kExtensionCrash);
177         base::UmaHistogramSparse("CrashExitCodes.Extension",
178                                  MapCrashExitCodeForHistogram(exit_code));
179       } else {
180         IncreaseRendererCrashCount();
181         base::UmaHistogramSparse("CrashExitCodes.Renderer",
182                                  MapCrashExitCodeForHistogram(exit_code));
183       }
184 
185       base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildCrashes",
186                                     histogram_type, RENDERER_TYPE_COUNT);
187       break;
188     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
189       RecordChildKills(histogram_type);
190       break;
191 #if BUILDFLAG(IS_CHROMEOS)
192     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
193       RecordChildKills(histogram_type);
194       base::UmaHistogramExactLinear("BrowserRenderProcessHost.ChildKills.OOM",
195                                     was_extension_process ? 2 : 1, 3);
196       break;
197 #endif
198     case base::TERMINATION_STATUS_STILL_RUNNING:
199       base::UmaHistogramEnumeration(
200           "BrowserRenderProcessHost.DisconnectedAlive", histogram_type,
201           RENDERER_TYPE_COUNT);
202       break;
203     case base::TERMINATION_STATUS_LAUNCH_FAILED:
204       // TODO(rkaplow): See if we can remove this histogram as we have
205       // Stability.Counts2 which has the same metrics.
206       base::UmaHistogramEnumeration(
207           "BrowserRenderProcessHost.ChildLaunchFailures", histogram_type,
208           RENDERER_TYPE_COUNT);
209       base::UmaHistogramSparse(
210           "BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
211       LogRendererLaunchFailed(was_extension_process);
212       break;
213 #if BUILDFLAG(IS_WIN)
214     case base::TERMINATION_STATUS_INTEGRITY_FAILURE:
215       base::UmaHistogramEnumeration(
216           "BrowserRenderProcessHost.ChildCodeIntegrityFailures", histogram_type,
217           RENDERER_TYPE_COUNT);
218       break;
219 #endif
220     case base::TERMINATION_STATUS_MAX_ENUM:
221       NOTREACHED();
222       break;
223   }
224 }
225 #endif  // !BUILDFLAG(IS_ANDROID)
226 
LogRendererLaunched(bool was_extension_process)227 void StabilityMetricsHelper::LogRendererLaunched(bool was_extension_process) {
228   auto metric = was_extension_process
229                     ? StabilityEventType::kExtensionRendererLaunch
230                     : StabilityEventType::kRendererLaunch;
231   RecordStabilityEvent(metric);
232 #if BUILDFLAG(IS_ANDROID)
233   if (!was_extension_process)
234     IncrementPrefValue(prefs::kStabilityRendererLaunchCount);
235 #endif  // BUILDFLAG(IS_ANDROID)
236 }
237 
LogRendererLaunchFailed(bool was_extension_process)238 void StabilityMetricsHelper::LogRendererLaunchFailed(
239     bool was_extension_process) {
240   auto metric = was_extension_process
241                     ? StabilityEventType::kExtensionRendererFailedLaunch
242                     : StabilityEventType::kRendererFailedLaunch;
243   RecordStabilityEvent(metric);
244 }
245 
IncrementPrefValue(const char * path)246 void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
247   int value = local_state_->GetInteger(path);
248   local_state_->SetInteger(path, value + 1);
249 }
250 
251 // static
RecordStabilityEvent(StabilityEventType stability_event_type)252 void StabilityMetricsHelper::RecordStabilityEvent(
253     StabilityEventType stability_event_type) {
254   UMA_STABILITY_HISTOGRAM_ENUMERATION("Stability.Counts2",
255                                       stability_event_type);
256 }
257 
258 }  // namespace metrics
259