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/chromeos_metrics_provider.h"
7 #include "base/prefs/pref_registry_simple.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/common/pref_names.h"
14 #include "chromeos/system/statistics_provider.h"
15 #include "components/metrics/metrics_service.h"
16 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
17 #include "components/user_manager/user_manager.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "device/bluetooth/bluetooth_adapter.h"
20 #include "device/bluetooth/bluetooth_adapter_factory.h"
21 #include "device/bluetooth/bluetooth_device.h"
22 #include "ui/events/event_utils.h"
23 #include "ui/gfx/screen.h"
26 #include "ui/events/devices/x11/touch_factory_x11.h"
27 #endif // defined(USE_X11)
29 using metrics::ChromeUserMetricsExtension
;
30 using metrics::SampledProfile
;
31 using metrics::SystemProfileProto
;
32 typedef SystemProfileProto::Hardware::Bluetooth::PairedDevice PairedDevice
;
36 PairedDevice::Type
AsBluetoothDeviceType(
37 device::BluetoothDevice::DeviceType device_type
) {
38 switch (device_type
) {
39 case device::BluetoothDevice::DEVICE_UNKNOWN
:
40 return PairedDevice::DEVICE_UNKNOWN
;
41 case device::BluetoothDevice::DEVICE_COMPUTER
:
42 return PairedDevice::DEVICE_COMPUTER
;
43 case device::BluetoothDevice::DEVICE_PHONE
:
44 return PairedDevice::DEVICE_PHONE
;
45 case device::BluetoothDevice::DEVICE_MODEM
:
46 return PairedDevice::DEVICE_MODEM
;
47 case device::BluetoothDevice::DEVICE_AUDIO
:
48 return PairedDevice::DEVICE_AUDIO
;
49 case device::BluetoothDevice::DEVICE_CAR_AUDIO
:
50 return PairedDevice::DEVICE_CAR_AUDIO
;
51 case device::BluetoothDevice::DEVICE_VIDEO
:
52 return PairedDevice::DEVICE_VIDEO
;
53 case device::BluetoothDevice::DEVICE_PERIPHERAL
:
54 return PairedDevice::DEVICE_PERIPHERAL
;
55 case device::BluetoothDevice::DEVICE_JOYSTICK
:
56 return PairedDevice::DEVICE_JOYSTICK
;
57 case device::BluetoothDevice::DEVICE_GAMEPAD
:
58 return PairedDevice::DEVICE_GAMEPAD
;
59 case device::BluetoothDevice::DEVICE_KEYBOARD
:
60 return PairedDevice::DEVICE_KEYBOARD
;
61 case device::BluetoothDevice::DEVICE_MOUSE
:
62 return PairedDevice::DEVICE_MOUSE
;
63 case device::BluetoothDevice::DEVICE_TABLET
:
64 return PairedDevice::DEVICE_TABLET
;
65 case device::BluetoothDevice::DEVICE_KEYBOARD_MOUSE_COMBO
:
66 return PairedDevice::DEVICE_KEYBOARD_MOUSE_COMBO
;
70 return PairedDevice::DEVICE_UNKNOWN
;
73 void WriteExternalTouchscreensProto(SystemProfileProto::Hardware
* hardware
) {
75 std::set
<std::pair
<int, int> > touchscreen_ids
=
76 ui::TouchFactory::GetInstance()->GetTouchscreenIds();
77 for (std::set
<std::pair
<int, int> >::iterator it
= touchscreen_ids
.begin();
78 it
!= touchscreen_ids
.end();
80 SystemProfileProto::Hardware::TouchScreen
* touchscreen
=
81 hardware
->add_external_touchscreen();
82 touchscreen
->set_vendor_id(it
->first
);
83 touchscreen
->set_product_id(it
->second
);
85 #endif // defined(USE_X11)
88 void IncrementPrefValue(const char* path
) {
89 PrefService
* pref
= g_browser_process
->local_state();
91 int value
= pref
->GetInteger(path
);
92 pref
->SetInteger(path
, value
+ 1);
97 ChromeOSMetricsProvider::ChromeOSMetricsProvider()
98 : registered_user_count_at_log_initialization_(false),
99 user_count_at_log_initialization_(0),
100 weak_ptr_factory_(this) {
103 ChromeOSMetricsProvider::~ChromeOSMetricsProvider() {
107 void ChromeOSMetricsProvider::RegisterPrefs(PrefRegistrySimple
* registry
) {
108 registry
->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount
, 0);
109 registry
->RegisterIntegerPref(prefs::kStabilityKernelCrashCount
, 0);
110 registry
->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount
, 0);
114 void ChromeOSMetricsProvider::LogCrash(const std::string
& crash_type
) {
115 if (crash_type
== "user")
116 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount
);
117 else if (crash_type
== "kernel")
118 IncrementPrefValue(prefs::kStabilityKernelCrashCount
);
119 else if (crash_type
== "uncleanshutdown")
120 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount
);
122 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type
;
124 // Wake up metrics logs sending if necessary now that new
125 // log data is available.
126 g_browser_process
->metrics_service()->OnApplicationNotIdle();
129 void ChromeOSMetricsProvider::OnDidCreateMetricsLog() {
130 registered_user_count_at_log_initialization_
= false;
131 if (user_manager::UserManager::IsInitialized()) {
132 registered_user_count_at_log_initialization_
= true;
133 user_count_at_log_initialization_
=
134 user_manager::UserManager::Get()->GetLoggedInUsers().size();
138 void ChromeOSMetricsProvider::InitTaskGetHardwareClass(
139 const base::Closure
& callback
) {
140 // Run the (potentially expensive) task on the FILE thread to avoid blocking
142 content::BrowserThread::PostTaskAndReply(
143 content::BrowserThread::FILE,
145 base::Bind(&ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread
,
146 weak_ptr_factory_
.GetWeakPtr()),
150 void ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread() {
151 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
152 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
153 "hardware_class", &hardware_class_
);
156 void ChromeOSMetricsProvider::ProvideSystemProfileMetrics(
157 metrics::SystemProfileProto
* system_profile_proto
) {
158 WriteBluetoothProto(system_profile_proto
);
159 UpdateMultiProfileUserCount(system_profile_proto
);
161 metrics::SystemProfileProto::Hardware
* hardware
=
162 system_profile_proto
->mutable_hardware();
163 hardware
->set_hardware_class(hardware_class_
);
164 gfx::Display::TouchSupport has_touch
= ui::GetInternalDisplayTouchSupport();
165 if (has_touch
== gfx::Display::TOUCH_SUPPORT_AVAILABLE
)
166 hardware
->set_internal_display_supports_touch(true);
167 else if (has_touch
== gfx::Display::TOUCH_SUPPORT_UNAVAILABLE
)
168 hardware
->set_internal_display_supports_touch(false);
169 WriteExternalTouchscreensProto(hardware
);
172 void ChromeOSMetricsProvider::ProvideStabilityMetrics(
173 metrics::SystemProfileProto
* system_profile_proto
) {
174 metrics::SystemProfileProto::Stability
* stability_proto
=
175 system_profile_proto
->mutable_stability();
176 PrefService
* pref
= g_browser_process
->local_state();
177 int count
= pref
->GetInteger(prefs::kStabilityOtherUserCrashCount
);
179 stability_proto
->set_other_user_crash_count(count
);
180 pref
->SetInteger(prefs::kStabilityOtherUserCrashCount
, 0);
183 count
= pref
->GetInteger(prefs::kStabilityKernelCrashCount
);
185 stability_proto
->set_kernel_crash_count(count
);
186 pref
->SetInteger(prefs::kStabilityKernelCrashCount
, 0);
189 count
= pref
->GetInteger(prefs::kStabilitySystemUncleanShutdownCount
);
191 stability_proto
->set_unclean_system_shutdown_count(count
);
192 pref
->SetInteger(prefs::kStabilitySystemUncleanShutdownCount
, 0);
196 void ChromeOSMetricsProvider::ProvideGeneralMetrics(
197 metrics::ChromeUserMetricsExtension
* uma_proto
) {
198 std::vector
<SampledProfile
> sampled_profiles
;
199 if (perf_provider_
.GetSampledProfiles(&sampled_profiles
)) {
200 for (std::vector
<SampledProfile
>::iterator iter
= sampled_profiles
.begin();
201 iter
!= sampled_profiles
.end();
203 uma_proto
->add_sampled_profile()->Swap(&(*iter
));
208 void ChromeOSMetricsProvider::WriteBluetoothProto(
209 metrics::SystemProfileProto
* system_profile_proto
) {
210 metrics::SystemProfileProto::Hardware
* hardware
=
211 system_profile_proto
->mutable_hardware();
213 // BluetoothAdapterFactory::GetAdapter is synchronous on Chrome OS; if that
214 // changes this will fail at the DCHECK().
215 device::BluetoothAdapterFactory::GetAdapter(base::Bind(
216 &ChromeOSMetricsProvider::SetBluetoothAdapter
, base::Unretained(this)));
217 DCHECK(adapter_
.get());
219 SystemProfileProto::Hardware::Bluetooth
* bluetooth
=
220 hardware
->mutable_bluetooth();
222 bluetooth
->set_is_present(adapter_
->IsPresent());
223 bluetooth
->set_is_enabled(adapter_
->IsPowered());
225 device::BluetoothAdapter::DeviceList devices
= adapter_
->GetDevices();
226 for (device::BluetoothAdapter::DeviceList::iterator iter
= devices
.begin();
227 iter
!= devices
.end();
229 device::BluetoothDevice
* device
= *iter
;
230 // Don't collect information about LE devices yet.
231 if (!device
->IsPaired())
234 PairedDevice
* paired_device
= bluetooth
->add_paired_device();
235 paired_device
->set_bluetooth_class(device
->GetBluetoothClass());
236 paired_device
->set_type(AsBluetoothDeviceType(device
->GetDeviceType()));
238 // |address| is xx:xx:xx:xx:xx:xx, extract the first three components and
239 // pack into a uint32.
240 std::string address
= device
->GetAddress();
241 if (address
.size() > 9 && address
[2] == ':' && address
[5] == ':' &&
243 std::string vendor_prefix_str
;
244 uint64 vendor_prefix
;
246 base::RemoveChars(address
.substr(0, 9), ":", &vendor_prefix_str
);
247 DCHECK_EQ(6U, vendor_prefix_str
.size());
248 base::HexStringToUInt64(vendor_prefix_str
, &vendor_prefix
);
250 paired_device
->set_vendor_prefix(vendor_prefix
);
253 switch (device
->GetVendorIDSource()) {
254 case device::BluetoothDevice::VENDOR_ID_BLUETOOTH
:
255 paired_device
->set_vendor_id_source(PairedDevice::VENDOR_ID_BLUETOOTH
);
257 case device::BluetoothDevice::VENDOR_ID_USB
:
258 paired_device
->set_vendor_id_source(PairedDevice::VENDOR_ID_USB
);
261 paired_device
->set_vendor_id_source(PairedDevice::VENDOR_ID_UNKNOWN
);
264 paired_device
->set_vendor_id(device
->GetVendorID());
265 paired_device
->set_product_id(device
->GetProductID());
266 paired_device
->set_device_id(device
->GetDeviceID());
270 void ChromeOSMetricsProvider::UpdateMultiProfileUserCount(
271 metrics::SystemProfileProto
* system_profile_proto
) {
272 if (user_manager::UserManager::IsInitialized()) {
274 user_manager::UserManager::Get()->GetLoggedInUsers().size();
276 // We invalidate the user count if it changed while the log was open.
277 if (registered_user_count_at_log_initialization_
&&
278 user_count
!= user_count_at_log_initialization_
) {
282 system_profile_proto
->set_multi_profile_user_count(user_count
);
286 void ChromeOSMetricsProvider::SetBluetoothAdapter(
287 scoped_refptr
<device::BluetoothAdapter
> adapter
) {