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