Home | History | Annotate | Download | only in metrics
      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 
     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:
    102   MetricsMemoryDetails(
    103       const base::Closure& callback,
    104       MemoryGrowthTracker* memory_growth_tracker)
    105       : callback_(callback) {
    106     SetMemoryGrowthTracker(memory_growth_tracker);
    107   }
    108 
    109   virtual void OnDetailsAvailable() OVERRIDE {
    110     base::MessageLoop::current()->PostTask(FROM_HERE, callback_);
    111   }
    112 
    113  private:
    114   virtual ~MetricsMemoryDetails() {}
    115 
    116   base::Closure callback_;
    117 
    118   DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails);
    119 };
    120 
    121 }  // namespace
    122 
    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 
    139 ChromeMetricsServiceClient::~ChromeMetricsServiceClient() {
    140   DCHECK(thread_checker_.CalledOnValidThread());
    141 }
    142 
    143 // static
    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
    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 
    173 void ChromeMetricsServiceClient::SetMetricsClientId(
    174     const std::string& client_id) {
    175   crash_keys::SetCrashClientIdFromGUID(client_id);
    176 }
    177 
    178 bool ChromeMetricsServiceClient::IsOffTheRecordSessionActive() {
    179   return chrome::IsOffTheRecordSessionActive();
    180 }
    181 
    182 std::string ChromeMetricsServiceClient::GetApplicationLocale() {
    183   return g_browser_process->GetApplicationLocale();
    184 }
    185 
    186 bool ChromeMetricsServiceClient::GetBrand(std::string* brand_code) {
    187   return google_brand::GetBrand(brand_code);
    188 }
    189 
    190 metrics::SystemProfileProto::Channel ChromeMetricsServiceClient::GetChannel() {
    191   return AsProtobufChannel(chrome::VersionInfo::GetChannel());
    192 }
    193 
    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 
    210 void ChromeMetricsServiceClient::OnLogUploadComplete() {
    211   // Collect network stats after each UMA upload.
    212   network_stats_uploader_.CollectAndReportNetworkStats();
    213 }
    214 
    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 
    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>
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    381 void ChromeMetricsServiceClient::FinishedReceivingProfilerData() {
    382   finished_gathering_initial_metrics_callback_.Run();
    383 }
    384 
    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 
    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 
    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 
    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 
    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)
    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