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