Changes for start_with_ext Telemetry test to work on Windows.
[chromium-blink-merge.git] / chrome / browser / metrics / chromeos_metrics_provider.cc
blob7c65d0b045f68e9ca2ab5a619f458348eb0e3581
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"
26 #if defined(USE_X11)
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;
35 namespace {
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;
70 NOTREACHED();
71 return PairedDevice::DEVICE_UNKNOWN;
74 void WriteExternalTouchscreensProto(SystemProfileProto::Hardware* hardware) {
75 #if defined(USE_X11)
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();
80 ++it) {
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();
91 DCHECK(pref);
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 {
100 NON_MANAGED,
101 MANAGED_EDU,
102 MANAGED_NON_EDU,
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();
111 if (!connector)
112 return ERROR_GETTING_ENROLLMENT_STATUS;
114 if (!connector->IsEnterpriseManaged())
115 return NON_MANAGED;
117 std::string domain = connector->GetEnterpriseDomain();
118 if (base::EndsWith(domain, kEduDomain, base::CompareCase::INSENSITIVE_ASCII))
119 return MANAGED_EDU;
121 return MANAGED_NON_EDU;
124 } // namespace
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() {
135 // static
136 void ChromeOSMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
137 registry->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount, 0);
138 registry->RegisterIntegerPref(prefs::kStabilityKernelCrashCount, 0);
139 registry->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount, 0);
142 // static
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);
150 else
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
170 // the UI thread.
171 content::BrowserThread::PostTaskAndReply(
172 content::BrowserThread::FILE,
173 FROM_HERE,
174 base::Bind(&ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread,
175 weak_ptr_factory_.GetWeakPtr()),
176 callback);
179 void ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread() {
180 DCHECK_CURRENTLY_ON(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);
207 if (count) {
208 stability_proto->set_other_user_crash_count(count);
209 pref->SetInteger(prefs::kStabilityOtherUserCrashCount, 0);
212 count = pref->GetInteger(prefs::kStabilityKernelCrashCount);
213 if (count) {
214 stability_proto->set_kernel_crash_count(count);
215 pref->SetInteger(prefs::kStabilityKernelCrashCount, 0);
218 count = pref->GetInteger(prefs::kStabilitySystemUncleanShutdownCount);
219 if (count) {
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();
231 ++iter) {
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();
258 ++iter) {
259 device::BluetoothDevice* device = *iter;
260 // Don't collect information about LE devices yet.
261 if (!device->IsPaired())
262 continue;
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] == ':' &&
272 address[8] == ':') {
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);
286 break;
287 case device::BluetoothDevice::VENDOR_ID_USB:
288 paired_device->set_vendor_id_source(PairedDevice::VENDOR_ID_USB);
289 break;
290 default:
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()) {
303 size_t user_count =
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_) {
309 user_count = 0;
312 system_profile_proto->set_multi_profile_user_count(user_count);
316 void ChromeOSMetricsProvider::SetBluetoothAdapter(
317 scoped_refptr<device::BluetoothAdapter> adapter) {
318 adapter_ = adapter;
321 void ChromeOSMetricsProvider::RecordEnrollmentStatus() {
322 UMA_HISTOGRAM_ENUMERATION(
323 "UMA.EnrollmentStatus", GetEnrollmentStatus(), ENROLLMENT_STATUS_MAX);