1 // Copyright (c) 2012 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/metrics_log.h"
11 #include "base/base64.h"
12 #include "base/basictypes.h"
13 #include "base/bind.h"
15 #include "base/lazy_instance.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/prefs/pref_registry_simple.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/profiler/alternate_timer.h"
20 #include "base/sha1.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/sys_info.h"
25 #include "base/third_party/nspr/prtime.h"
26 #include "base/time/time.h"
27 #include "base/tracked_objects.h"
28 #include "chrome/browser/autocomplete/autocomplete_input.h"
29 #include "chrome/browser/autocomplete/autocomplete_match.h"
30 #include "chrome/browser/autocomplete/autocomplete_provider.h"
31 #include "chrome/browser/autocomplete/autocomplete_result.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/google/google_util.h"
34 #include "chrome/browser/omnibox/omnibox_log.h"
35 #include "chrome/browser/plugins/plugin_prefs.h"
36 #include "chrome/browser/profiles/profile_manager.h"
37 #include "chrome/common/chrome_version_info.h"
38 #include "chrome/common/logging_chrome.h"
39 #include "chrome/common/metrics/proto/omnibox_event.pb.h"
40 #include "chrome/common/metrics/proto/profiler_event.pb.h"
41 #include "chrome/common/metrics/proto/system_profile.pb.h"
42 #include "chrome/common/metrics/variations/variations_util.h"
43 #include "chrome/common/pref_names.h"
44 #include "chrome/installer/util/google_update_settings.h"
45 #include "components/nacl/common/nacl_process_type.h"
46 #include "content/public/browser/gpu_data_manager.h"
47 #include "content/public/common/content_client.h"
48 #include "content/public/common/webplugininfo.h"
49 #include "device/bluetooth/bluetooth_adapter.h"
50 #include "device/bluetooth/bluetooth_adapter_factory.h"
51 #include "device/bluetooth/bluetooth_device.h"
52 #include "gpu/config/gpu_info.h"
53 #include "ui/gfx/screen.h"
56 #if defined(OS_ANDROID)
57 #include "base/android/build_info.h"
61 #include "base/win/metro.h"
63 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
64 extern "C" IMAGE_DOS_HEADER __ImageBase
;
67 #if defined(OS_CHROMEOS)
68 #include "chrome/browser/chromeos/login/user_manager.h"
71 using content::GpuDataManager
;
72 using metrics::OmniboxEventProto
;
73 using metrics::PerfDataProto
;
74 using metrics::ProfilerEventProto
;
75 using metrics::SystemProfileProto
;
76 using tracked_objects::ProcessDataSnapshot
;
77 typedef chrome_variations::ActiveGroupId ActiveGroupId
;
78 typedef SystemProfileProto::GoogleUpdate::ProductInfo ProductInfo
;
79 typedef SystemProfileProto::Hardware::Bluetooth::PairedDevice PairedDevice
;
83 // Returns the date at which the current metrics client ID was created as
84 // a string containing seconds since the epoch, or "0" if none was found.
85 std::string
GetMetricsEnabledDate(PrefService
* pref
) {
91 return pref
->GetString(prefs::kMetricsClientIDTimestamp
);
94 OmniboxEventProto::InputType
AsOmniboxEventInputType(
95 AutocompleteInput::Type type
) {
97 case AutocompleteInput::INVALID
:
98 return OmniboxEventProto::INVALID
;
99 case AutocompleteInput::UNKNOWN
:
100 return OmniboxEventProto::UNKNOWN
;
101 case AutocompleteInput::URL
:
102 return OmniboxEventProto::URL
;
103 case AutocompleteInput::QUERY
:
104 return OmniboxEventProto::QUERY
;
105 case AutocompleteInput::FORCED_QUERY
:
106 return OmniboxEventProto::FORCED_QUERY
;
109 return OmniboxEventProto::INVALID
;
113 OmniboxEventProto::Suggestion::ResultType
AsOmniboxEventResultType(
114 AutocompleteMatch::Type type
) {
116 case AutocompleteMatchType::URL_WHAT_YOU_TYPED
:
117 return OmniboxEventProto::Suggestion::URL_WHAT_YOU_TYPED
;
118 case AutocompleteMatchType::HISTORY_URL
:
119 return OmniboxEventProto::Suggestion::HISTORY_URL
;
120 case AutocompleteMatchType::HISTORY_TITLE
:
121 return OmniboxEventProto::Suggestion::HISTORY_TITLE
;
122 case AutocompleteMatchType::HISTORY_BODY
:
123 return OmniboxEventProto::Suggestion::HISTORY_BODY
;
124 case AutocompleteMatchType::HISTORY_KEYWORD
:
125 return OmniboxEventProto::Suggestion::HISTORY_KEYWORD
;
126 case AutocompleteMatchType::NAVSUGGEST
:
127 return OmniboxEventProto::Suggestion::NAVSUGGEST
;
128 case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
:
129 return OmniboxEventProto::Suggestion::SEARCH_WHAT_YOU_TYPED
;
130 case AutocompleteMatchType::SEARCH_HISTORY
:
131 return OmniboxEventProto::Suggestion::SEARCH_HISTORY
;
132 case AutocompleteMatchType::SEARCH_SUGGEST
:
133 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST
;
134 case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
:
135 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_ENTITY
;
136 case AutocompleteMatchType::SEARCH_SUGGEST_INFINITE
:
137 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_INFINITE
;
138 case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED
:
139 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PERSONALIZED
;
140 case AutocompleteMatchType::SEARCH_SUGGEST_PROFILE
:
141 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PROFILE
;
142 case AutocompleteMatchType::SEARCH_OTHER_ENGINE
:
143 return OmniboxEventProto::Suggestion::SEARCH_OTHER_ENGINE
;
144 case AutocompleteMatchType::EXTENSION_APP
:
145 return OmniboxEventProto::Suggestion::EXTENSION_APP
;
146 case AutocompleteMatchType::CONTACT
:
147 return OmniboxEventProto::Suggestion::CONTACT
;
148 case AutocompleteMatchType::BOOKMARK_TITLE
:
149 return OmniboxEventProto::Suggestion::BOOKMARK_TITLE
;
152 return OmniboxEventProto::Suggestion::UNKNOWN_RESULT_TYPE
;
156 OmniboxEventProto::PageClassification
AsOmniboxEventPageClassification(
157 AutocompleteInput::PageClassification page_classification
) {
158 switch (page_classification
) {
159 case AutocompleteInput::INVALID_SPEC
:
160 return OmniboxEventProto::INVALID_SPEC
;
161 case AutocompleteInput::NTP
:
162 return OmniboxEventProto::NTP
;
163 case AutocompleteInput::BLANK
:
164 return OmniboxEventProto::BLANK
;
165 case AutocompleteInput::HOME_PAGE
:
166 return OmniboxEventProto::HOME_PAGE
;
167 case AutocompleteInput::OTHER
:
168 return OmniboxEventProto::OTHER
;
169 case AutocompleteInput::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT
:
170 return OmniboxEventProto::
171 SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT
;
172 case AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS
:
173 return OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS
;
174 case AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
:
175 return OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS
;
176 case AutocompleteInput::SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT
:
177 return OmniboxEventProto::
178 SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT
;
180 return OmniboxEventProto::INVALID_SPEC
;
183 ProfilerEventProto::TrackedObject::ProcessType
AsProtobufProcessType(
185 switch (process_type
) {
186 case content::PROCESS_TYPE_BROWSER
:
187 return ProfilerEventProto::TrackedObject::BROWSER
;
188 case content::PROCESS_TYPE_RENDERER
:
189 return ProfilerEventProto::TrackedObject::RENDERER
;
190 case content::PROCESS_TYPE_PLUGIN
:
191 return ProfilerEventProto::TrackedObject::PLUGIN
;
192 case content::PROCESS_TYPE_WORKER
:
193 return ProfilerEventProto::TrackedObject::WORKER
;
194 case content::PROCESS_TYPE_UTILITY
:
195 return ProfilerEventProto::TrackedObject::UTILITY
;
196 case content::PROCESS_TYPE_ZYGOTE
:
197 return ProfilerEventProto::TrackedObject::ZYGOTE
;
198 case content::PROCESS_TYPE_SANDBOX_HELPER
:
199 return ProfilerEventProto::TrackedObject::SANDBOX_HELPER
;
200 case content::PROCESS_TYPE_GPU
:
201 return ProfilerEventProto::TrackedObject::GPU
;
202 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
203 return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN
;
204 case content::PROCESS_TYPE_PPAPI_BROKER
:
205 return ProfilerEventProto::TrackedObject::PPAPI_BROKER
;
206 case PROCESS_TYPE_NACL_LOADER
:
207 return ProfilerEventProto::TrackedObject::NACL_LOADER
;
208 case PROCESS_TYPE_NACL_BROKER
:
209 return ProfilerEventProto::TrackedObject::NACL_BROKER
;
212 return ProfilerEventProto::TrackedObject::UNKNOWN
;
216 // Computes a SHA-1 hash of |data| and returns it as a hex string.
217 std::string
ComputeSHA1(const std::string
& data
) {
218 const std::string sha1
= base::SHA1HashString(data
);
219 return base::HexEncode(sha1
.data(), sha1
.size());
222 #if defined(ENABLE_PLUGINS)
223 // Returns the plugin preferences corresponding for this user, if available.
224 // If multiple user profiles are loaded, returns the preferences corresponding
225 // to an arbitrary one of the profiles.
226 PluginPrefs
* GetPluginPrefs() {
227 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
229 if (!profile_manager
) {
230 // The profile manager can be NULL when testing.
234 std::vector
<Profile
*> profiles
= profile_manager
->GetLoadedProfiles();
235 if (profiles
.empty())
238 return PluginPrefs::GetForProfile(profiles
.front()).get();
241 // Fills |plugin| with the info contained in |plugin_info| and |plugin_prefs|.
242 void SetPluginInfo(const content::WebPluginInfo
& plugin_info
,
243 const PluginPrefs
* plugin_prefs
,
244 SystemProfileProto::Plugin
* plugin
) {
245 plugin
->set_name(base::UTF16ToUTF8(plugin_info
.name
));
246 plugin
->set_filename(plugin_info
.path
.BaseName().AsUTF8Unsafe());
247 plugin
->set_version(base::UTF16ToUTF8(plugin_info
.version
));
248 plugin
->set_is_pepper(plugin_info
.is_pepper_plugin());
250 plugin
->set_is_disabled(!plugin_prefs
->IsPluginEnabled(plugin_info
));
252 #endif // defined(ENABLE_PLUGINS)
254 void WriteFieldTrials(const std::vector
<ActiveGroupId
>& field_trial_ids
,
255 SystemProfileProto
* system_profile
) {
256 for (std::vector
<ActiveGroupId
>::const_iterator it
=
257 field_trial_ids
.begin(); it
!= field_trial_ids
.end(); ++it
) {
258 SystemProfileProto::FieldTrial
* field_trial
=
259 system_profile
->add_field_trial();
260 field_trial
->set_name_id(it
->name
);
261 field_trial
->set_group_id(it
->group
);
265 void WriteProfilerData(const ProcessDataSnapshot
& profiler_data
,
267 ProfilerEventProto
* performance_profile
) {
268 for (std::vector
<tracked_objects::TaskSnapshot
>::const_iterator it
=
269 profiler_data
.tasks
.begin();
270 it
!= profiler_data
.tasks
.end(); ++it
) {
271 const tracked_objects::DeathDataSnapshot
& death_data
= it
->death_data
;
272 ProfilerEventProto::TrackedObject
* tracked_object
=
273 performance_profile
->add_tracked_object();
274 tracked_object
->set_birth_thread_name_hash(
275 MetricsLogBase::Hash(it
->birth
.thread_name
));
276 tracked_object
->set_exec_thread_name_hash(
277 MetricsLogBase::Hash(it
->death_thread_name
));
278 tracked_object
->set_source_file_name_hash(
279 MetricsLogBase::Hash(it
->birth
.location
.file_name
));
280 tracked_object
->set_source_function_name_hash(
281 MetricsLogBase::Hash(it
->birth
.location
.function_name
));
282 tracked_object
->set_source_line_number(it
->birth
.location
.line_number
);
283 tracked_object
->set_exec_count(death_data
.count
);
284 tracked_object
->set_exec_time_total(death_data
.run_duration_sum
);
285 tracked_object
->set_exec_time_sampled(death_data
.run_duration_sample
);
286 tracked_object
->set_queue_time_total(death_data
.queue_duration_sum
);
287 tracked_object
->set_queue_time_sampled(death_data
.queue_duration_sample
);
288 tracked_object
->set_process_type(AsProtobufProcessType(process_type
));
289 tracked_object
->set_process_id(profiler_data
.process_id
);
293 #if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
294 void ProductDataToProto(const GoogleUpdateSettings::ProductData
& product_data
,
295 ProductInfo
* product_info
) {
296 product_info
->set_version(product_data
.version
);
297 product_info
->set_last_update_success_timestamp(
298 product_data
.last_success
.ToTimeT());
299 product_info
->set_last_error(product_data
.last_error_code
);
300 product_info
->set_last_extra_error(product_data
.last_extra_code
);
301 if (ProductInfo::InstallResult_IsValid(product_data
.last_result
)) {
302 product_info
->set_last_result(
303 static_cast<ProductInfo::InstallResult
>(product_data
.last_result
));
309 struct ScreenDPIInformation
{
314 // Called once for each connected monitor.
315 BOOL CALLBACK
GetMonitorDPICallback(HMONITOR
, HDC hdc
, LPRECT
, LPARAM dwData
) {
316 const double kMillimetersPerInch
= 25.4;
317 ScreenDPIInformation
* screen_info
=
318 reinterpret_cast<ScreenDPIInformation
*>(dwData
);
319 // Size of screen, in mm.
320 DWORD size_x
= GetDeviceCaps(hdc
, HORZSIZE
);
321 DWORD size_y
= GetDeviceCaps(hdc
, VERTSIZE
);
322 double dpi_x
= (size_x
> 0) ?
323 GetDeviceCaps(hdc
, HORZRES
) / (size_x
/ kMillimetersPerInch
) : 0;
324 double dpi_y
= (size_y
> 0) ?
325 GetDeviceCaps(hdc
, VERTRES
) / (size_y
/ kMillimetersPerInch
) : 0;
326 screen_info
->max_dpi_x
= std::max(dpi_x
, screen_info
->max_dpi_x
);
327 screen_info
->max_dpi_y
= std::max(dpi_y
, screen_info
->max_dpi_y
);
331 void WriteScreenDPIInformationProto(SystemProfileProto::Hardware
* hardware
) {
332 HDC desktop_dc
= GetDC(NULL
);
334 ScreenDPIInformation si
= {0, 0};
335 if (EnumDisplayMonitors(desktop_dc
, NULL
, GetMonitorDPICallback
,
336 reinterpret_cast<LPARAM
>(&si
))) {
337 hardware
->set_max_dpi_x(si
.max_dpi_x
);
338 hardware
->set_max_dpi_y(si
.max_dpi_y
);
340 ReleaseDC(GetDesktopWindow(), desktop_dc
);
344 #endif // defined(OS_WIN)
346 #if defined(OS_CHROMEOS)
347 PairedDevice::Type
AsBluetoothDeviceType(
348 enum device::BluetoothDevice::DeviceType device_type
) {
349 switch (device_type
) {
350 case device::BluetoothDevice::DEVICE_UNKNOWN
:
351 return PairedDevice::DEVICE_UNKNOWN
;
352 case device::BluetoothDevice::DEVICE_COMPUTER
:
353 return PairedDevice::DEVICE_COMPUTER
;
354 case device::BluetoothDevice::DEVICE_PHONE
:
355 return PairedDevice::DEVICE_PHONE
;
356 case device::BluetoothDevice::DEVICE_MODEM
:
357 return PairedDevice::DEVICE_MODEM
;
358 case device::BluetoothDevice::DEVICE_AUDIO
:
359 return PairedDevice::DEVICE_AUDIO
;
360 case device::BluetoothDevice::DEVICE_CAR_AUDIO
:
361 return PairedDevice::DEVICE_CAR_AUDIO
;
362 case device::BluetoothDevice::DEVICE_VIDEO
:
363 return PairedDevice::DEVICE_VIDEO
;
364 case device::BluetoothDevice::DEVICE_PERIPHERAL
:
365 return PairedDevice::DEVICE_PERIPHERAL
;
366 case device::BluetoothDevice::DEVICE_JOYSTICK
:
367 return PairedDevice::DEVICE_JOYSTICK
;
368 case device::BluetoothDevice::DEVICE_GAMEPAD
:
369 return PairedDevice::DEVICE_GAMEPAD
;
370 case device::BluetoothDevice::DEVICE_KEYBOARD
:
371 return PairedDevice::DEVICE_KEYBOARD
;
372 case device::BluetoothDevice::DEVICE_MOUSE
:
373 return PairedDevice::DEVICE_MOUSE
;
374 case device::BluetoothDevice::DEVICE_TABLET
:
375 return PairedDevice::DEVICE_TABLET
;
376 case device::BluetoothDevice::DEVICE_KEYBOARD_MOUSE_COMBO
:
377 return PairedDevice::DEVICE_KEYBOARD_MOUSE_COMBO
;
381 return PairedDevice::DEVICE_UNKNOWN
;
383 #endif // defined(OS_CHROMEOS)
385 // Round a timestamp measured in seconds since epoch to one with a granularity
386 // of an hour. This can be used before uploaded potentially sensitive
388 int64
RoundSecondsToHour(int64 time_in_seconds
) {
389 return 3600 * (time_in_seconds
/ 3600);
394 GoogleUpdateMetrics::GoogleUpdateMetrics() : is_system_install(false) {}
396 GoogleUpdateMetrics::~GoogleUpdateMetrics() {}
398 static base::LazyInstance
<std::string
>::Leaky
399 g_version_extension
= LAZY_INSTANCE_INITIALIZER
;
401 MetricsLog::MetricsLog(const std::string
& client_id
, int session_id
)
402 : MetricsLogBase(client_id
, session_id
, MetricsLog::GetVersionString()),
403 creation_time_(base::TimeTicks::Now()) {
404 #if defined(OS_CHROMEOS)
405 UpdateMultiProfileUserCount();
409 MetricsLog::~MetricsLog() {}
412 void MetricsLog::RegisterPrefs(PrefRegistrySimple
* registry
) {
413 registry
->RegisterListPref(prefs::kStabilityPluginStats
);
417 std::string
MetricsLog::GetVersionString() {
418 chrome::VersionInfo version_info
;
419 if (!version_info
.is_valid()) {
420 NOTREACHED() << "Unable to retrieve version info.";
421 return std::string();
424 std::string version
= version_info
.Version();
425 if (!version_extension().empty())
426 version
+= version_extension();
427 if (!version_info
.IsOfficialBuild())
428 version
.append("-devel");
433 void MetricsLog::set_version_extension(const std::string
& extension
) {
434 g_version_extension
.Get() = extension
;
438 const std::string
& MetricsLog::version_extension() {
439 return g_version_extension
.Get();
442 void MetricsLog::RecordStabilityMetrics(
443 base::TimeDelta incremental_uptime
,
445 DCHECK_NE(NO_LOG
, log_type
);
447 DCHECK(HasEnvironment());
448 DCHECK(!HasStabilityMetrics());
450 PrefService
* pref
= GetPrefService();
453 // Get stability attributes out of Local State, zeroing out stored values.
454 // NOTE: This could lead to some data loss if this report isn't successfully
455 // sent, but that's true for all the metrics.
457 WriteRequiredStabilityAttributes(pref
);
458 WritePluginStabilityElements(pref
);
460 // Record recent delta for critical stability metrics. We can't wait for a
461 // restart to gather these, as that delay biases our observation away from
462 // users that run happily for a looooong time. We send increments with each
463 // uma log upload, just as we send histogram data.
464 WriteRealtimeStabilityAttributes(pref
, incremental_uptime
);
466 // Omit some stats unless this is the initial stability log.
467 if (log_type
!= INITIAL_LOG
)
470 int incomplete_shutdown_count
=
471 pref
->GetInteger(prefs::kStabilityIncompleteSessionEndCount
);
472 pref
->SetInteger(prefs::kStabilityIncompleteSessionEndCount
, 0);
473 int breakpad_registration_success_count
=
474 pref
->GetInteger(prefs::kStabilityBreakpadRegistrationSuccess
);
475 pref
->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess
, 0);
476 int breakpad_registration_failure_count
=
477 pref
->GetInteger(prefs::kStabilityBreakpadRegistrationFail
);
478 pref
->SetInteger(prefs::kStabilityBreakpadRegistrationFail
, 0);
479 int debugger_present_count
=
480 pref
->GetInteger(prefs::kStabilityDebuggerPresent
);
481 pref
->SetInteger(prefs::kStabilityDebuggerPresent
, 0);
482 int debugger_not_present_count
=
483 pref
->GetInteger(prefs::kStabilityDebuggerNotPresent
);
484 pref
->SetInteger(prefs::kStabilityDebuggerNotPresent
, 0);
486 // TODO(jar): The following are all optional, so we *could* optimize them for
487 // values of zero (and not include them).
488 SystemProfileProto::Stability
* stability
=
489 uma_proto()->mutable_system_profile()->mutable_stability();
490 stability
->set_incomplete_shutdown_count(incomplete_shutdown_count
);
491 stability
->set_breakpad_registration_success_count(
492 breakpad_registration_success_count
);
493 stability
->set_breakpad_registration_failure_count(
494 breakpad_registration_failure_count
);
495 stability
->set_debugger_present_count(debugger_present_count
);
496 stability
->set_debugger_not_present_count(debugger_not_present_count
);
499 PrefService
* MetricsLog::GetPrefService() {
500 return g_browser_process
->local_state();
503 gfx::Size
MetricsLog::GetScreenSize() const {
504 return gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().GetSizeInPixel();
507 float MetricsLog::GetScreenDeviceScaleFactor() const {
508 return gfx::Screen::GetNativeScreen()->
509 GetPrimaryDisplay().device_scale_factor();
512 int MetricsLog::GetScreenCount() const {
513 // TODO(scottmg): NativeScreen maybe wrong. http://crbug.com/133312
514 return gfx::Screen::GetNativeScreen()->GetNumDisplays();
517 void MetricsLog::GetFieldTrialIds(
518 std::vector
<ActiveGroupId
>* field_trial_ids
) const {
519 chrome_variations::GetFieldTrialActiveGroupIds(field_trial_ids
);
522 bool MetricsLog::HasEnvironment() const {
523 return uma_proto()->system_profile().has_uma_enabled_date();
526 bool MetricsLog::HasStabilityMetrics() const {
527 return uma_proto()->system_profile().stability().has_launch_count();
530 void MetricsLog::WritePluginStabilityElements(PrefService
* pref
) {
531 // Now log plugin stability info.
532 const base::ListValue
* plugin_stats_list
= pref
->GetList(
533 prefs::kStabilityPluginStats
);
534 if (!plugin_stats_list
)
537 #if defined(ENABLE_PLUGINS)
538 SystemProfileProto::Stability
* stability
=
539 uma_proto()->mutable_system_profile()->mutable_stability();
540 for (base::ListValue::const_iterator iter
= plugin_stats_list
->begin();
541 iter
!= plugin_stats_list
->end(); ++iter
) {
542 if (!(*iter
)->IsType(base::Value::TYPE_DICTIONARY
)) {
546 base::DictionaryValue
* plugin_dict
=
547 static_cast<base::DictionaryValue
*>(*iter
);
549 // Note that this search is potentially a quadratic operation, but given the
550 // low number of plugins installed on a "reasonable" setup, this should be
552 // TODO(isherman): Verify that this does not show up as a hotspot in
554 const SystemProfileProto::Plugin
* system_profile_plugin
= NULL
;
555 std::string plugin_name
;
556 plugin_dict
->GetString(prefs::kStabilityPluginName
, &plugin_name
);
557 const SystemProfileProto
& system_profile
= uma_proto()->system_profile();
558 for (int i
= 0; i
< system_profile
.plugin_size(); ++i
) {
559 if (system_profile
.plugin(i
).name() == plugin_name
) {
560 system_profile_plugin
= &system_profile
.plugin(i
);
565 if (!system_profile_plugin
) {
570 SystemProfileProto::Stability::PluginStability
* plugin_stability
=
571 stability
->add_plugin_stability();
572 *plugin_stability
->mutable_plugin() = *system_profile_plugin
;
575 plugin_dict
->GetInteger(prefs::kStabilityPluginLaunches
, &launches
);
577 plugin_stability
->set_launch_count(launches
);
580 plugin_dict
->GetInteger(prefs::kStabilityPluginInstances
, &instances
);
582 plugin_stability
->set_instance_count(instances
);
585 plugin_dict
->GetInteger(prefs::kStabilityPluginCrashes
, &crashes
);
587 plugin_stability
->set_crash_count(crashes
);
589 int loading_errors
= 0;
590 plugin_dict
->GetInteger(prefs::kStabilityPluginLoadingErrors
,
592 if (loading_errors
> 0)
593 plugin_stability
->set_loading_error_count(loading_errors
);
595 #endif // defined(ENABLE_PLUGINS)
597 pref
->ClearPref(prefs::kStabilityPluginStats
);
600 // The server refuses data that doesn't have certain values. crashcount and
601 // launchcount are currently "required" in the "stability" group.
602 // TODO(isherman): Stop writing these attributes specially once the migration to
603 // protobufs is complete.
604 void MetricsLog::WriteRequiredStabilityAttributes(PrefService
* pref
) {
605 int launch_count
= pref
->GetInteger(prefs::kStabilityLaunchCount
);
606 pref
->SetInteger(prefs::kStabilityLaunchCount
, 0);
607 int crash_count
= pref
->GetInteger(prefs::kStabilityCrashCount
);
608 pref
->SetInteger(prefs::kStabilityCrashCount
, 0);
610 SystemProfileProto::Stability
* stability
=
611 uma_proto()->mutable_system_profile()->mutable_stability();
612 stability
->set_launch_count(launch_count
);
613 stability
->set_crash_count(crash_count
);
616 void MetricsLog::WriteRealtimeStabilityAttributes(
618 base::TimeDelta incremental_uptime
) {
619 // Update the stats which are critical for real-time stability monitoring.
620 // Since these are "optional," only list ones that are non-zero, as the counts
621 // are aggregated (summed) server side.
623 SystemProfileProto::Stability
* stability
=
624 uma_proto()->mutable_system_profile()->mutable_stability();
625 int count
= pref
->GetInteger(prefs::kStabilityPageLoadCount
);
627 stability
->set_page_load_count(count
);
628 pref
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
631 count
= pref
->GetInteger(prefs::kStabilityRendererCrashCount
);
633 stability
->set_renderer_crash_count(count
);
634 pref
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
637 count
= pref
->GetInteger(prefs::kStabilityExtensionRendererCrashCount
);
639 stability
->set_extension_renderer_crash_count(count
);
640 pref
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
643 count
= pref
->GetInteger(prefs::kStabilityRendererHangCount
);
645 stability
->set_renderer_hang_count(count
);
646 pref
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
649 count
= pref
->GetInteger(prefs::kStabilityChildProcessCrashCount
);
651 stability
->set_child_process_crash_count(count
);
652 pref
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
655 #if defined(OS_CHROMEOS)
656 count
= pref
->GetInteger(prefs::kStabilityOtherUserCrashCount
);
658 stability
->set_other_user_crash_count(count
);
659 pref
->SetInteger(prefs::kStabilityOtherUserCrashCount
, 0);
662 count
= pref
->GetInteger(prefs::kStabilityKernelCrashCount
);
664 stability
->set_kernel_crash_count(count
);
665 pref
->SetInteger(prefs::kStabilityKernelCrashCount
, 0);
668 count
= pref
->GetInteger(prefs::kStabilitySystemUncleanShutdownCount
);
670 stability
->set_unclean_system_shutdown_count(count
);
671 pref
->SetInteger(prefs::kStabilitySystemUncleanShutdownCount
, 0);
673 #endif // OS_CHROMEOS
675 const uint64 uptime_sec
= incremental_uptime
.InSeconds();
677 stability
->set_uptime_sec(uptime_sec
);
680 void MetricsLog::WritePluginList(
681 const std::vector
<content::WebPluginInfo
>& plugin_list
) {
684 #if defined(ENABLE_PLUGINS)
685 PluginPrefs
* plugin_prefs
= GetPluginPrefs();
686 SystemProfileProto
* system_profile
= uma_proto()->mutable_system_profile();
687 for (std::vector
<content::WebPluginInfo
>::const_iterator iter
=
689 iter
!= plugin_list
.end(); ++iter
) {
690 SystemProfileProto::Plugin
* plugin
= system_profile
->add_plugin();
691 SetPluginInfo(*iter
, plugin_prefs
, plugin
);
693 #endif // defined(ENABLE_PLUGINS)
696 void MetricsLog::RecordEnvironment(
697 const std::vector
<content::WebPluginInfo
>& plugin_list
,
698 const GoogleUpdateMetrics
& google_update_metrics
,
699 const std::vector
<chrome_variations::ActiveGroupId
>& synthetic_trials
) {
700 DCHECK(!HasEnvironment());
702 SystemProfileProto
* system_profile
= uma_proto()->mutable_system_profile();
704 std::string brand_code
;
705 if (google_util::GetBrand(&brand_code
))
706 system_profile
->set_brand_code(brand_code
);
709 bool success
= base::StringToInt(GetMetricsEnabledDate(GetPrefService()),
713 // Reduce granularity of the enabled_date field to nearest hour.
714 system_profile
->set_uma_enabled_date(RoundSecondsToHour(enabled_date
));
716 int64 install_date
= GetPrefService()->GetInt64(prefs::kInstallDate
);
718 // Reduce granularity of the install_date field to nearest hour.
719 system_profile
->set_install_date(RoundSecondsToHour(install_date
));
721 system_profile
->set_application_locale(
722 g_browser_process
->GetApplicationLocale());
724 SystemProfileProto::Hardware
* hardware
= system_profile
->mutable_hardware();
725 hardware
->set_cpu_architecture(base::SysInfo::OperatingSystemArchitecture());
726 hardware
->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
728 hardware
->set_dll_base(reinterpret_cast<uint64
>(&__ImageBase
));
731 SystemProfileProto::Network
* network
= system_profile
->mutable_network();
732 network
->set_connection_type_is_ambiguous(
733 network_observer_
.connection_type_is_ambiguous());
734 network
->set_connection_type(network_observer_
.connection_type());
735 network
->set_wifi_phy_layer_protocol_is_ambiguous(
736 network_observer_
.wifi_phy_layer_protocol_is_ambiguous());
737 network
->set_wifi_phy_layer_protocol(
738 network_observer_
.wifi_phy_layer_protocol());
739 network_observer_
.Reset();
741 SystemProfileProto::OS
* os
= system_profile
->mutable_os();
742 std::string os_name
= base::SysInfo::OperatingSystemName();
744 // TODO(mad): This only checks whether the main process is a Metro process at
745 // upload time; not whether the collected metrics were all gathered from
746 // Metro. This is ok as an approximation for now, since users will rarely be
747 // switching from Metro to Desktop mode; but we should re-evaluate whether we
748 // can distinguish metrics more cleanly in the future: http://crbug.com/140568
749 if (base::win::IsMetroProcess())
750 os_name
+= " (Metro)";
752 os
->set_name(os_name
);
753 os
->set_version(base::SysInfo::OperatingSystemVersion());
754 #if defined(OS_ANDROID)
756 base::android::BuildInfo::GetInstance()->android_build_fp());
760 SystemProfileProto::Hardware::CPU
* cpu
= hardware
->mutable_cpu();
761 cpu
->set_vendor_name(cpu_info
.vendor_name());
762 cpu
->set_signature(cpu_info
.signature());
764 const gpu::GPUInfo
& gpu_info
=
765 GpuDataManager::GetInstance()->GetGPUInfo();
766 SystemProfileProto::Hardware::Graphics
* gpu
= hardware
->mutable_gpu();
767 gpu
->set_vendor_id(gpu_info
.gpu
.vendor_id
);
768 gpu
->set_device_id(gpu_info
.gpu
.device_id
);
769 gpu
->set_driver_version(gpu_info
.driver_version
);
770 gpu
->set_driver_date(gpu_info
.driver_date
);
771 SystemProfileProto::Hardware::Graphics::PerformanceStatistics
*
772 gpu_performance
= gpu
->mutable_performance_statistics();
773 gpu_performance
->set_graphics_score(gpu_info
.performance_stats
.graphics
);
774 gpu_performance
->set_gaming_score(gpu_info
.performance_stats
.gaming
);
775 gpu_performance
->set_overall_score(gpu_info
.performance_stats
.overall
);
776 gpu
->set_gl_vendor(gpu_info
.gl_vendor
);
777 gpu
->set_gl_renderer(gpu_info
.gl_renderer
);
779 const gfx::Size display_size
= GetScreenSize();
780 hardware
->set_primary_screen_width(display_size
.width());
781 hardware
->set_primary_screen_height(display_size
.height());
782 hardware
->set_primary_screen_scale_factor(GetScreenDeviceScaleFactor());
783 hardware
->set_screen_count(GetScreenCount());
786 WriteScreenDPIInformationProto(hardware
);
789 WriteGoogleUpdateProto(google_update_metrics
);
791 WritePluginList(plugin_list
);
793 std::vector
<ActiveGroupId
> field_trial_ids
;
794 GetFieldTrialIds(&field_trial_ids
);
795 WriteFieldTrials(field_trial_ids
, system_profile
);
796 WriteFieldTrials(synthetic_trials
, system_profile
);
798 #if defined(OS_CHROMEOS)
799 PerfDataProto perf_data_proto
;
800 if (perf_provider_
.GetPerfData(&perf_data_proto
))
801 uma_proto()->add_perf_data()->Swap(&perf_data_proto
);
803 WriteBluetoothProto(hardware
);
804 UpdateMultiProfileUserCount();
807 std::string serialied_system_profile
;
808 std::string base64_system_profile
;
809 if (system_profile
->SerializeToString(&serialied_system_profile
)) {
810 base::Base64Encode(serialied_system_profile
, &base64_system_profile
);
811 PrefService
* local_state
= GetPrefService();
812 local_state
->SetString(prefs::kStabilitySavedSystemProfile
,
813 base64_system_profile
);
814 local_state
->SetString(prefs::kStabilitySavedSystemProfileHash
,
815 ComputeSHA1(serialied_system_profile
));
819 bool MetricsLog::LoadSavedEnvironmentFromPrefs() {
820 PrefService
* local_state
= GetPrefService();
821 const std::string base64_system_profile
=
822 local_state
->GetString(prefs::kStabilitySavedSystemProfile
);
823 if (base64_system_profile
.empty())
826 const std::string system_profile_hash
=
827 local_state
->GetString(prefs::kStabilitySavedSystemProfileHash
);
828 local_state
->ClearPref(prefs::kStabilitySavedSystemProfile
);
829 local_state
->ClearPref(prefs::kStabilitySavedSystemProfileHash
);
831 SystemProfileProto
* system_profile
= uma_proto()->mutable_system_profile();
832 std::string serialied_system_profile
;
833 return base::Base64Decode(base64_system_profile
, &serialied_system_profile
) &&
834 ComputeSHA1(serialied_system_profile
) == system_profile_hash
&&
835 system_profile
->ParseFromString(serialied_system_profile
);
838 void MetricsLog::RecordProfilerData(
839 const tracked_objects::ProcessDataSnapshot
& process_data
,
843 if (tracked_objects::GetTimeSourceType() !=
844 tracked_objects::TIME_SOURCE_TYPE_WALL_TIME
) {
845 // We currently only support the default time source, wall clock time.
849 ProfilerEventProto
* profile
;
850 if (!uma_proto()->profiler_event_size()) {
851 // For the first process's data, add a new field to the protocol buffer.
852 profile
= uma_proto()->add_profiler_event();
853 profile
->set_profile_type(ProfilerEventProto::STARTUP_PROFILE
);
854 profile
->set_time_source(ProfilerEventProto::WALL_CLOCK_TIME
);
856 // For the remaining calls, re-use the existing field.
857 profile
= uma_proto()->mutable_profiler_event(0);
860 WriteProfilerData(process_data
, process_type
, profile
);
863 void MetricsLog::RecordOmniboxOpenedURL(const OmniboxLog
& log
) {
866 std::vector
<base::string16
> terms
;
867 const int num_terms
=
868 static_cast<int>(Tokenize(log
.text
, base::kWhitespaceUTF16
, &terms
));
870 OmniboxEventProto
* omnibox_event
= uma_proto()->add_omnibox_event();
871 omnibox_event
->set_time(MetricsLogBase::GetCurrentTime());
872 if (log
.tab_id
!= -1) {
873 // If we know what tab the autocomplete URL was opened in, log it.
874 omnibox_event
->set_tab_id(log
.tab_id
);
876 omnibox_event
->set_typed_length(log
.text
.length());
877 omnibox_event
->set_just_deleted_text(log
.just_deleted_text
);
878 omnibox_event
->set_num_typed_terms(num_terms
);
879 omnibox_event
->set_selected_index(log
.selected_index
);
880 if (log
.completed_length
!= base::string16::npos
)
881 omnibox_event
->set_completed_length(log
.completed_length
);
882 if (log
.elapsed_time_since_user_first_modified_omnibox
!=
883 base::TimeDelta::FromMilliseconds(-1)) {
884 // Only upload the typing duration if it is set/valid.
885 omnibox_event
->set_typing_duration_ms(
886 log
.elapsed_time_since_user_first_modified_omnibox
.InMilliseconds());
888 omnibox_event
->set_duration_since_last_default_match_update_ms(
889 log
.elapsed_time_since_last_change_to_default_match
.InMilliseconds());
890 omnibox_event
->set_current_page_classification(
891 AsOmniboxEventPageClassification(log
.current_page_classification
));
892 omnibox_event
->set_input_type(AsOmniboxEventInputType(log
.input_type
));
893 omnibox_event
->set_is_top_result_hidden_in_dropdown(
894 log
.result
.ShouldHideTopMatch());
896 for (AutocompleteResult::const_iterator
i(log
.result
.begin());
897 i
!= log
.result
.end(); ++i
) {
898 OmniboxEventProto::Suggestion
* suggestion
= omnibox_event
->add_suggestion();
899 suggestion
->set_provider(i
->provider
->AsOmniboxEventProviderType());
900 suggestion
->set_result_type(AsOmniboxEventResultType(i
->type
));
901 suggestion
->set_relevance(i
->relevance
);
902 if (i
->typed_count
!= -1)
903 suggestion
->set_typed_count(i
->typed_count
);
904 suggestion
->set_is_starred(i
->starred
);
906 for (ProvidersInfo::const_iterator
i(log
.providers_info
.begin());
907 i
!= log
.providers_info
.end(); ++i
) {
908 OmniboxEventProto::ProviderInfo
* provider_info
=
909 omnibox_event
->add_provider_info();
910 provider_info
->CopyFrom(*i
);
916 void MetricsLog::WriteGoogleUpdateProto(
917 const GoogleUpdateMetrics
& google_update_metrics
) {
918 #if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
919 SystemProfileProto::GoogleUpdate
* google_update
=
920 uma_proto()->mutable_system_profile()->mutable_google_update();
922 google_update
->set_is_system_install(google_update_metrics
.is_system_install
);
924 if (!google_update_metrics
.last_started_au
.is_null()) {
925 google_update
->set_last_automatic_start_timestamp(
926 google_update_metrics
.last_started_au
.ToTimeT());
929 if (!google_update_metrics
.last_checked
.is_null()) {
930 google_update
->set_last_update_check_timestamp(
931 google_update_metrics
.last_checked
.ToTimeT());
934 if (!google_update_metrics
.google_update_data
.version
.empty()) {
935 ProductDataToProto(google_update_metrics
.google_update_data
,
936 google_update
->mutable_google_update_status());
939 if (!google_update_metrics
.product_data
.version
.empty()) {
940 ProductDataToProto(google_update_metrics
.product_data
,
941 google_update
->mutable_client_status());
943 #endif // defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
946 void MetricsLog::SetBluetoothAdapter(
947 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
951 void MetricsLog::WriteBluetoothProto(
952 SystemProfileProto::Hardware
* hardware
) {
953 #if defined(OS_CHROMEOS)
954 // BluetoothAdapterFactory::GetAdapter is synchronous on Chrome OS; if that
955 // changes this will fail at the DCHECK().
956 device::BluetoothAdapterFactory::GetAdapter(
957 base::Bind(&MetricsLog::SetBluetoothAdapter
,
958 base::Unretained(this)));
959 DCHECK(adapter_
.get());
961 SystemProfileProto::Hardware::Bluetooth
* bluetooth
=
962 hardware
->mutable_bluetooth();
964 bluetooth
->set_is_present(adapter_
->IsPresent());
965 bluetooth
->set_is_enabled(adapter_
->IsPowered());
967 device::BluetoothAdapter::DeviceList devices
= adapter_
->GetDevices();
968 for (device::BluetoothAdapter::DeviceList::iterator iter
=
969 devices
.begin(); iter
!= devices
.end(); ++iter
) {
970 PairedDevice
* paired_device
= bluetooth
->add_paired_device();
972 device::BluetoothDevice
* device
= *iter
;
973 paired_device
->set_bluetooth_class(device
->GetBluetoothClass());
974 paired_device
->set_type(AsBluetoothDeviceType(device
->GetDeviceType()));
976 // address is xx:xx:xx:xx:xx:xx, extract the first three components and
977 // pack into a uint32
978 std::string address
= device
->GetAddress();
979 if (address
.size() > 9 &&
980 address
[2] == ':' && address
[5] == ':' && address
[8] == ':') {
981 std::string vendor_prefix_str
;
982 uint64 vendor_prefix
;
984 base::RemoveChars(address
.substr(0, 9), ":", &vendor_prefix_str
);
985 DCHECK_EQ(6U, vendor_prefix_str
.size());
986 base::HexStringToUInt64(vendor_prefix_str
, &vendor_prefix
);
988 paired_device
->set_vendor_prefix(vendor_prefix
);
991 paired_device
->set_vendor_id(device
->GetVendorID());
992 paired_device
->set_product_id(device
->GetProductID());
993 paired_device
->set_device_id(device
->GetDeviceID());
995 #endif // defined(OS_CHROMEOS)
998 #if defined(OS_CHROMEOS)
999 void MetricsLog::UpdateMultiProfileUserCount() {
1000 if (chromeos::UserManager::IsInitialized() &&
1001 chromeos::UserManager::Get()->IsMultipleProfilesAllowed()) {
1002 uint32 user_count
= chromeos::UserManager::Get()
1003 ->GetLoggedInUsers().size();
1004 SystemProfileProto
* system_profile
= uma_proto()->mutable_system_profile();
1006 // We invalidate the user count if it changed while the log was open.
1007 if (system_profile
->has_multi_profile_user_count() &&
1008 user_count
!= system_profile
->multi_profile_user_count())
1011 system_profile
->set_multi_profile_user_count(user_count
);