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