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