OLD | NEW |
---|---|
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/browser_watcher/watcher_metrics_provider_win.h" | 5 #include "components/browser_watcher/watcher_metrics_provider_win.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <limits> | 9 #include <limits> |
10 #include <memory> | |
11 #include <set> | |
10 #include <vector> | 12 #include <vector> |
11 | 13 |
12 #include "base/bind.h" | 14 #include "base/bind.h" |
15 #include "base/feature_list.h" | |
16 #include "base/metrics/histogram_macros.h" | |
13 #include "base/metrics/sparse_histogram.h" | 17 #include "base/metrics/sparse_histogram.h" |
14 #include "base/process/process.h" | 18 #include "base/process/process.h" |
15 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/string_piece.h" | 20 #include "base/strings/string_piece.h" |
17 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
18 #include "base/win/registry.h" | 22 #include "base/win/registry.h" |
23 #include "components/browser_watcher/features.h" | |
24 #include "components/browser_watcher/postmortem_report_collector.h" | |
25 #include "components/browser_watcher/stability_debugging_win.h" | |
26 #include "third_party/crashpad/crashpad/client/crash_report_database.h" | |
19 | 27 |
20 namespace browser_watcher { | 28 namespace browser_watcher { |
21 | 29 |
22 namespace { | 30 namespace { |
23 | 31 |
24 // Process ID APIs on Windows talk in DWORDs, whereas for string formatting | 32 // Process ID APIs on Windows talk in DWORDs, whereas for string formatting |
25 // and parsing, this code uses int. In practice there are no process IDs with | 33 // and parsing, this code uses int. In practice there are no process IDs with |
26 // the high bit set on Windows, so there's no danger of overflow if this is | 34 // the high bit set on Windows, so there's no danger of overflow if this is |
27 // done consistently. | 35 // done consistently. |
28 static_assert(sizeof(DWORD) == sizeof(int), | 36 static_assert(sizeof(DWORD) == sizeof(int), |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
185 DVLOG(1) << "Failed to delete exit code key " << registry_path; | 193 DVLOG(1) << "Failed to delete exit code key " << registry_path; |
186 } | 194 } |
187 | 195 |
188 } // namespace | 196 } // namespace |
189 | 197 |
190 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = | 198 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = |
191 "Stability.BrowserExitCodes"; | 199 "Stability.BrowserExitCodes"; |
192 | 200 |
193 WatcherMetricsProviderWin::WatcherMetricsProviderWin( | 201 WatcherMetricsProviderWin::WatcherMetricsProviderWin( |
194 const base::string16& registry_path, | 202 const base::string16& registry_path, |
195 base::TaskRunner* cleanup_io_task_runner) | 203 const base::FilePath& user_data_dir, |
204 const base::FilePath& crash_dir, | |
205 base::TaskRunner* io_task_runner) | |
196 : recording_enabled_(false), | 206 : recording_enabled_(false), |
197 cleanup_scheduled_(false), | 207 cleanup_scheduled_(false), |
198 registry_path_(registry_path), | 208 registry_path_(registry_path), |
199 cleanup_io_task_runner_(cleanup_io_task_runner) { | 209 user_data_dir_(user_data_dir), |
200 DCHECK(cleanup_io_task_runner_); | 210 crash_dir_(crash_dir), |
211 io_task_runner_(io_task_runner), | |
212 weak_ptr_factory_(this) { | |
213 DCHECK(io_task_runner_); | |
201 } | 214 } |
202 | 215 |
203 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { | 216 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { |
204 } | 217 } |
205 | 218 |
206 void WatcherMetricsProviderWin::OnRecordingEnabled() { | 219 void WatcherMetricsProviderWin::OnRecordingEnabled() { |
207 recording_enabled_ = true; | 220 recording_enabled_ = true; |
208 } | 221 } |
209 | 222 |
210 void WatcherMetricsProviderWin::OnRecordingDisabled() { | 223 void WatcherMetricsProviderWin::OnRecordingDisabled() { |
211 if (!recording_enabled_ && !cleanup_scheduled_) { | 224 if (!recording_enabled_ && !cleanup_scheduled_) { |
212 // When metrics reporting is disabled, the providers get an | 225 // When metrics reporting is disabled, the providers get an |
213 // OnRecordingDisabled notification at startup. Use that first notification | 226 // OnRecordingDisabled notification at startup. Use that first notification |
214 // to issue the cleanup task. | 227 // to issue the cleanup task. |
215 cleanup_io_task_runner_->PostTask( | 228 io_task_runner_->PostTask( |
216 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); | 229 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); |
217 | 230 |
218 cleanup_scheduled_ = true; | 231 cleanup_scheduled_ = true; |
219 } | 232 } |
220 } | 233 } |
221 | 234 |
222 void WatcherMetricsProviderWin::ProvideStabilityMetrics( | 235 void WatcherMetricsProviderWin::ProvideStabilityMetrics( |
223 metrics::SystemProfileProto* /* system_profile_proto */) { | 236 metrics::SystemProfileProto* /* system_profile_proto */) { |
224 // Note that if there are multiple instances of Chrome running in the same | 237 // Note that if there are multiple instances of Chrome running in the same |
225 // user account, there's a small race that will double-report the exit codes | 238 // user account, there's a small race that will double-report the exit codes |
226 // from both/multiple instances. This ought to be vanishingly rare and will | 239 // from both/multiple instances. This ought to be vanishingly rare and will |
227 // only manifest as low-level "random" noise. To work around this it would be | 240 // only manifest as low-level "random" noise. To work around this it would be |
228 // necessary to implement some form of global locking, which is not worth it | 241 // necessary to implement some form of global locking, which is not worth it |
229 // here. | 242 // here. |
230 RecordExitCodes(registry_path_); | 243 RecordExitCodes(registry_path_); |
231 DeleteExitFunnels(registry_path_); | 244 DeleteExitFunnels(registry_path_); |
232 } | 245 } |
233 | 246 |
247 void WatcherMetricsProviderWin::CollectPostmortemReports( | |
248 const base::Closure& done_callback) { | |
249 io_task_runner_->PostTaskAndReply( | |
250 FROM_HERE, | |
251 base::Bind( | |
252 &WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool, | |
253 weak_ptr_factory_.GetWeakPtr()), | |
254 done_callback); | |
255 } | |
256 | |
257 void WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool() { | |
258 // Note: the feature controls both instrumentation and collection. | |
259 bool is_stability_debugging_on = | |
260 base::FeatureList::IsEnabled(browser_watcher::kStabilityDebuggingFeature); | |
261 if (!is_stability_debugging_on) { | |
262 // TODO(manzagop): delete possible leftover data. | |
263 return; | |
264 } | |
265 | |
266 SCOPED_UMA_HISTOGRAM_TIMER("ActivityTracker.Collect.TotalTime"); | |
267 | |
268 if (user_data_dir_.empty() || crash_dir_.empty()) { | |
269 LOG(ERROR) << "User data directory or crash directory is unknown."; | |
Sigurður Ásgeirsson
2016/09/19 14:20:05
I would suggest a second UMA metric to count failu
manzagop (departed)
2016/09/21 22:00:43
Done.
| |
270 return; | |
271 } | |
272 | |
273 // Determine the stability directory and the stability file for the current | |
274 // process. | |
275 base::FilePath stability_dir = StabilityDebugging::GetDir(user_data_dir_); | |
276 base::FilePath current_stability_file; | |
277 if (!StabilityDebugging::GetFileForProcess( | |
278 base::Process::Current(), user_data_dir_, ¤t_stability_file)) { | |
279 LOG(ERROR) << "Failed to get the current stability file."; | |
280 return; | |
281 } | |
282 const std::set<base::FilePath>& excluded_debug_files = { | |
283 current_stability_file}; | |
284 | |
285 // Create a database. Note: Chrome already has a g_database in crashpad.cc but | |
286 // it has internal linkage. Create a new one. | |
287 std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database = | |
288 crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir_); | |
289 if (!crashpad_database) { | |
290 LOG(ERROR) << "Failed to initialize a CrashPad database."; | |
291 return; | |
292 } | |
293 | |
294 // TODO(manzagop): fix incorrect version attribution on update. | |
295 PostmortemReportCollector collector; | |
296 collector.CollectAndSubmitForUpload( | |
297 stability_dir, StabilityDebugging::GetFilePattern(), excluded_debug_files, | |
298 crashpad_database.get()); | |
299 } | |
300 | |
234 } // namespace browser_watcher | 301 } // namespace browser_watcher |
OLD | NEW |