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.
5 #include "chrome/browser/metrics/chrome_metrics_service_client.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"
44 #if defined(OS_ANDROID)
45 #include "chrome/browser/metrics/android_metrics_provider.h"
48 #if defined(ENABLE_FULL_PRINTING)
49 #include "chrome/browser/service_process/service_process_control.h"
52 #if defined(ENABLE_EXTENSIONS)
53 #include "chrome/browser/metrics/extensions_metrics_provider.h"
56 #if defined(ENABLE_PLUGINS)
57 #include "chrome/browser/metrics/plugin_metrics_provider.h"
60 #if defined(OS_CHROMEOS)
61 #include "chrome/browser/metrics/chromeos_metrics_provider.h"
66 #include "base/win/registry.h"
67 #include "chrome/browser/metrics/google_update_metrics_provider_win.h"
70 #if !defined(OS_CHROMEOS) && !defined(OS_IOS)
71 #include "chrome/browser/metrics/signin_status_metrics_provider.h"
76 // This specifies the amount of time to wait for all renderers to send their
78 const int kMaxHistogramGatheringWaitDuration
= 60000; // 60 seconds.
80 metrics::SystemProfileProto::Channel
AsProtobufChannel(
81 chrome::VersionInfo::Channel 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
;
95 return metrics::SystemProfileProto::CHANNEL_UNKNOWN
;
98 // Handles asynchronous fetching of memory details.
99 // Will run the provided task after finished.
100 class MetricsMemoryDetails
: public MemoryDetails
{
102 MetricsMemoryDetails(
103 const base::Closure
& callback
,
104 MemoryGrowthTracker
* memory_growth_tracker
)
105 : callback_(callback
) {
106 SetMemoryGrowthTracker(memory_growth_tracker
);
109 virtual void OnDetailsAvailable() override
{
110 base::MessageLoop::current()->PostTask(FROM_HERE
, callback_
);
114 virtual ~MetricsMemoryDetails() {}
116 base::Closure callback_
;
118 DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails
);
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();
135 CountBrowserCrashDumpAttempts();
136 #endif // defined(OS_WIN)
139 ChromeMetricsServiceClient::~ChromeMetricsServiceClient() {
140 DCHECK(thread_checker_
.CalledOnValidThread());
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();
153 return client
.Pass();
157 void ChromeMetricsServiceClient::RegisterPrefs(PrefRegistrySimple
* registry
) {
158 registry
->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec
, 0);
159 registry
->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec
, 0);
161 metrics::MetricsService::RegisterPrefs(registry
);
162 ChromeStabilityMetricsProvider::RegisterPrefs(registry
);
164 #if defined(OS_ANDROID)
165 AndroidMetricsProvider::RegisterPrefs(registry
);
166 #endif // defined(OS_ANDROID)
168 #if defined(ENABLE_PLUGINS)
169 PluginMetricsProvider::RegisterPrefs(registry
);
170 #endif // defined(ENABLE_PLUGINS)
173 void ChromeMetricsServiceClient::SetMetricsClientId(
174 const std::string
& client_id
) {
175 crash_keys::SetCrashClientIdFromGUID(client_id
);
178 bool ChromeMetricsServiceClient::IsOffTheRecordSessionActive() {
179 return chrome::IsOffTheRecordSessionActive();
182 int32
ChromeMetricsServiceClient::GetProduct() {
183 return metrics::ChromeUserMetricsExtension::CHROME
;
186 std::string
ChromeMetricsServiceClient::GetApplicationLocale() {
187 return g_browser_process
->GetApplicationLocale();
190 bool ChromeMetricsServiceClient::GetBrand(std::string
* brand_code
) {
191 return google_brand::GetBrand(brand_code
);
194 metrics::SystemProfileProto::Channel
ChromeMetricsServiceClient::GetChannel() {
195 return AsProtobufChannel(chrome::VersionInfo::GetChannel());
198 std::string
ChromeMetricsServiceClient::GetVersionString() {
199 chrome::VersionInfo version_info
;
200 std::string version
= version_info
.Version();
201 #if defined(ARCH_CPU_64_BITS)
203 #endif // defined(ARCH_CPU_64_BITS)
204 if (!version_info
.IsOfficialBuild())
205 version
.append("-devel");
209 void ChromeMetricsServiceClient::OnLogUploadComplete() {
210 // Collect network stats after each UMA upload.
211 network_stats_uploader_
.CollectAndReportNetworkStats();
214 void ChromeMetricsServiceClient::StartGatheringMetrics(
215 const base::Closure
& done_callback
) {
216 finished_gathering_initial_metrics_callback_
= done_callback
;
217 base::Closure got_hardware_class_callback
=
218 base::Bind(&ChromeMetricsServiceClient::OnInitTaskGotHardwareClass
,
219 weak_ptr_factory_
.GetWeakPtr());
220 #if defined(OS_CHROMEOS)
221 chromeos_metrics_provider_
->InitTaskGetHardwareClass(
222 got_hardware_class_callback
);
224 got_hardware_class_callback
.Run();
225 #endif // defined(OS_CHROMEOS)
228 void ChromeMetricsServiceClient::CollectFinalMetrics(
229 const base::Closure
& done_callback
) {
230 DCHECK(thread_checker_
.CalledOnValidThread());
232 collect_final_metrics_done_callback_
= done_callback
;
234 // Begin the multi-step process of collecting memory usage histograms:
235 // First spawn a task to collect the memory details; when that task is
236 // finished, it will call OnMemoryDetailCollectionDone. That will in turn
237 // call HistogramSynchronization to collect histograms from all renderers and
238 // then call OnHistogramSynchronizationDone to continue processing.
239 DCHECK(!waiting_for_collect_final_metrics_step_
);
240 waiting_for_collect_final_metrics_step_
= true;
242 #if !defined(OS_CHROMEOS) && !defined(OS_IOS)
243 // Record the signin status histogram value.
244 signin_status_metrics_provider_
->RecordSigninStatusHistogram();
247 base::Closure callback
=
248 base::Bind(&ChromeMetricsServiceClient::OnMemoryDetailCollectionDone
,
249 weak_ptr_factory_
.GetWeakPtr());
251 scoped_refptr
<MetricsMemoryDetails
> details(
252 new MetricsMemoryDetails(callback
, &memory_growth_tracker_
));
253 details
->StartFetch(MemoryDetails::UPDATE_USER_METRICS
);
255 // Collect WebCore cache information to put into a histogram.
256 for (content::RenderProcessHost::iterator
i(
257 content::RenderProcessHost::AllHostsIterator());
258 !i
.IsAtEnd(); i
.Advance()) {
259 i
.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats());
263 scoped_ptr
<metrics::MetricsLogUploader
>
264 ChromeMetricsServiceClient::CreateUploader(
265 const std::string
& server_url
,
266 const std::string
& mime_type
,
267 const base::Callback
<void(int)>& on_upload_complete
) {
268 return scoped_ptr
<metrics::MetricsLogUploader
>(
269 new metrics::NetMetricsLogUploader(
270 g_browser_process
->system_request_context(), server_url
, mime_type
,
271 on_upload_complete
));
274 base::string16
ChromeMetricsServiceClient::GetRegistryBackupKey() {
276 return L
"Software\\" PRODUCT_STRING_PATH L
"\\StabilityMetrics";
278 return base::string16();
282 void ChromeMetricsServiceClient::LogPluginLoadingError(
283 const base::FilePath
& plugin_path
) {
284 #if defined(ENABLE_PLUGINS)
285 plugin_metrics_provider_
->LogPluginLoadingError(plugin_path
);
288 #endif // defined(ENABLE_PLUGINS)
291 void ChromeMetricsServiceClient::Initialize() {
292 metrics_service_
.reset(new metrics::MetricsService(
293 metrics_state_manager_
, this, g_browser_process
->local_state()));
295 // Register metrics providers.
296 #if defined(ENABLE_EXTENSIONS)
297 metrics_service_
->RegisterMetricsProvider(
298 scoped_ptr
<metrics::MetricsProvider
>(
299 new ExtensionsMetricsProvider(metrics_state_manager_
)));
301 metrics_service_
->RegisterMetricsProvider(
302 scoped_ptr
<metrics::MetricsProvider
>(new NetworkMetricsProvider(
303 content::BrowserThread::GetBlockingPool())));
304 metrics_service_
->RegisterMetricsProvider(
305 scoped_ptr
<metrics::MetricsProvider
>(new OmniboxMetricsProvider
));
306 metrics_service_
->RegisterMetricsProvider(
307 scoped_ptr
<metrics::MetricsProvider
>(new ChromeStabilityMetricsProvider
));
308 metrics_service_
->RegisterMetricsProvider(
309 scoped_ptr
<metrics::MetricsProvider
>(new metrics::GPUMetricsProvider()));
310 profiler_metrics_provider_
= new metrics::ProfilerMetricsProvider
;
311 metrics_service_
->RegisterMetricsProvider(
312 scoped_ptr
<metrics::MetricsProvider
>(profiler_metrics_provider_
));
314 #if defined(OS_ANDROID)
315 metrics_service_
->RegisterMetricsProvider(
316 scoped_ptr
<metrics::MetricsProvider
>(
317 new AndroidMetricsProvider(g_browser_process
->local_state())));
318 #endif // defined(OS_ANDROID)
321 google_update_metrics_provider_
= new GoogleUpdateMetricsProviderWin
;
322 metrics_service_
->RegisterMetricsProvider(
323 scoped_ptr
<metrics::MetricsProvider
>(google_update_metrics_provider_
));
324 #endif // defined(OS_WIN)
326 #if defined(ENABLE_PLUGINS)
327 plugin_metrics_provider_
=
328 new PluginMetricsProvider(g_browser_process
->local_state());
329 metrics_service_
->RegisterMetricsProvider(
330 scoped_ptr
<metrics::MetricsProvider
>(plugin_metrics_provider_
));
331 #endif // defined(ENABLE_PLUGINS)
333 #if defined(OS_CHROMEOS)
334 ChromeOSMetricsProvider
* chromeos_metrics_provider
=
335 new ChromeOSMetricsProvider
;
336 chromeos_metrics_provider_
= chromeos_metrics_provider
;
337 metrics_service_
->RegisterMetricsProvider(
338 scoped_ptr
<metrics::MetricsProvider
>(chromeos_metrics_provider
));
339 #endif // defined(OS_CHROMEOS)
341 #if !defined(OS_CHROMEOS) && !defined(OS_IOS)
342 signin_status_metrics_provider_
=
343 SigninStatusMetricsProvider::CreateInstance();
344 metrics_service_
->RegisterMetricsProvider(
345 scoped_ptr
<metrics::MetricsProvider
>(signin_status_metrics_provider_
));
349 void ChromeMetricsServiceClient::OnInitTaskGotHardwareClass() {
350 const base::Closure got_plugin_info_callback
=
351 base::Bind(&ChromeMetricsServiceClient::OnInitTaskGotPluginInfo
,
352 weak_ptr_factory_
.GetWeakPtr());
354 #if defined(ENABLE_PLUGINS)
355 plugin_metrics_provider_
->GetPluginInformation(got_plugin_info_callback
);
357 got_plugin_info_callback
.Run();
358 #endif // defined(ENABLE_PLUGINS)
361 void ChromeMetricsServiceClient::OnInitTaskGotPluginInfo() {
362 const base::Closure got_metrics_callback
=
363 base::Bind(&ChromeMetricsServiceClient::OnInitTaskGotGoogleUpdateData
,
364 weak_ptr_factory_
.GetWeakPtr());
366 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
367 google_update_metrics_provider_
->GetGoogleUpdateData(got_metrics_callback
);
369 got_metrics_callback
.Run();
370 #endif // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
373 void ChromeMetricsServiceClient::OnInitTaskGotGoogleUpdateData() {
374 // Start the next part of the init task: fetching performance data. This will
375 // call into |FinishedReceivingProfilerData()| when the task completes.
376 metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
377 weak_ptr_factory_
.GetWeakPtr());
380 void ChromeMetricsServiceClient::ReceivedProfilerData(
381 const tracked_objects::ProcessDataSnapshot
& process_data
,
383 profiler_metrics_provider_
->RecordProfilerData(process_data
, process_type
);
386 void ChromeMetricsServiceClient::FinishedReceivingProfilerData() {
387 finished_gathering_initial_metrics_callback_
.Run();
390 void ChromeMetricsServiceClient::OnMemoryDetailCollectionDone() {
391 DCHECK(thread_checker_
.CalledOnValidThread());
393 // This function should only be called as the callback from an ansynchronous
395 DCHECK(waiting_for_collect_final_metrics_step_
);
397 // Create a callback_task for OnHistogramSynchronizationDone.
398 base::Closure callback
= base::Bind(
399 &ChromeMetricsServiceClient::OnHistogramSynchronizationDone
,
400 weak_ptr_factory_
.GetWeakPtr());
402 base::TimeDelta timeout
=
403 base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration
);
405 DCHECK_EQ(num_async_histogram_fetches_in_progress_
, 0);
407 #if !defined(ENABLE_FULL_PRINTING)
408 num_async_histogram_fetches_in_progress_
= 1;
409 #else // !ENABLE_FULL_PRINTING
410 num_async_histogram_fetches_in_progress_
= 2;
411 // Run requests to service and content in parallel.
412 if (!ServiceProcessControl::GetInstance()->GetHistograms(callback
, timeout
)) {
413 // Assume |num_async_histogram_fetches_in_progress_| is not changed by
414 // |GetHistograms()|.
415 DCHECK_EQ(num_async_histogram_fetches_in_progress_
, 2);
416 // Assign |num_async_histogram_fetches_in_progress_| above and decrement it
417 // here to make code work even if |GetHistograms()| fired |callback|.
418 --num_async_histogram_fetches_in_progress_
;
420 #endif // !ENABLE_FULL_PRINTING
422 // Set up the callback to task to call after we receive histograms from all
423 // child processes. |timeout| specifies how long to wait before absolutely
424 // calling us back on the task.
425 content::FetchHistogramsAsynchronously(base::MessageLoop::current(), callback
,
429 void ChromeMetricsServiceClient::OnHistogramSynchronizationDone() {
430 DCHECK(thread_checker_
.CalledOnValidThread());
432 // This function should only be called as the callback from an ansynchronous
434 DCHECK(waiting_for_collect_final_metrics_step_
);
435 DCHECK_GT(num_async_histogram_fetches_in_progress_
, 0);
437 // Check if all expected requests finished.
438 if (--num_async_histogram_fetches_in_progress_
> 0)
441 waiting_for_collect_final_metrics_step_
= false;
442 collect_final_metrics_done_callback_
.Run();
445 void ChromeMetricsServiceClient::RecordCommandLineMetrics() {
446 // Get stats on use of command line.
447 const CommandLine
* command_line(CommandLine::ForCurrentProcess());
448 size_t common_commands
= 0;
449 if (command_line
->HasSwitch(switches::kUserDataDir
)) {
451 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
454 if (command_line
->HasSwitch(switches::kApp
)) {
456 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
459 // TODO(rohitrao): Should these be logged on iOS as well?
460 // http://crbug.com/375794
461 size_t switch_count
= command_line
->GetSwitches().size();
462 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count
);
463 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
464 switch_count
- common_commands
);
467 void ChromeMetricsServiceClient::RegisterForNotifications() {
468 registrar_
.Add(this, chrome::NOTIFICATION_BROWSER_OPENED
,
469 content::NotificationService::AllBrowserContextsAndSources());
470 registrar_
.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED
,
471 content::NotificationService::AllSources());
472 registrar_
.Add(this, chrome::NOTIFICATION_TAB_PARENTED
,
473 content::NotificationService::AllSources());
474 registrar_
.Add(this, chrome::NOTIFICATION_TAB_CLOSING
,
475 content::NotificationService::AllSources());
476 registrar_
.Add(this, content::NOTIFICATION_LOAD_START
,
477 content::NotificationService::AllSources());
478 registrar_
.Add(this, content::NOTIFICATION_LOAD_STOP
,
479 content::NotificationService::AllSources());
480 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
481 content::NotificationService::AllSources());
482 registrar_
.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
,
483 content::NotificationService::AllSources());
484 registrar_
.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL
,
485 content::NotificationService::AllSources());
488 void ChromeMetricsServiceClient::Observe(
490 const content::NotificationSource
& source
,
491 const content::NotificationDetails
& details
) {
492 DCHECK(thread_checker_
.CalledOnValidThread());
495 case chrome::NOTIFICATION_BROWSER_OPENED
:
496 case chrome::NOTIFICATION_BROWSER_CLOSED
:
497 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL
:
498 case chrome::NOTIFICATION_TAB_PARENTED
:
499 case chrome::NOTIFICATION_TAB_CLOSING
:
500 case content::NOTIFICATION_LOAD_STOP
:
501 case content::NOTIFICATION_LOAD_START
:
502 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
:
503 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
:
504 metrics_service_
->OnApplicationNotIdle();
513 void ChromeMetricsServiceClient::CountBrowserCrashDumpAttempts() {
514 // Open the registry key for iteration.
515 base::win::RegKey regkey
;
516 if (regkey
.Open(HKEY_CURRENT_USER
,
517 chrome::kBrowserCrashDumpAttemptsRegistryPath
,
518 KEY_ALL_ACCESS
) != ERROR_SUCCESS
) {
522 // The values we're interested in counting are all prefixed with the version.
523 base::string16
chrome_version(base::ASCIIToUTF16(chrome::kChromeVersion
));
525 // Track a list of values to delete. We don't modify the registry key while
526 // we're iterating over its values.
527 typedef std::vector
<base::string16
> StringVector
;
528 StringVector to_delete
;
530 // Iterate over the values in the key counting dumps with and without crashes.
531 // We directly walk the values instead of using RegistryValueIterator in order
532 // to read all of the values as DWORDS instead of strings.
535 int dumps_with_crash
= 0;
536 int dumps_with_no_crash
= 0;
537 for (int i
= regkey
.GetValueCount() - 1; i
>= 0; --i
) {
538 if (regkey
.GetValueNameAt(i
, &name
) == ERROR_SUCCESS
&&
539 StartsWith(name
, chrome_version
, false) &&
540 regkey
.ReadValueDW(name
.c_str(), &value
) == ERROR_SUCCESS
) {
541 to_delete
.push_back(name
);
543 ++dumps_with_no_crash
;
549 // Delete the registry keys we've just counted.
550 for (StringVector::iterator i
= to_delete
.begin(); i
!= to_delete
.end(); ++i
)
551 regkey
.DeleteValue(i
->c_str());
553 // Capture the histogram samples.
554 if (dumps_with_crash
!= 0)
555 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithCrash", dumps_with_crash
);
556 if (dumps_with_no_crash
!= 0)
557 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithNoCrash", dumps_with_no_crash
);
558 int total_dumps
= dumps_with_crash
+ dumps_with_no_crash
;
559 if (total_dumps
!= 0)
560 UMA_HISTOGRAM_COUNTS("Chrome.BrowserCrashDumpAttempts", total_dumps
);
562 #endif // defined(OS_WIN)