Home | History | Annotate | Download | only in metrics
      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.
      4 
      5 #include "chrome/browser/metrics/chromeos_metrics_provider.h"
      6 
      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"
     24 
     25 #if defined(USE_X11)
     26 #include "ui/events/x/touch_factory_x11.h"
     27 #endif  // defined(USE_X11)
     28 
     29 using metrics::ChromeUserMetricsExtension;
     30 using metrics::SampledProfile;
     31 using metrics::SystemProfileProto;
     32 typedef SystemProfileProto::Hardware::Bluetooth::PairedDevice PairedDevice;
     33 
     34 namespace {
     35 
     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;
     67   }
     68 
     69   NOTREACHED();
     70   return PairedDevice::DEVICE_UNKNOWN;
     71 }
     72 
     73 void WriteExternalTouchscreensProto(SystemProfileProto::Hardware* hardware) {
     74 #if defined(USE_X11)
     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();
     79        ++it) {
     80     SystemProfileProto::Hardware::TouchScreen* touchscreen =
     81         hardware->add_external_touchscreen();
     82     touchscreen->set_vendor_id(it->first);
     83     touchscreen->set_product_id(it->second);
     84   }
     85 #endif  // defined(USE_X11)
     86 }
     87 
     88 void IncrementPrefValue(const char* path) {
     89   PrefService* pref = g_browser_process->local_state();
     90   DCHECK(pref);
     91   int value = pref->GetInteger(path);
     92   pref->SetInteger(path, value + 1);
     93 }
     94 
     95 }  // namespace
     96 
     97 ChromeOSMetricsProvider::ChromeOSMetricsProvider()
     98     : registered_user_count_at_log_initialization_(false),
     99       user_count_at_log_initialization_(0),
    100       weak_ptr_factory_(this) {
    101 }
    102 
    103 ChromeOSMetricsProvider::~ChromeOSMetricsProvider() {
    104 }
    105 
    106 // static
    107 void ChromeOSMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
    108   registry->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount, 0);
    109   registry->RegisterIntegerPref(prefs::kStabilityKernelCrashCount, 0);
    110   registry->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount, 0);
    111 }
    112 
    113 // static
    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);
    121   else
    122     NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type;
    123 
    124   // Wake up metrics logs sending if necessary now that new
    125   // log data is available.
    126   g_browser_process->metrics_service()->OnApplicationNotIdle();
    127 }
    128 
    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();
    135   }
    136 }
    137 
    138 void ChromeOSMetricsProvider::InitTaskGetHardwareClass(
    139     const base::Closure& callback) {
    140   // Run the (potentially expensive) task on the FILE thread to avoid blocking
    141   // the UI thread.
    142   content::BrowserThread::PostTaskAndReply(
    143       content::BrowserThread::FILE,
    144       FROM_HERE,
    145       base::Bind(&ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread,
    146                  weak_ptr_factory_.GetWeakPtr()),
    147       callback);
    148 }
    149 
    150 void ChromeOSMetricsProvider::InitTaskGetHardwareClassOnFileThread() {
    151   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
    152   chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
    153       "hardware_class", &hardware_class_);
    154 }
    155 
    156 void ChromeOSMetricsProvider::ProvideSystemProfileMetrics(
    157     metrics::SystemProfileProto* system_profile_proto) {
    158   WriteBluetoothProto(system_profile_proto);
    159   UpdateMultiProfileUserCount(system_profile_proto);
    160 
    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);
    170 }
    171 
    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);
    178   if (count) {
    179     stability_proto->set_other_user_crash_count(count);
    180     pref->SetInteger(prefs::kStabilityOtherUserCrashCount, 0);
    181   }
    182 
    183   count = pref->GetInteger(prefs::kStabilityKernelCrashCount);
    184   if (count) {
    185     stability_proto->set_kernel_crash_count(count);
    186     pref->SetInteger(prefs::kStabilityKernelCrashCount, 0);
    187   }
    188 
    189   count = pref->GetInteger(prefs::kStabilitySystemUncleanShutdownCount);
    190   if (count) {
    191     stability_proto->set_unclean_system_shutdown_count(count);
    192     pref->SetInteger(prefs::kStabilitySystemUncleanShutdownCount, 0);
    193   }
    194 }
    195 
    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();
    202          ++iter) {
    203       uma_proto->add_sampled_profile()->Swap(&(*iter));
    204     }
    205   }
    206 }
    207 
    208 void ChromeOSMetricsProvider::WriteBluetoothProto(
    209     metrics::SystemProfileProto* system_profile_proto) {
    210   metrics::SystemProfileProto::Hardware* hardware =
    211       system_profile_proto->mutable_hardware();
    212 
    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());
    218 
    219   SystemProfileProto::Hardware::Bluetooth* bluetooth =
    220       hardware->mutable_bluetooth();
    221 
    222   bluetooth->set_is_present(adapter_->IsPresent());
    223   bluetooth->set_is_enabled(adapter_->IsPowered());
    224 
    225   device::BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
    226   for (device::BluetoothAdapter::DeviceList::iterator iter = devices.begin();
    227        iter != devices.end();
    228        ++iter) {
    229     device::BluetoothDevice* device = *iter;
    230     // Don't collect information about LE devices yet.
    231     if (!device->IsPaired())
    232       continue;
    233 
    234     PairedDevice* paired_device = bluetooth->add_paired_device();
    235     paired_device->set_bluetooth_class(device->GetBluetoothClass());
    236     paired_device->set_type(AsBluetoothDeviceType(device->GetDeviceType()));
    237 
    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] == ':' &&
    242         address[8] == ':') {
    243       std::string vendor_prefix_str;
    244       uint64 vendor_prefix;
    245 
    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);
    249 
    250       paired_device->set_vendor_prefix(vendor_prefix);
    251     }
    252 
    253     switch (device->GetVendorIDSource()) {
    254       case device::BluetoothDevice::VENDOR_ID_BLUETOOTH:
    255         paired_device->set_vendor_id_source(PairedDevice::VENDOR_ID_BLUETOOTH);
    256         break;
    257       case device::BluetoothDevice::VENDOR_ID_USB:
    258         paired_device->set_vendor_id_source(PairedDevice::VENDOR_ID_USB);
    259         break;
    260       default:
    261         paired_device->set_vendor_id_source(PairedDevice::VENDOR_ID_UNKNOWN);
    262     }
    263 
    264     paired_device->set_vendor_id(device->GetVendorID());
    265     paired_device->set_product_id(device->GetProductID());
    266     paired_device->set_device_id(device->GetDeviceID());
    267   }
    268 }
    269 
    270 void ChromeOSMetricsProvider::UpdateMultiProfileUserCount(
    271     metrics::SystemProfileProto* system_profile_proto) {
    272   if (user_manager::UserManager::IsInitialized()) {
    273     size_t user_count =
    274         user_manager::UserManager::Get()->GetLoggedInUsers().size();
    275 
    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_) {
    279       user_count = 0;
    280     }
    281 
    282     system_profile_proto->set_multi_profile_user_count(user_count);
    283   }
    284 }
    285 
    286 void ChromeOSMetricsProvider::SetBluetoothAdapter(
    287     scoped_refptr<device::BluetoothAdapter> adapter) {
    288   adapter_ = adapter;
    289 }
    290