• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
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 "chrome/browser/metrics/chrome_metrics_service_client.h"
6 
7 #include <vector>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_registry_simple.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/strings/string16.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/threading/platform_thread.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/google/google_brand.h"
24 #include "chrome/browser/metrics/chrome_stability_metrics_provider.h"
25 #include "chrome/browser/metrics/omnibox_metrics_provider.h"
26 #include "chrome/browser/ui/browser_otr_state.h"
27 #include "chrome/common/chrome_constants.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/chrome_version_info.h"
30 #include "chrome/common/crash_keys.h"
31 #include "chrome/common/pref_names.h"
32 #include "chrome/common/render_messages.h"
33 #include "components/metrics/gpu/gpu_metrics_provider.h"
34 #include "components/metrics/metrics_service.h"
35 #include "components/metrics/net/net_metrics_log_uploader.h"
36 #include "components/metrics/net/network_metrics_provider.h"
37 #include "components/metrics/profiler/profiler_metrics_provider.h"
38 #include "components/metrics/profiler/tracking_synchronizer.h"
39 #include "content/public/browser/browser_thread.h"
40 #include "content/public/browser/histogram_fetcher.h"
41 #include "content/public/browser/notification_service.h"
42 #include "content/public/browser/render_process_host.h"
43 
44 #if defined(OS_ANDROID)
45 #include "chrome/browser/metrics/android_metrics_provider.h"
46 #endif
47 
48 #if defined(ENABLE_FULL_PRINTING)
49 #include "chrome/browser/service_process/service_process_control.h"
50 #endif
51 
52 #if defined(ENABLE_EXTENSIONS)
53 #include "chrome/browser/metrics/extensions_metrics_provider.h"
54 #endif
55 
56 #if defined(ENABLE_PLUGINS)
57 #include "chrome/browser/metrics/plugin_metrics_provider.h"
58 #endif
59 
60 #if defined(OS_CHROMEOS)
61 #include "chrome/browser/metrics/chromeos_metrics_provider.h"
62 #endif
63 
64 #if defined(OS_WIN)
65 #include <windows.h>
66 #include "base/win/registry.h"
67 #include "chrome/browser/metrics/google_update_metrics_provider_win.h"
68 #endif
69 
70 #if !defined(OS_CHROMEOS) && !defined(OS_IOS)
71 #include "chrome/browser/metrics/signin_status_metrics_provider.h"
72 #endif
73 
74 namespace {
75 
76 // This specifies the amount of time to wait for all renderers to send their
77 // data.
78 const int kMaxHistogramGatheringWaitDuration = 60000;  // 60 seconds.
79 
AsProtobufChannel(chrome::VersionInfo::Channel channel)80 metrics::SystemProfileProto::Channel AsProtobufChannel(
81     chrome::VersionInfo::Channel channel) {
82   switch (channel) {
83     case chrome::VersionInfo::CHANNEL_UNKNOWN:
84       return metrics::SystemProfileProto::CHANNEL_UNKNOWN;
85     case chrome::VersionInfo::CHANNEL_CANARY:
86       return metrics::SystemProfileProto::CHANNEL_CANARY;
87     case chrome::VersionInfo::CHANNEL_DEV:
88       return metrics::SystemProfileProto::CHANNEL_DEV;
89     case chrome::VersionInfo::CHANNEL_BETA:
90       return metrics::SystemProfileProto::CHANNEL_BETA;
91     case chrome::VersionInfo::CHANNEL_STABLE:
92       return metrics::SystemProfileProto::CHANNEL_STABLE;
93   }
94   NOTREACHED();
95   return metrics::SystemProfileProto::CHANNEL_UNKNOWN;
96 }
97 
98 // Handles asynchronous fetching of memory details.
99 // Will run the provided task after finished.
100 class MetricsMemoryDetails : public MemoryDetails {
101  public:
MetricsMemoryDetails(const base::Closure & callback,MemoryGrowthTracker * memory_growth_tracker)102   MetricsMemoryDetails(
103       const base::Closure& callback,
104       MemoryGrowthTracker* memory_growth_tracker)
105       : callback_(callback) {
106     SetMemoryGrowthTracker(memory_growth_tracker);
107   }
108 
OnDetailsAvailable()109   virtual void OnDetailsAvailable() OVERRIDE {
110     base::MessageLoop::current()->PostTask(FROM_HERE, callback_);
111   }
112 
113  private:
~MetricsMemoryDetails()114   virtual ~MetricsMemoryDetails() {}
115 
116   base::Closure callback_;
117 
118   DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails);
119 };
120 
121 }  // namespace
122 
ChromeMetricsServiceClient(metrics::MetricsStateManager * state_manager)123 ChromeMetricsServiceClient::ChromeMetricsServiceClient(
124     metrics::MetricsStateManager* state_manager)
125     : metrics_state_manager_(state_manager),
126       chromeos_metrics_provider_(NULL),
127       waiting_for_collect_final_metrics_step_(false),
128       num_async_histogram_fetches_in_progress_(0),
129       weak_ptr_factory_(this) {
130   DCHECK(thread_checker_.CalledOnValidThread());
131   RecordCommandLineMetrics();
132   RegisterForNotifications();
133 
134 #if defined(OS_WIN)
135   CountBrowserCrashDumpAttempts();
136 #endif  // defined(OS_WIN)
137 }
138 
~ChromeMetricsServiceClient()139 ChromeMetricsServiceClient::~ChromeMetricsServiceClient() {
140   DCHECK(thread_checker_.CalledOnValidThread());
141 }
142 
143 // static
Create(metrics::MetricsStateManager * state_manager,PrefService * local_state)144 scoped_ptr<ChromeMetricsServiceClient> ChromeMetricsServiceClient::Create(
145     metrics::MetricsStateManager* state_manager,
146     PrefService* local_state) {
147   // Perform two-phase initialization so that |client->metrics_service_| only
148   // receives pointers to fully constructed objects.
149   scoped_ptr<ChromeMetricsServiceClient> client(
150       new ChromeMetricsServiceClient(state_manager));
151   client->Initialize();
152 
153   return client.Pass();
154 }
155 
156 // static
RegisterPrefs(PrefRegistrySimple * registry)157 void ChromeMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
158   registry->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0);
159   registry->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0);
160 
161   metrics::MetricsService::RegisterPrefs(registry);
162   ChromeStabilityMetricsProvider::RegisterPrefs(registry);
163 
164 #if defined(OS_ANDROID)
165   AndroidMetricsProvider::RegisterPrefs(registry);
166 #endif  // defined(OS_ANDROID)
167 
168 #if defined(ENABLE_PLUGINS)
169   PluginMetricsProvider::RegisterPrefs(registry);
170 #endif  // defined(ENABLE_PLUGINS)
171 }
172 
SetMetricsClientId(const std::string & client_id)173 void ChromeMetricsServiceClient::SetMetricsClientId(
174     const std::string& client_id) {
175   crash_keys::SetCrashClientIdFromGUID(client_id);
176 }
177 
IsOffTheRecordSessionActive()178 bool ChromeMetricsServiceClient::IsOffTheRecordSessionActive() {
179   return chrome::IsOffTheRecordSessionActive();
180 }
181 
GetApplicationLocale()182 std::string ChromeMetricsServiceClient::GetApplicationLocale() {
183   return g_browser_process->GetApplicationLocale();
184 }
185 
GetBrand(std::string * brand_code)186 bool ChromeMetricsServiceClient::GetBrand(std::string* brand_code) {
187   return google_brand::GetBrand(brand_code);
188 }
189 
GetChannel()190 metrics::SystemProfileProto::Channel ChromeMetricsServiceClient::GetChannel() {
191   return AsProtobufChannel(chrome::VersionInfo::GetChannel());
192 }
193 
GetVersionString()194 std::string ChromeMetricsServiceClient::GetVersionString() {
195   chrome::VersionInfo version_info;
196   if (!version_info.is_valid()) {
197     NOTREACHED();
198     return std::string();
199   }
200 
201   std::string version = version_info.Version();
202 #if defined(ARCH_CPU_64_BITS)
203   version += "-64";
204 #endif  // defined(ARCH_CPU_64_BITS)
205   if (!version_info.IsOfficialBuild())
206     version.append("-devel");
207   return version;
208 }
209 
OnLogUploadComplete()210 void ChromeMetricsServiceClient::OnLogUploadComplete() {
211   // Collect network stats after each UMA upload.
212   network_stats_uploader_.CollectAndReportNetworkStats();
213 }
214 
StartGatheringMetrics(const base::Closure & done_callback)215 void ChromeMetricsServiceClient::StartGatheringMetrics(
216     const base::Closure& done_callback) {
217   finished_gathering_initial_metrics_callback_ = done_callback;
218   base::Closure got_hardware_class_callback =
219       base::Bind(&ChromeMetricsServiceClient::OnInitTaskGotHardwareClass,
220                  weak_ptr_factory_.GetWeakPtr());
221 #if defined(OS_CHROMEOS)
222   chromeos_metrics_provider_->InitTaskGetHardwareClass(
223       got_hardware_class_callback);
224 #else
225   got_hardware_class_callback.Run();
226 #endif  // defined(OS_CHROMEOS)
227 }
228 
CollectFinalMetrics(const base::Closure & done_callback)229 void ChromeMetricsServiceClient::CollectFinalMetrics(
230     const base::Closure& done_callback) {
231   DCHECK(thread_checker_.CalledOnValidThread());
232 
233   collect_final_metrics_done_callback_ = done_callback;
234 
235   // Begin the multi-step process of collecting memory usage histograms:
236   // First spawn a task to collect the memory details; when that task is
237   // finished, it will call OnMemoryDetailCollectionDone. That will in turn
238   // call HistogramSynchronization to collect histograms from all renderers and
239   // then call OnHistogramSynchronizationDone to continue processing.
240   DCHECK(!waiting_for_collect_final_metrics_step_);
241   waiting_for_collect_final_metrics_step_ = true;
242 
243   base::Closure callback =
244       base::Bind(&ChromeMetricsServiceClient::OnMemoryDetailCollectionDone,
245                  weak_ptr_factory_.GetWeakPtr());
246 
247   scoped_refptr<MetricsMemoryDetails> details(
248       new MetricsMemoryDetails(callback, &memory_growth_tracker_));
249   details->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
250 
251   // Collect WebCore cache information to put into a histogram.
252   for (content::RenderProcessHost::iterator i(
253           content::RenderProcessHost::AllHostsIterator());
254        !i.IsAtEnd(); i.Advance()) {
255     i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats());
256   }
257 }
258 
259 scoped_ptr<metrics::MetricsLogUploader>
CreateUploader(const std::string & server_url,const std::string & mime_type,const base::Callback<void (int)> & on_upload_complete)260 ChromeMetricsServiceClient::CreateUploader(
261     const std::string& server_url,
262     const std::string& mime_type,
263     const base::Callback<void(int)>& on_upload_complete) {
264   return scoped_ptr<metrics::MetricsLogUploader>(
265       new metrics::NetMetricsLogUploader(
266           g_browser_process->system_request_context(), server_url, mime_type,
267           on_upload_complete));
268 }
269 
GetRegistryBackupKey()270 base::string16 ChromeMetricsServiceClient::GetRegistryBackupKey() {
271 #if defined(OS_WIN)
272   return L"Software\\" PRODUCT_STRING_PATH L"\\StabilityMetrics";
273 #else
274   return base::string16();
275 #endif
276 }
277 
LogPluginLoadingError(const base::FilePath & plugin_path)278 void ChromeMetricsServiceClient::LogPluginLoadingError(
279     const base::FilePath& plugin_path) {
280 #if defined(ENABLE_PLUGINS)
281   plugin_metrics_provider_->LogPluginLoadingError(plugin_path);
282 #else
283   NOTREACHED();
284 #endif  // defined(ENABLE_PLUGINS)
285 }
286 
Initialize()287 void ChromeMetricsServiceClient::Initialize() {
288   metrics_service_.reset(new metrics::MetricsService(
289       metrics_state_manager_, this, g_browser_process->local_state()));
290 
291   // Register metrics providers.
292 #if defined(ENABLE_EXTENSIONS)
293   metrics_service_->RegisterMetricsProvider(
294       scoped_ptr<metrics::MetricsProvider>(
295           new ExtensionsMetricsProvider(metrics_state_manager_)));
296 #endif
297   metrics_service_->RegisterMetricsProvider(
298       scoped_ptr<metrics::MetricsProvider>(new NetworkMetricsProvider(
299           content::BrowserThread::GetBlockingPool())));
300   metrics_service_->RegisterMetricsProvider(
301       scoped_ptr<metrics::MetricsProvider>(new OmniboxMetricsProvider));
302   metrics_service_->RegisterMetricsProvider(
303       scoped_ptr<metrics::MetricsProvider>(new ChromeStabilityMetricsProvider));
304   metrics_service_->RegisterMetricsProvider(
305       scoped_ptr<metrics::MetricsProvider>(new metrics::GPUMetricsProvider()));
306   profiler_metrics_provider_ = new metrics::ProfilerMetricsProvider;
307   metrics_service_->RegisterMetricsProvider(
308       scoped_ptr<metrics::MetricsProvider>(profiler_metrics_provider_));
309 
310 #if defined(OS_ANDROID)
311   metrics_service_->RegisterMetricsProvider(
312       scoped_ptr<metrics::MetricsProvider>(
313           new AndroidMetricsProvider(g_browser_process->local_state())));
314 #endif  // defined(OS_ANDROID)
315 
316 #if defined(OS_WIN)
317   google_update_metrics_provider_ = new GoogleUpdateMetricsProviderWin;
318   metrics_service_->RegisterMetricsProvider(
319       scoped_ptr<metrics::MetricsProvider>(google_update_metrics_provider_));
320 #endif  // defined(OS_WIN)
321 
322 #if defined(ENABLE_PLUGINS)
323   plugin_metrics_provider_ =
324       new PluginMetricsProvider(g_browser_process->local_state());
325   metrics_service_->RegisterMetricsProvider(
326       scoped_ptr<metrics::MetricsProvider>(plugin_metrics_provider_));
327 #endif  // defined(ENABLE_PLUGINS)
328 
329 #if defined(OS_CHROMEOS)
330   ChromeOSMetricsProvider* chromeos_metrics_provider =
331       new ChromeOSMetricsProvider;
332   chromeos_metrics_provider_ = chromeos_metrics_provider;
333   metrics_service_->RegisterMetricsProvider(
334       scoped_ptr<metrics::MetricsProvider>(chromeos_metrics_provider));
335 #endif  // defined(OS_CHROMEOS)
336 
337 #if !defined(OS_CHROMEOS) && !defined(OS_IOS)
338   metrics_service_->RegisterMetricsProvider(
339       scoped_ptr<metrics::MetricsProvider>(
340           SigninStatusMetricsProvider::CreateInstance()));
341 #endif
342 }
343 
OnInitTaskGotHardwareClass()344 void ChromeMetricsServiceClient::OnInitTaskGotHardwareClass() {
345   const base::Closure got_plugin_info_callback =
346       base::Bind(&ChromeMetricsServiceClient::OnInitTaskGotPluginInfo,
347                  weak_ptr_factory_.GetWeakPtr());
348 
349 #if defined(ENABLE_PLUGINS)
350   plugin_metrics_provider_->GetPluginInformation(got_plugin_info_callback);
351 #else
352   got_plugin_info_callback.Run();
353 #endif  // defined(ENABLE_PLUGINS)
354 }
355 
OnInitTaskGotPluginInfo()356 void ChromeMetricsServiceClient::OnInitTaskGotPluginInfo() {
357   const base::Closure got_metrics_callback =
358       base::Bind(&ChromeMetricsServiceClient::OnInitTaskGotGoogleUpdateData,
359                  weak_ptr_factory_.GetWeakPtr());
360 
361 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
362   google_update_metrics_provider_->GetGoogleUpdateData(got_metrics_callback);
363 #else
364   got_metrics_callback.Run();
365 #endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
366 }
367 
OnInitTaskGotGoogleUpdateData()368 void ChromeMetricsServiceClient::OnInitTaskGotGoogleUpdateData() {
369   // Start the next part of the init task: fetching performance data.  This will
370   // call into |FinishedReceivingProfilerData()| when the task completes.
371   metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
372       weak_ptr_factory_.GetWeakPtr());
373 }
374 
ReceivedProfilerData(const tracked_objects::ProcessDataSnapshot & process_data,int process_type)375 void ChromeMetricsServiceClient::ReceivedProfilerData(
376     const tracked_objects::ProcessDataSnapshot& process_data,
377     int process_type) {
378   profiler_metrics_provider_->RecordProfilerData(process_data, process_type);
379 }
380 
FinishedReceivingProfilerData()381 void ChromeMetricsServiceClient::FinishedReceivingProfilerData() {
382   finished_gathering_initial_metrics_callback_.Run();
383 }
384 
OnMemoryDetailCollectionDone()385 void ChromeMetricsServiceClient::OnMemoryDetailCollectionDone() {
386   DCHECK(thread_checker_.CalledOnValidThread());
387 
388   // This function should only be called as the callback from an ansynchronous
389   // step.
390   DCHECK(waiting_for_collect_final_metrics_step_);
391 
392   // Create a callback_task for OnHistogramSynchronizationDone.
393   base::Closure callback = base::Bind(
394       &ChromeMetricsServiceClient::OnHistogramSynchronizationDone,
395       weak_ptr_factory_.GetWeakPtr());
396 
397   base::TimeDelta timeout =
398       base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration);
399 
400   DCHECK_EQ(num_async_histogram_fetches_in_progress_, 0);
401 
402 #if !defined(ENABLE_FULL_PRINTING)
403   num_async_histogram_fetches_in_progress_ = 1;
404 #else  // !ENABLE_FULL_PRINTING
405   num_async_histogram_fetches_in_progress_ = 2;
406   // Run requests to service and content in parallel.
407   if (!ServiceProcessControl::GetInstance()->GetHistograms(callback, timeout)) {
408     // Assume |num_async_histogram_fetches_in_progress_| is not changed by
409     // |GetHistograms()|.
410     DCHECK_EQ(num_async_histogram_fetches_in_progress_, 2);
411     // Assign |num_async_histogram_fetches_in_progress_| above and decrement it
412     // here to make code work even if |GetHistograms()| fired |callback|.
413     --num_async_histogram_fetches_in_progress_;
414   }
415 #endif  // !ENABLE_FULL_PRINTING
416 
417   // Set up the callback to task to call after we receive histograms from all
418   // child processes. |timeout| specifies how long to wait before absolutely
419   // calling us back on the task.
420   content::FetchHistogramsAsynchronously(base::MessageLoop::current(), callback,
421                                          timeout);
422 }
423 
OnHistogramSynchronizationDone()424 void ChromeMetricsServiceClient::OnHistogramSynchronizationDone() {
425   DCHECK(thread_checker_.CalledOnValidThread());
426 
427   // This function should only be called as the callback from an ansynchronous
428   // step.
429   DCHECK(waiting_for_collect_final_metrics_step_);
430   DCHECK_GT(num_async_histogram_fetches_in_progress_, 0);
431 
432   // Check if all expected requests finished.
433   if (--num_async_histogram_fetches_in_progress_ > 0)
434     return;
435 
436   waiting_for_collect_final_metrics_step_ = false;
437   collect_final_metrics_done_callback_.Run();
438 }
439 
RecordCommandLineMetrics()440 void ChromeMetricsServiceClient::RecordCommandLineMetrics() {
441   // Get stats on use of command line.
442   const CommandLine* command_line(CommandLine::ForCurrentProcess());
443   size_t common_commands = 0;
444   if (command_line->HasSwitch(switches::kUserDataDir)) {
445     ++common_commands;
446     UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
447   }
448 
449   if (command_line->HasSwitch(switches::kApp)) {
450     ++common_commands;
451     UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
452   }
453 
454   // TODO(rohitrao): Should these be logged on iOS as well?
455   // http://crbug.com/375794
456   size_t switch_count = command_line->GetSwitches().size();
457   UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count);
458   UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
459                            switch_count - common_commands);
460 }
461 
RegisterForNotifications()462 void ChromeMetricsServiceClient::RegisterForNotifications() {
463   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
464                  content::NotificationService::AllBrowserContextsAndSources());
465   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
466                  content::NotificationService::AllSources());
467   registrar_.Add(this, chrome::NOTIFICATION_TAB_PARENTED,
468                  content::NotificationService::AllSources());
469   registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING,
470                  content::NotificationService::AllSources());
471   registrar_.Add(this, content::NOTIFICATION_LOAD_START,
472                  content::NotificationService::AllSources());
473   registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
474                  content::NotificationService::AllSources());
475   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
476                  content::NotificationService::AllSources());
477   registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
478                  content::NotificationService::AllSources());
479   registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
480                  content::NotificationService::AllSources());
481 }
482 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)483 void ChromeMetricsServiceClient::Observe(
484     int type,
485     const content::NotificationSource& source,
486     const content::NotificationDetails& details) {
487   DCHECK(thread_checker_.CalledOnValidThread());
488 
489   switch (type) {
490     case chrome::NOTIFICATION_BROWSER_OPENED:
491     case chrome::NOTIFICATION_BROWSER_CLOSED:
492     case chrome::NOTIFICATION_OMNIBOX_OPENED_URL:
493     case chrome::NOTIFICATION_TAB_PARENTED:
494     case chrome::NOTIFICATION_TAB_CLOSING:
495     case content::NOTIFICATION_LOAD_STOP:
496     case content::NOTIFICATION_LOAD_START:
497     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
498     case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
499       metrics_service_->OnApplicationNotIdle();
500       break;
501 
502     default:
503       NOTREACHED();
504   }
505 }
506 
507 #if defined(OS_WIN)
CountBrowserCrashDumpAttempts()508 void ChromeMetricsServiceClient::CountBrowserCrashDumpAttempts() {
509   // Open the registry key for iteration.
510   base::win::RegKey regkey;
511   if (regkey.Open(HKEY_CURRENT_USER,
512                   chrome::kBrowserCrashDumpAttemptsRegistryPath,
513                   KEY_ALL_ACCESS) != ERROR_SUCCESS) {
514     return;
515   }
516 
517   // The values we're interested in counting are all prefixed with the version.
518   base::string16 chrome_version(base::ASCIIToUTF16(chrome::kChromeVersion));
519 
520   // Track a list of values to delete. We don't modify the registry key while
521   // we're iterating over its values.
522   typedef std::vector<base::string16> StringVector;
523   StringVector to_delete;
524 
525   // Iterate over the values in the key counting dumps with and without crashes.
526   // We directly walk the values instead of using RegistryValueIterator in order
527   // to read all of the values as DWORDS instead of strings.
528   base::string16 name;
529   DWORD value = 0;
530   int dumps_with_crash = 0;
531   int dumps_with_no_crash = 0;
532   for (int i = regkey.GetValueCount() - 1; i >= 0; --i) {
533     if (regkey.GetValueNameAt(i, &name) == ERROR_SUCCESS &&
534         StartsWith(name, chrome_version, false) &&
535         regkey.ReadValueDW(name.c_str(), &value) == ERROR_SUCCESS) {
536       to_delete.push_back(name);
537       if (value == 0)
538         ++dumps_with_no_crash;
539       else
540         ++dumps_with_crash;
541     }
542   }
543 
544   // Delete the registry keys we've just counted.
545   for (StringVector::iterator i = to_delete.begin(); i != to_delete.end(); ++i)
546     regkey.DeleteValue(i->c_str());
547 
548   // Capture the histogram samples.
549   if (dumps_with_crash != 0)
550     UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithCrash", dumps_with_crash);
551   if (dumps_with_no_crash != 0)
552     UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithNoCrash", dumps_with_no_crash);
553   int total_dumps = dumps_with_crash + dumps_with_no_crash;
554   if (total_dumps != 0)
555     UMA_HISTOGRAM_COUNTS("Chrome.BrowserCrashDumpAttempts", total_dumps);
556 }
557 #endif  // defined(OS_WIN)
558