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.h" |
| 17 #include "base/metrics/histogram_base.h" |
| 18 #include "base/metrics/histogram_macros.h" |
13 #include "base/metrics/sparse_histogram.h" | 19 #include "base/metrics/sparse_histogram.h" |
14 #include "base/process/process.h" | 20 #include "base/process/process.h" |
15 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/string_piece.h" | 22 #include "base/strings/string_piece.h" |
17 #include "base/strings/utf_string_conversions.h" | 23 #include "base/strings/utf_string_conversions.h" |
18 #include "base/win/registry.h" | 24 #include "base/win/registry.h" |
| 25 #include "components/browser_watcher/features.h" |
| 26 #include "components/browser_watcher/postmortem_report_collector.h" |
| 27 #include "components/browser_watcher/stability_debugging_win.h" |
| 28 #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
19 | 29 |
20 namespace browser_watcher { | 30 namespace browser_watcher { |
21 | 31 |
22 namespace { | 32 namespace { |
23 | 33 |
24 // Process ID APIs on Windows talk in DWORDs, whereas for string formatting | 34 // 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 | 35 // 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 | 36 // the high bit set on Windows, so there's no danger of overflow if this is |
27 // done consistently. | 37 // done consistently. |
28 static_assert(sizeof(DWORD) == sizeof(int), | 38 static_assert(sizeof(DWORD) == sizeof(int), |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 LONG res = key.Open(HKEY_CURRENT_USER, registry_path.c_str(), | 188 LONG res = key.Open(HKEY_CURRENT_USER, registry_path.c_str(), |
179 KEY_QUERY_VALUE | KEY_SET_VALUE); | 189 KEY_QUERY_VALUE | KEY_SET_VALUE); |
180 if (res == ERROR_SUCCESS) { | 190 if (res == ERROR_SUCCESS) { |
181 DeleteAllValues(&key); | 191 DeleteAllValues(&key); |
182 res = key.DeleteEmptyKey(L""); | 192 res = key.DeleteEmptyKey(L""); |
183 } | 193 } |
184 if (res != ERROR_FILE_NOT_FOUND && res != ERROR_SUCCESS) | 194 if (res != ERROR_FILE_NOT_FOUND && res != ERROR_SUCCESS) |
185 DVLOG(1) << "Failed to delete exit code key " << registry_path; | 195 DVLOG(1) << "Failed to delete exit code key " << registry_path; |
186 } | 196 } |
187 | 197 |
| 198 enum CollectionInitializationStatus { |
| 199 INIT_SUCCESS = 0, |
| 200 UNKNOWN_DIR = 1, |
| 201 GET_STABILITY_FILE_PATH_FAILED = 2, |
| 202 CRASHPAD_DATABASE_INIT_FAILED = 3, |
| 203 INIT_STATUS_MAX = 4 |
| 204 }; |
| 205 |
| 206 void LogCollectionInitStatus(CollectionInitializationStatus status) { |
| 207 UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.InitStatus", status, |
| 208 INIT_STATUS_MAX); |
| 209 } |
| 210 |
188 } // namespace | 211 } // namespace |
189 | 212 |
190 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = | 213 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = |
191 "Stability.BrowserExitCodes"; | 214 "Stability.BrowserExitCodes"; |
192 | 215 |
193 WatcherMetricsProviderWin::WatcherMetricsProviderWin( | 216 WatcherMetricsProviderWin::WatcherMetricsProviderWin( |
194 const base::string16& registry_path, | 217 const base::string16& registry_path, |
195 base::TaskRunner* cleanup_io_task_runner) | 218 const base::FilePath& user_data_dir, |
| 219 const base::FilePath& crash_dir, |
| 220 base::TaskRunner* io_task_runner) |
196 : recording_enabled_(false), | 221 : recording_enabled_(false), |
197 cleanup_scheduled_(false), | 222 cleanup_scheduled_(false), |
198 registry_path_(registry_path), | 223 registry_path_(registry_path), |
199 cleanup_io_task_runner_(cleanup_io_task_runner) { | 224 user_data_dir_(user_data_dir), |
200 DCHECK(cleanup_io_task_runner_); | 225 crash_dir_(crash_dir), |
| 226 io_task_runner_(io_task_runner), |
| 227 weak_ptr_factory_(this) { |
| 228 DCHECK(io_task_runner_); |
201 } | 229 } |
202 | 230 |
203 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { | 231 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { |
204 } | 232 } |
205 | 233 |
206 void WatcherMetricsProviderWin::OnRecordingEnabled() { | 234 void WatcherMetricsProviderWin::OnRecordingEnabled() { |
207 recording_enabled_ = true; | 235 recording_enabled_ = true; |
208 } | 236 } |
209 | 237 |
210 void WatcherMetricsProviderWin::OnRecordingDisabled() { | 238 void WatcherMetricsProviderWin::OnRecordingDisabled() { |
211 if (!recording_enabled_ && !cleanup_scheduled_) { | 239 if (!recording_enabled_ && !cleanup_scheduled_) { |
212 // When metrics reporting is disabled, the providers get an | 240 // When metrics reporting is disabled, the providers get an |
213 // OnRecordingDisabled notification at startup. Use that first notification | 241 // OnRecordingDisabled notification at startup. Use that first notification |
214 // to issue the cleanup task. | 242 // to issue the cleanup task. |
215 cleanup_io_task_runner_->PostTask( | 243 io_task_runner_->PostTask( |
216 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); | 244 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); |
217 | 245 |
218 cleanup_scheduled_ = true; | 246 cleanup_scheduled_ = true; |
219 } | 247 } |
220 } | 248 } |
221 | 249 |
222 void WatcherMetricsProviderWin::ProvideStabilityMetrics( | 250 void WatcherMetricsProviderWin::ProvideStabilityMetrics( |
223 metrics::SystemProfileProto* /* system_profile_proto */) { | 251 metrics::SystemProfileProto* /* system_profile_proto */) { |
224 // Note that if there are multiple instances of Chrome running in the same | 252 // 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 | 253 // 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 | 254 // 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 | 255 // 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 | 256 // necessary to implement some form of global locking, which is not worth it |
229 // here. | 257 // here. |
230 RecordExitCodes(registry_path_); | 258 RecordExitCodes(registry_path_); |
231 DeleteExitFunnels(registry_path_); | 259 DeleteExitFunnels(registry_path_); |
232 } | 260 } |
233 | 261 |
| 262 void WatcherMetricsProviderWin::CollectPostmortemReports( |
| 263 const base::Closure& done_callback) { |
| 264 io_task_runner_->PostTaskAndReply( |
| 265 FROM_HERE, |
| 266 base::Bind( |
| 267 &WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool, |
| 268 weak_ptr_factory_.GetWeakPtr()), |
| 269 done_callback); |
| 270 } |
| 271 |
| 272 void WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool() { |
| 273 // Note: the feature controls both instrumentation and collection. |
| 274 bool is_stability_debugging_on = |
| 275 base::FeatureList::IsEnabled(browser_watcher::kStabilityDebuggingFeature); |
| 276 if (!is_stability_debugging_on) { |
| 277 // TODO(manzagop): delete possible leftover data. |
| 278 return; |
| 279 } |
| 280 |
| 281 SCOPED_UMA_HISTOGRAM_TIMER("ActivityTracker.Collect.TotalTime"); |
| 282 |
| 283 if (user_data_dir_.empty() || crash_dir_.empty()) { |
| 284 LOG(ERROR) << "User data directory or crash directory is unknown."; |
| 285 LogCollectionInitStatus(UNKNOWN_DIR); |
| 286 return; |
| 287 } |
| 288 |
| 289 // Determine the stability directory and the stability file for the current |
| 290 // process. |
| 291 base::FilePath stability_dir = GetStabilityDir(user_data_dir_); |
| 292 base::FilePath current_stability_file; |
| 293 if (!GetStabilityFileForProcess(base::Process::Current(), user_data_dir_, |
| 294 ¤t_stability_file)) { |
| 295 LOG(ERROR) << "Failed to get the current stability file."; |
| 296 LogCollectionInitStatus(GET_STABILITY_FILE_PATH_FAILED); |
| 297 return; |
| 298 } |
| 299 const std::set<base::FilePath>& excluded_debug_files = { |
| 300 current_stability_file}; |
| 301 |
| 302 // Create a database. Note: Chrome already has a g_database in crashpad.cc but |
| 303 // it has internal linkage. Create a new one. |
| 304 std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database = |
| 305 crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir_); |
| 306 if (!crashpad_database) { |
| 307 LOG(ERROR) << "Failed to initialize a CrashPad database."; |
| 308 LogCollectionInitStatus(CRASHPAD_DATABASE_INIT_FAILED); |
| 309 return; |
| 310 } |
| 311 |
| 312 // Note: not caching the histogram pointer as this function isn't expected to |
| 313 // be called multiple times. |
| 314 LogCollectionInitStatus(INIT_SUCCESS); |
| 315 |
| 316 // TODO(manzagop): fix incorrect version attribution on update. |
| 317 PostmortemReportCollector collector; |
| 318 collector.CollectAndSubmitForUpload(stability_dir, GetStabilityFilePattern(), |
| 319 excluded_debug_files, |
| 320 crashpad_database.get()); |
| 321 } |
| 322 |
234 } // namespace browser_watcher | 323 } // namespace browser_watcher |
OLD | NEW |