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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 LONG res = key.Open(HKEY_CURRENT_USER, registry_path.c_str(), | 186 LONG res = key.Open(HKEY_CURRENT_USER, registry_path.c_str(), |
179 KEY_QUERY_VALUE | KEY_SET_VALUE); | 187 KEY_QUERY_VALUE | KEY_SET_VALUE); |
180 if (res == ERROR_SUCCESS) { | 188 if (res == ERROR_SUCCESS) { |
181 DeleteAllValues(&key); | 189 DeleteAllValues(&key); |
182 res = key.DeleteEmptyKey(L""); | 190 res = key.DeleteEmptyKey(L""); |
183 } | 191 } |
184 if (res != ERROR_FILE_NOT_FOUND && res != ERROR_SUCCESS) | 192 if (res != ERROR_FILE_NOT_FOUND && res != ERROR_SUCCESS) |
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 |
196 enum CollectionInitializationStatus { | |
197 INIT_SUCCESS = 0, | |
198 UNKNOWN_DIR = 1, | |
199 GET_STABILITY_FILE_PATH_FAILED = 2, | |
200 CRASHPAD_DATABASE_INIT_FAILED = 3, | |
201 INIT_STATUS_MAX = 4 | |
202 }; | |
203 | |
188 } // namespace | 204 } // namespace |
189 | 205 |
190 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = | 206 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = |
191 "Stability.BrowserExitCodes"; | 207 "Stability.BrowserExitCodes"; |
192 | 208 |
193 WatcherMetricsProviderWin::WatcherMetricsProviderWin( | 209 WatcherMetricsProviderWin::WatcherMetricsProviderWin( |
194 const base::string16& registry_path, | 210 const base::string16& registry_path, |
195 base::TaskRunner* cleanup_io_task_runner) | 211 const base::FilePath& user_data_dir, |
212 const base::FilePath& crash_dir, | |
213 base::TaskRunner* io_task_runner) | |
196 : recording_enabled_(false), | 214 : recording_enabled_(false), |
197 cleanup_scheduled_(false), | 215 cleanup_scheduled_(false), |
198 registry_path_(registry_path), | 216 registry_path_(registry_path), |
199 cleanup_io_task_runner_(cleanup_io_task_runner) { | 217 user_data_dir_(user_data_dir), |
200 DCHECK(cleanup_io_task_runner_); | 218 crash_dir_(crash_dir), |
219 io_task_runner_(io_task_runner), | |
220 weak_ptr_factory_(this) { | |
221 DCHECK(io_task_runner_); | |
201 } | 222 } |
202 | 223 |
203 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { | 224 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { |
204 } | 225 } |
205 | 226 |
206 void WatcherMetricsProviderWin::OnRecordingEnabled() { | 227 void WatcherMetricsProviderWin::OnRecordingEnabled() { |
207 recording_enabled_ = true; | 228 recording_enabled_ = true; |
208 } | 229 } |
209 | 230 |
210 void WatcherMetricsProviderWin::OnRecordingDisabled() { | 231 void WatcherMetricsProviderWin::OnRecordingDisabled() { |
211 if (!recording_enabled_ && !cleanup_scheduled_) { | 232 if (!recording_enabled_ && !cleanup_scheduled_) { |
212 // When metrics reporting is disabled, the providers get an | 233 // When metrics reporting is disabled, the providers get an |
213 // OnRecordingDisabled notification at startup. Use that first notification | 234 // OnRecordingDisabled notification at startup. Use that first notification |
214 // to issue the cleanup task. | 235 // to issue the cleanup task. |
215 cleanup_io_task_runner_->PostTask( | 236 io_task_runner_->PostTask( |
216 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); | 237 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); |
217 | 238 |
218 cleanup_scheduled_ = true; | 239 cleanup_scheduled_ = true; |
219 } | 240 } |
220 } | 241 } |
221 | 242 |
222 void WatcherMetricsProviderWin::ProvideStabilityMetrics( | 243 void WatcherMetricsProviderWin::ProvideStabilityMetrics( |
223 metrics::SystemProfileProto* /* system_profile_proto */) { | 244 metrics::SystemProfileProto* /* system_profile_proto */) { |
224 // Note that if there are multiple instances of Chrome running in the same | 245 // 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 | 246 // 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 | 247 // 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 | 248 // 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 | 249 // necessary to implement some form of global locking, which is not worth it |
229 // here. | 250 // here. |
230 RecordExitCodes(registry_path_); | 251 RecordExitCodes(registry_path_); |
231 DeleteExitFunnels(registry_path_); | 252 DeleteExitFunnels(registry_path_); |
232 } | 253 } |
233 | 254 |
255 void WatcherMetricsProviderWin::CollectPostmortemReports( | |
256 const base::Closure& done_callback) { | |
257 io_task_runner_->PostTaskAndReply( | |
258 FROM_HERE, | |
259 base::Bind( | |
260 &WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool, | |
261 weak_ptr_factory_.GetWeakPtr()), | |
262 done_callback); | |
263 } | |
264 | |
265 void WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool() { | |
266 // Note: the feature controls both instrumentation and collection. | |
267 bool is_stability_debugging_on = | |
268 base::FeatureList::IsEnabled(browser_watcher::kStabilityDebuggingFeature); | |
269 if (!is_stability_debugging_on) { | |
270 // TODO(manzagop): delete possible leftover data. | |
271 return; | |
272 } | |
273 | |
274 SCOPED_UMA_HISTOGRAM_TIMER("ActivityTracker.Collect.TotalTime"); | |
275 | |
276 if (user_data_dir_.empty() || crash_dir_.empty()) { | |
277 LOG(ERROR) << "User data directory or crash directory is unknown."; | |
278 UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.InitStatus", | |
Sigurður Ásgeirsson
2016/09/22 13:06:12
It irks me to see these macros used for code that'
manzagop (departed)
2016/09/22 15:41:57
There doesn't seem to be, so I went with a manual
| |
279 UNKNOWN_DIR, INIT_STATUS_MAX); | |
280 return; | |
281 } | |
282 | |
283 // Determine the stability directory and the stability file for the current | |
284 // process. | |
285 base::FilePath stability_dir = StabilityDebugging::GetDir(user_data_dir_); | |
286 base::FilePath current_stability_file; | |
287 if (!StabilityDebugging::GetFileForProcess( | |
288 base::Process::Current(), user_data_dir_, ¤t_stability_file)) { | |
289 LOG(ERROR) << "Failed to get the current stability file."; | |
290 UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.InitStatus", | |
291 GET_STABILITY_FILE_PATH_FAILED, INIT_STATUS_MAX); | |
292 return; | |
293 } | |
294 const std::set<base::FilePath>& excluded_debug_files = { | |
295 current_stability_file}; | |
296 | |
297 // Create a database. Note: Chrome already has a g_database in crashpad.cc but | |
298 // it has internal linkage. Create a new one. | |
299 std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database = | |
300 crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir_); | |
301 if (!crashpad_database) { | |
302 LOG(ERROR) << "Failed to initialize a CrashPad database."; | |
303 UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.InitStatus", | |
304 CRASHPAD_DATABASE_INIT_FAILED, INIT_STATUS_MAX); | |
305 return; | |
306 } | |
307 UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.InitStatus", | |
308 INIT_SUCCESS, INIT_STATUS_MAX); | |
309 | |
310 // TODO(manzagop): fix incorrect version attribution on update. | |
311 PostmortemReportCollector collector; | |
312 collector.CollectAndSubmitForUpload( | |
313 stability_dir, StabilityDebugging::GetFilePattern(), excluded_debug_files, | |
314 crashpad_database.get()); | |
315 } | |
316 | |
234 } // namespace browser_watcher | 317 } // namespace browser_watcher |
OLD | NEW |