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 LogCollectionInitStatusWithoutStaticVar( | |
207 CollectionInitializationStatus status) { | |
208 base::HistogramBase* init_status_hist = base::LinearHistogram::FactoryGet( | |
209 "ActivityTracker.Collect.InitStatus", 1, INIT_STATUS_MAX, | |
210 INIT_STATUS_MAX + 1, base::HistogramBase::kUmaTargetedHistogramFlag); | |
Sigurður Ásgeirsson
2016/09/22 15:46:14
same comment here.
manzagop (departed)
2016/09/23 21:57:01
Done.
| |
211 init_status_hist->Add(status); | |
212 } | |
213 | |
188 } // namespace | 214 } // namespace |
189 | 215 |
190 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = | 216 const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] = |
191 "Stability.BrowserExitCodes"; | 217 "Stability.BrowserExitCodes"; |
192 | 218 |
193 WatcherMetricsProviderWin::WatcherMetricsProviderWin( | 219 WatcherMetricsProviderWin::WatcherMetricsProviderWin( |
194 const base::string16& registry_path, | 220 const base::string16& registry_path, |
195 base::TaskRunner* cleanup_io_task_runner) | 221 const base::FilePath& user_data_dir, |
222 const base::FilePath& crash_dir, | |
223 base::TaskRunner* io_task_runner) | |
196 : recording_enabled_(false), | 224 : recording_enabled_(false), |
197 cleanup_scheduled_(false), | 225 cleanup_scheduled_(false), |
198 registry_path_(registry_path), | 226 registry_path_(registry_path), |
199 cleanup_io_task_runner_(cleanup_io_task_runner) { | 227 user_data_dir_(user_data_dir), |
200 DCHECK(cleanup_io_task_runner_); | 228 crash_dir_(crash_dir), |
229 io_task_runner_(io_task_runner), | |
230 weak_ptr_factory_(this) { | |
231 DCHECK(io_task_runner_); | |
201 } | 232 } |
202 | 233 |
203 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { | 234 WatcherMetricsProviderWin::~WatcherMetricsProviderWin() { |
204 } | 235 } |
205 | 236 |
206 void WatcherMetricsProviderWin::OnRecordingEnabled() { | 237 void WatcherMetricsProviderWin::OnRecordingEnabled() { |
207 recording_enabled_ = true; | 238 recording_enabled_ = true; |
208 } | 239 } |
209 | 240 |
210 void WatcherMetricsProviderWin::OnRecordingDisabled() { | 241 void WatcherMetricsProviderWin::OnRecordingDisabled() { |
211 if (!recording_enabled_ && !cleanup_scheduled_) { | 242 if (!recording_enabled_ && !cleanup_scheduled_) { |
212 // When metrics reporting is disabled, the providers get an | 243 // When metrics reporting is disabled, the providers get an |
213 // OnRecordingDisabled notification at startup. Use that first notification | 244 // OnRecordingDisabled notification at startup. Use that first notification |
214 // to issue the cleanup task. | 245 // to issue the cleanup task. |
215 cleanup_io_task_runner_->PostTask( | 246 io_task_runner_->PostTask( |
216 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); | 247 FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_)); |
217 | 248 |
218 cleanup_scheduled_ = true; | 249 cleanup_scheduled_ = true; |
219 } | 250 } |
220 } | 251 } |
221 | 252 |
222 void WatcherMetricsProviderWin::ProvideStabilityMetrics( | 253 void WatcherMetricsProviderWin::ProvideStabilityMetrics( |
223 metrics::SystemProfileProto* /* system_profile_proto */) { | 254 metrics::SystemProfileProto* /* system_profile_proto */) { |
224 // Note that if there are multiple instances of Chrome running in the same | 255 // 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 | 256 // 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 | 257 // 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 | 258 // 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 | 259 // necessary to implement some form of global locking, which is not worth it |
229 // here. | 260 // here. |
230 RecordExitCodes(registry_path_); | 261 RecordExitCodes(registry_path_); |
231 DeleteExitFunnels(registry_path_); | 262 DeleteExitFunnels(registry_path_); |
232 } | 263 } |
233 | 264 |
265 void WatcherMetricsProviderWin::CollectPostmortemReports( | |
266 const base::Closure& done_callback) { | |
267 io_task_runner_->PostTaskAndReply( | |
268 FROM_HERE, | |
269 base::Bind( | |
270 &WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool, | |
271 weak_ptr_factory_.GetWeakPtr()), | |
272 done_callback); | |
273 } | |
274 | |
275 void WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool() { | |
276 // Note: the feature controls both instrumentation and collection. | |
277 bool is_stability_debugging_on = | |
278 base::FeatureList::IsEnabled(browser_watcher::kStabilityDebuggingFeature); | |
279 if (!is_stability_debugging_on) { | |
280 // TODO(manzagop): delete possible leftover data. | |
281 return; | |
282 } | |
283 | |
284 SCOPED_UMA_HISTOGRAM_TIMER("ActivityTracker.Collect.TotalTime"); | |
285 | |
286 if (user_data_dir_.empty() || crash_dir_.empty()) { | |
287 LOG(ERROR) << "User data directory or crash directory is unknown."; | |
288 LogCollectionInitStatusWithoutStaticVar(UNKNOWN_DIR); | |
289 return; | |
290 } | |
291 | |
292 // Determine the stability directory and the stability file for the current | |
293 // process. | |
294 base::FilePath stability_dir = StabilityDebugging::GetDir(user_data_dir_); | |
295 base::FilePath current_stability_file; | |
296 if (!StabilityDebugging::GetFileForProcess( | |
297 base::Process::Current(), user_data_dir_, ¤t_stability_file)) { | |
298 LOG(ERROR) << "Failed to get the current stability file."; | |
299 LogCollectionInitStatusWithoutStaticVar(GET_STABILITY_FILE_PATH_FAILED); | |
300 return; | |
301 } | |
302 const std::set<base::FilePath>& excluded_debug_files = { | |
303 current_stability_file}; | |
304 | |
305 // Create a database. Note: Chrome already has a g_database in crashpad.cc but | |
306 // it has internal linkage. Create a new one. | |
307 std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database = | |
308 crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir_); | |
309 if (!crashpad_database) { | |
310 LOG(ERROR) << "Failed to initialize a CrashPad database."; | |
311 LogCollectionInitStatusWithoutStaticVar(CRASHPAD_DATABASE_INIT_FAILED); | |
312 return; | |
313 } | |
314 | |
315 // Note: not caching the histogram pointer as this function isn't expected to | |
316 // be called multiple times. | |
317 LogCollectionInitStatusWithoutStaticVar(INIT_SUCCESS); | |
318 | |
319 // TODO(manzagop): fix incorrect version attribution on update. | |
320 PostmortemReportCollector collector; | |
321 collector.CollectAndSubmitForUpload( | |
322 stability_dir, StabilityDebugging::GetFilePattern(), excluded_debug_files, | |
323 crashpad_database.get()); | |
324 } | |
325 | |
234 } // namespace browser_watcher | 326 } // namespace browser_watcher |
OLD | NEW |