Home | History | Annotate | Download | only in net
      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 "components/metrics/net/network_metrics_provider.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/compiler_specific.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_split.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/task_runner_util.h"
     15 
     16 #if defined(OS_CHROMEOS)
     17 #include "components/metrics/net/wifi_access_point_info_provider_chromeos.h"
     18 #endif // OS_CHROMEOS
     19 
     20 using metrics::SystemProfileProto;
     21 
     22 NetworkMetricsProvider::NetworkMetricsProvider(
     23     base::TaskRunner* io_task_runner)
     24     : io_task_runner_(io_task_runner),
     25       connection_type_is_ambiguous_(false),
     26       wifi_phy_layer_protocol_is_ambiguous_(false),
     27       wifi_phy_layer_protocol_(net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN),
     28       weak_ptr_factory_(this) {
     29   net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
     30   connection_type_ = net::NetworkChangeNotifier::GetConnectionType();
     31   ProbeWifiPHYLayerProtocol();
     32 }
     33 
     34 NetworkMetricsProvider::~NetworkMetricsProvider() {
     35   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
     36 }
     37 
     38 void NetworkMetricsProvider::OnDidCreateMetricsLog() {
     39   net::NetworkChangeNotifier::LogOperatorCodeHistogram(
     40       net::NetworkChangeNotifier::GetConnectionType());
     41 }
     42 
     43 void NetworkMetricsProvider::ProvideSystemProfileMetrics(
     44     SystemProfileProto* system_profile) {
     45   SystemProfileProto::Network* network = system_profile->mutable_network();
     46   network->set_connection_type_is_ambiguous(connection_type_is_ambiguous_);
     47   network->set_connection_type(GetConnectionType());
     48   network->set_wifi_phy_layer_protocol_is_ambiguous(
     49       wifi_phy_layer_protocol_is_ambiguous_);
     50   network->set_wifi_phy_layer_protocol(GetWifiPHYLayerProtocol());
     51 
     52   // Resets the "ambiguous" flags, since a new metrics log session has started.
     53   connection_type_is_ambiguous_ = false;
     54   // TODO(isherman): This line seems unnecessary.
     55   connection_type_ = net::NetworkChangeNotifier::GetConnectionType();
     56   wifi_phy_layer_protocol_is_ambiguous_ = false;
     57 
     58   if (!wifi_access_point_info_provider_.get()) {
     59 #if defined(OS_CHROMEOS)
     60     wifi_access_point_info_provider_.reset(
     61         new WifiAccessPointInfoProviderChromeos());
     62 #else
     63     wifi_access_point_info_provider_.reset(
     64         new WifiAccessPointInfoProvider());
     65 #endif // OS_CHROMEOS
     66   }
     67 
     68   // Connected wifi access point information.
     69   WifiAccessPointInfoProvider::WifiAccessPointInfo info;
     70   if (wifi_access_point_info_provider_->GetInfo(&info))
     71     WriteWifiAccessPointProto(info, network);
     72 }
     73 
     74 void NetworkMetricsProvider::OnConnectionTypeChanged(
     75     net::NetworkChangeNotifier::ConnectionType type) {
     76   if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
     77     return;
     78   if (type != connection_type_ &&
     79       connection_type_ != net::NetworkChangeNotifier::CONNECTION_NONE) {
     80     connection_type_is_ambiguous_ = true;
     81   }
     82   connection_type_ = type;
     83 
     84   ProbeWifiPHYLayerProtocol();
     85 }
     86 
     87 SystemProfileProto::Network::ConnectionType
     88 NetworkMetricsProvider::GetConnectionType() const {
     89   switch (connection_type_) {
     90     case net::NetworkChangeNotifier::CONNECTION_NONE:
     91     case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
     92       return SystemProfileProto::Network::CONNECTION_UNKNOWN;
     93     case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
     94       return SystemProfileProto::Network::CONNECTION_ETHERNET;
     95     case net::NetworkChangeNotifier::CONNECTION_WIFI:
     96       return SystemProfileProto::Network::CONNECTION_WIFI;
     97     case net::NetworkChangeNotifier::CONNECTION_2G:
     98       return SystemProfileProto::Network::CONNECTION_2G;
     99     case net::NetworkChangeNotifier::CONNECTION_3G:
    100       return SystemProfileProto::Network::CONNECTION_3G;
    101     case net::NetworkChangeNotifier::CONNECTION_4G:
    102       return SystemProfileProto::Network::CONNECTION_4G;
    103     case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
    104       return SystemProfileProto::Network::CONNECTION_BLUETOOTH;
    105   }
    106   NOTREACHED();
    107   return SystemProfileProto::Network::CONNECTION_UNKNOWN;
    108 }
    109 
    110 SystemProfileProto::Network::WifiPHYLayerProtocol
    111 NetworkMetricsProvider::GetWifiPHYLayerProtocol() const {
    112   switch (wifi_phy_layer_protocol_) {
    113     case net::WIFI_PHY_LAYER_PROTOCOL_NONE:
    114       return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_NONE;
    115     case net::WIFI_PHY_LAYER_PROTOCOL_ANCIENT:
    116       return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
    117     case net::WIFI_PHY_LAYER_PROTOCOL_A:
    118       return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_A;
    119     case net::WIFI_PHY_LAYER_PROTOCOL_B:
    120       return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_B;
    121     case net::WIFI_PHY_LAYER_PROTOCOL_G:
    122       return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_G;
    123     case net::WIFI_PHY_LAYER_PROTOCOL_N:
    124       return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_N;
    125     case net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN:
    126       return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
    127   }
    128   NOTREACHED();
    129   return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
    130 }
    131 
    132 void NetworkMetricsProvider::ProbeWifiPHYLayerProtocol() {
    133   PostTaskAndReplyWithResult(
    134       io_task_runner_,
    135       FROM_HERE,
    136       base::Bind(&net::GetWifiPHYLayerProtocol),
    137       base::Bind(&NetworkMetricsProvider::OnWifiPHYLayerProtocolResult,
    138                  weak_ptr_factory_.GetWeakPtr()));
    139 }
    140 
    141 void NetworkMetricsProvider::OnWifiPHYLayerProtocolResult(
    142     net::WifiPHYLayerProtocol mode) {
    143   if (wifi_phy_layer_protocol_ != net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN &&
    144       mode != wifi_phy_layer_protocol_) {
    145     wifi_phy_layer_protocol_is_ambiguous_ = true;
    146   }
    147   wifi_phy_layer_protocol_ = mode;
    148 }
    149 
    150 void NetworkMetricsProvider::WriteWifiAccessPointProto(
    151     const WifiAccessPointInfoProvider::WifiAccessPointInfo& info,
    152     SystemProfileProto::Network* network_proto) {
    153   SystemProfileProto::Network::WifiAccessPoint* access_point_info =
    154       network_proto->mutable_access_point_info();
    155   SystemProfileProto::Network::WifiAccessPoint::SecurityMode security =
    156       SystemProfileProto::Network::WifiAccessPoint::SECURITY_UNKNOWN;
    157   switch (info.security) {
    158     case WifiAccessPointInfoProvider::WIFI_SECURITY_NONE:
    159       security = SystemProfileProto::Network::WifiAccessPoint::SECURITY_NONE;
    160       break;
    161     case WifiAccessPointInfoProvider::WIFI_SECURITY_WPA:
    162       security = SystemProfileProto::Network::WifiAccessPoint::SECURITY_WPA;
    163       break;
    164     case WifiAccessPointInfoProvider::WIFI_SECURITY_WEP:
    165       security = SystemProfileProto::Network::WifiAccessPoint::SECURITY_WEP;
    166       break;
    167     case WifiAccessPointInfoProvider::WIFI_SECURITY_RSN:
    168       security = SystemProfileProto::Network::WifiAccessPoint::SECURITY_RSN;
    169       break;
    170     case WifiAccessPointInfoProvider::WIFI_SECURITY_802_1X:
    171       security = SystemProfileProto::Network::WifiAccessPoint::SECURITY_802_1X;
    172       break;
    173     case WifiAccessPointInfoProvider::WIFI_SECURITY_PSK:
    174       security = SystemProfileProto::Network::WifiAccessPoint::SECURITY_PSK;
    175       break;
    176     case WifiAccessPointInfoProvider::WIFI_SECURITY_UNKNOWN:
    177       security = SystemProfileProto::Network::WifiAccessPoint::SECURITY_UNKNOWN;
    178       break;
    179   }
    180   access_point_info->set_security_mode(security);
    181 
    182   // |bssid| is xx:xx:xx:xx:xx:xx, extract the first three components and
    183   // pack into a uint32.
    184   std::string bssid = info.bssid;
    185   if (bssid.size() == 17 && bssid[2] == ':' && bssid[5] == ':' &&
    186       bssid[8] == ':' && bssid[11] == ':' && bssid[14] == ':') {
    187     std::string vendor_prefix_str;
    188     uint32 vendor_prefix;
    189 
    190     base::RemoveChars(bssid.substr(0, 9), ":", &vendor_prefix_str);
    191     DCHECK_EQ(6U, vendor_prefix_str.size());
    192     if (base::HexStringToUInt(vendor_prefix_str, &vendor_prefix))
    193       access_point_info->set_vendor_prefix(vendor_prefix);
    194     else
    195       NOTREACHED();
    196   }
    197 
    198   // Return if vendor information is not provided.
    199   if (info.model_number.empty() && info.model_name.empty() &&
    200       info.device_name.empty() && info.oui_list.empty())
    201     return;
    202 
    203   SystemProfileProto::Network::WifiAccessPoint::VendorInformation* vendor =
    204       access_point_info->mutable_vendor_info();
    205   if (!info.model_number.empty())
    206     vendor->set_model_number(info.model_number);
    207   if (!info.model_name.empty())
    208     vendor->set_model_name(info.model_name);
    209   if (!info.device_name.empty())
    210     vendor->set_device_name(info.device_name);
    211 
    212   // Return if OUI list is not provided.
    213   if (info.oui_list.empty())
    214     return;
    215 
    216   // Parse OUI list.
    217   std::vector<std::string> oui_list;
    218   base::SplitString(info.oui_list, ' ', &oui_list);
    219   for (std::vector<std::string>::const_iterator it = oui_list.begin();
    220        it != oui_list.end();
    221        ++it) {
    222     uint32 oui;
    223     if (base::HexStringToUInt(*it, &oui))
    224       vendor->add_element_identifier(oui);
    225     else
    226       NOTREACHED();
    227   }
    228 }
    229