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/browser/chromeos/policy/browser_policy_connector_chromeos.h"
14 #include "chrome/common/pref_names.h"
15 #include "chromeos/system/statistics_provider.h"
16 #include "components/metrics/metrics_service.h"
17 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
18 #include "components/user_manager/user_manager.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "device/bluetooth/bluetooth_adapter.h"
21 #include "device/bluetooth/bluetooth_adapter_factory.h"
22 #include "device/bluetooth/bluetooth_device.h"
23 #include "ui/events/event_utils.h"
24 #include "ui/gfx/screen.h"
27 #include "ui/events/devices/x11/touch_factory_x11.h"
28 #endif // defined(USE_X11)
30 using metrics::ChromeUserMetricsExtension
;
31 using metrics::SampledProfile
;
32 using metrics::SystemProfileProto
;
33 typedef SystemProfileProto::Hardware::Bluetooth::PairedDevice PairedDevice
;
37 PairedDevice::Type
AsBluetoothDeviceType(
38 device::BluetoothDevice::DeviceType device_type
) {
39 switch (device_type
) {
40 case device::BluetoothDevice::DEVICE_UNKNOWN
:
41 return PairedDevice::DEVICE_UNKNOWN
;
42 case device::BluetoothDevice::DEVICE_COMPUTER
:
43 return PairedDevice::DEVICE_COMPUTER
;
44 case device::BluetoothDevice::DEVICE_PHONE
:
45 return PairedDevice::DEVICE_PHONE
;
46 case device::BluetoothDevice::DEVICE_MODEM
:
47 return PairedDevice::DEVICE_MODEM
;
48 case device::BluetoothDevice::DEVICE_AUDIO
:
49 return PairedDevice::DEVICE_AUDIO
;
50 case device::BluetoothDevice::DEVICE_CAR_AUDIO
:
51 return PairedDevice::DEVICE_CAR_AUDIO
;
52 case device::BluetoothDevice::DEVICE_VIDEO
:
53 return PairedDevice::DEVICE_VIDEO
;
54 case device::BluetoothDevice::DEVICE_PERIPHERAL
:
55 return PairedDevice::DEVICE_PERIPHERAL
;
56 case device::BluetoothDevice::DEVICE_JOYSTICK
:
57 return PairedDevice::DEVICE_JOYSTICK
;
58 case device::BluetoothDevice::DEVICE_GAMEPAD
:
59 return PairedDevice::DEVICE_GAMEPAD
;
60 case device::BluetoothDevice::DEVICE_KEYBOARD
:
61 return PairedDevice::DEVICE_KEYBOARD
;
62 case device::BluetoothDevice::DEVICE_MOUSE
:
63 return PairedDevice::DEVICE_MOUSE
;
64 case device::BluetoothDevice::DEVICE_TABLET
:
65 return PairedDevice::DEVICE_TABLET
;
66 case device::BluetoothDevice::DEVICE_KEYBOARD_MOUSE_COMBO
:
67 return PairedDevice::DEVICE_KEYBOARD_MOUSE_COMBO
;
71 return PairedDevice::DEVICE_UNKNOWN
;
74 void WriteExternalTouchscreensProto(SystemProfileProto::Hardware
* hardware
) {
76 std::set
<std::pair
<int, int> > touchscreen_ids
=
77 ui::TouchFactory::GetInstance()->GetTouchscreenIds();
78 for (std::set
<std::pair
<int, int> >::iterator it
= touchscreen_ids
.begin();
79 it
!= touchscreen_ids
.end();
81 SystemProfileProto::Hardware::TouchScreen
* touchscreen
=
82 hardware
->add_external_touchscreen();
83 touchscreen
->set_vendor_id(it
->first
);
84 touchscreen
->set_product_id(it
->second
);
86 #endif // defined(USE_X11)
89 void IncrementPrefValue(const char* path
) {
90 PrefService
* pref
= g_browser_process
->local_state();
92 int value
= pref
->GetInteger(path
);
93 pref
->SetInteger(path
, value
+ 1);
96 const char kEduDomain
[] = ".edu";
98 // Possible device enrollment status for a Chrome OS device.
99 enum EnrollmentStatus
{
103 ERROR_GETTING_ENROLLMENT_STATUS
,
104 ENROLLMENT_STATUS_MAX
,
107 // Get the enrollment status.
108 EnrollmentStatus
GetEnrollmentStatus() {
109 policy::BrowserPolicyConnectorChromeOS
* connector
=
110 g_browser_process
->platform_part()->browser_policy_connector_chromeos();
112 return ERROR_GETTING_ENROLLMENT_STATUS
;
114 if (!connector
->IsEnterpriseManaged())
117 std::string domain
= connector
->GetEnterpriseDomain();
118 if (EndsWith(domain
, kEduDomain
, false /* case insensitive */))
121 return MANAGED_NON_EDU
;
126 ChromeOSMetricsProvider::ChromeOSMetricsProvider()
127 : registered_user_count_at_log_initialization_(false),
128 user_count_at_log_initialization_(0),
129 weak_ptr_factory_(this) {
132 ChromeOSMetricsProvider::~ChromeOSMetricsProvider() {
136 void ChromeOSMetricsProvider::RegisterPrefs(PrefRegistrySimple
* registry
) {
137 registry
->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount
, 0);
138 registry
->RegisterIntegerPref(prefs::kStabilityKernelCrashCount
, 0);
139 registry
->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount
, 0);
143 void ChromeOSMetricsProvider::LogCrash(const std::string
& crash_type
) {
144 if (crash_type
== "user")
145 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount
);
146 else if (crash_type
== "kernel")
147 IncrementPrefValue(prefs::kStabilityKernelCrashCount
);
148 else if (crash_type
== "uncleanshutdown")
149 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount
);
151 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type
;
153 // Wake up metrics logs sending if necessary now that new
154 // log data is available.
155 g_browser_process
->metrics_service()->OnApplicationNotIdle();
158 void ChromeOSMetricsProvider::OnDidCreateMetricsLog() {
159 registered_user_count_at_log_initialization_
= false;
160 if (user_manager::UserManager::IsInitialized()) {
161 registered_user_count_at_log_initialization_
= true;
162 user_count_at_log_initialization_
=
163 user_manager::UserManager::Get()->GetLoggedInUsers().size();
167 void ChromeOSMetricsProvider::InitTaskGetHardwareClass(
168 const base::Closure
& callback
) {
169 // Run the (potentially expensive) task on the FILE thread to avoid blocking
171 content::BrowserThread::PostTaskAndReply(
172 content::BrowserThread::FILE,
174 base::Bind(&ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread
,
175 weak_ptr_factory_
.GetWeakPtr()),
179 void ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread() {
180 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
181 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
182 "hardware_class", &hardware_class_
);
185 void ChromeOSMetricsProvider::ProvideSystemProfileMetrics(
186 metrics::SystemProfileProto
* system_profile_proto
) {
187 WriteBluetoothProto(system_profile_proto
);
188 UpdateMultiProfileUserCount(system_profile_proto
);
190 metrics::SystemProfileProto::Hardware
* hardware
=
191 system_profile_proto
->mutable_hardware();
192 hardware
->set_hardware_class(hardware_class_
);
193 gfx::Display::TouchSupport has_touch
= ui::GetInternalDisplayTouchSupport();
194 if (has_touch
== gfx::Display::TOUCH_SUPPORT_AVAILABLE
)
195 hardware
->set_internal_display_supports_touch(true);
196 else if (has_touch
== gfx::Display::TOUCH_SUPPORT_UNAVAILABLE
)
197 hardware
->set_internal_display_supports_touch(false);
198 WriteExternalTouchscreensProto(hardware
);
201 void ChromeOSMetricsProvider::ProvideStabilityMetrics(
202 metrics::SystemProfileProto
* system_profile_proto
) {
203 metrics::SystemProfileProto::Stability
* stability_proto
=
204 system_profile_proto
->mutable_stability();
205 PrefService
* pref
= g_browser_process
->local_state();
206 int count
= pref
->GetInteger(prefs::kStabilityOtherUserCrashCount
);
208 stability_proto
->set_other_user_crash_count(count
);
209 pref
->SetInteger(prefs::kStabilityOtherUserCrashCount
, 0);
212 count
= pref
->GetInteger(prefs::kStabilityKernelCrashCount
);
214 stability_proto
->set_kernel_crash_count(count
);
215 pref
->SetInteger(prefs::kStabilityKernelCrashCount
, 0);
218 count
= pref
->GetInteger(prefs::kStabilitySystemUncleanShutdownCount
);
220 stability_proto
->set_unclean_system_shutdown_count(count
);
221 pref
->SetInteger(prefs::kStabilitySystemUncleanShutdownCount
, 0);
225 void ChromeOSMetricsProvider::ProvideGeneralMetrics(
226 metrics::ChromeUserMetricsExtension
* uma_proto
) {
227 std::vector
<SampledProfile
> sampled_profiles
;
228 if (perf_provider_
.GetSampledProfiles(&sampled_profiles
)) {
229 for (std::vector
<SampledProfile
>::iterator iter
= sampled_profiles
.begin();
230 iter
!= sampled_profiles
.end();
232 uma_proto
->add_sampled_profile()->Swap(&(*iter
));
235 RecordEnrollmentStatus();
238 void ChromeOSMetricsProvider::WriteBluetoothProto(
239 metrics::SystemProfileProto
* system_profile_proto
) {
240 metrics::SystemProfileProto::Hardware
* hardware
=
241 system_profile_proto
->mutable_hardware();
243 // BluetoothAdapterFactory::GetAdapter is synchronous on Chrome OS; if that
244 // changes this will fail at the DCHECK().
245 device::BluetoothAdapterFactory::GetAdapter(base::Bind(
246 &ChromeOSMetricsProvider::SetBluetoothAdapter
, base::Unretained(this)));
247 DCHECK(adapter_
.get());
249 SystemProfileProto::Hardware::Bluetooth
* bluetooth
=
250 hardware
->mutable_bluetooth();
252 bluetooth
->set_is_present(adapter_
->IsPresent());
253 bluetooth
->set_is_enabled(adapter_
->IsPowered());
255 device::BluetoothAdapter::DeviceList devices
= adapter_
->GetDevices();
256 for (device::BluetoothAdapter::DeviceList::iterator iter
= devices
.begin();
257 iter
!= devices
.end();
259 device::BluetoothDevice
* device
= *iter
;
260 // Don't collect information about LE devices yet.
261 if (!device
->IsPaired())
264 PairedDevice
* paired_device
= bluetooth
->add_paired_device();
265 paired_device
->set_bluetooth_class(device
->GetBluetoothClass());
266 paired_device
->set_type(AsBluetoothDeviceType(device
->GetDeviceType()));
268 // |address| is xx:xx:xx:xx:xx:xx, extract the first three components and
269 // pack into a uint32.
270 std::string address
= device
->GetAddress();
271 if (address
.size() > 9 && address
[2] == ':' && address
[5] == ':' &&
273 std::string vendor_prefix_str
;
274 uint64 vendor_prefix
;
276 base::RemoveChars(address
.substr(0, 9), ":", &vendor_prefix_str
);
277 DCHECK_EQ(6U, vendor_prefix_str
.size());
278 base::HexStringToUInt64(vendor_prefix_str
, &vendor_prefix
);
280 paired_device
->set_vendor_prefix(vendor_prefix
);
283 switch (device
->GetVendorIDSource()) {
284 case device::BluetoothDevice::VENDOR_ID_BLUETOOTH
:
285 paired_device
->set_vendor_id_source(PairedDevice::VENDOR_ID_BLUETOOTH
);
287 case device::BluetoothDevice::VENDOR_ID_USB
:
288 paired_device
->set_vendor_id_source(PairedDevice::VENDOR_ID_USB
);
291 paired_device
->set_vendor_id_source(PairedDevice::VENDOR_ID_UNKNOWN
);
294 paired_device
->set_vendor_id(device
->GetVendorID());
295 paired_device
->set_product_id(device
->GetProductID());
296 paired_device
->set_device_id(device
->GetDeviceID());
300 void ChromeOSMetricsProvider::UpdateMultiProfileUserCount(
301 metrics::SystemProfileProto
* system_profile_proto
) {
302 if (user_manager::UserManager::IsInitialized()) {
304 user_manager::UserManager::Get()->GetLoggedInUsers().size();
306 // We invalidate the user count if it changed while the log was open.
307 if (registered_user_count_at_log_initialization_
&&
308 user_count
!= user_count_at_log_initialization_
) {
312 system_profile_proto
->set_multi_profile_user_count(user_count
);
316 void ChromeOSMetricsProvider::SetBluetoothAdapter(
317 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
321 void ChromeOSMetricsProvider::RecordEnrollmentStatus() {
322 UMA_HISTOGRAM_ENUMERATION(
323 "UMA.EnrollmentStatus", GetEnrollmentStatus(), ENROLLMENT_STATUS_MAX
);