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