Home | History | Annotate | Download | only in network
      1 // Copyright (c) 2012 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 "chromeos/network/network_state_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/format_macros.h"
      9 #include "base/guid.h"
     10 #include "base/location.h"
     11 #include "base/logging.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/stl_util.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "base/values.h"
     17 #include "chromeos/network/device_state.h"
     18 #include "chromeos/network/managed_state.h"
     19 #include "chromeos/network/network_event_log.h"
     20 #include "chromeos/network/network_state.h"
     21 #include "chromeos/network/network_state_handler_observer.h"
     22 #include "chromeos/network/shill_property_handler.h"
     23 #include "third_party/cros_system_api/dbus/service_constants.h"
     24 
     25 namespace chromeos {
     26 
     27 namespace {
     28 
     29 bool ConnectionStateChanged(NetworkState* network,
     30                             const std::string& prev_connection_state) {
     31   return (network->connection_state() != prev_connection_state) &&
     32          (network->connection_state() != shill::kStateIdle ||
     33           !prev_connection_state.empty());
     34 }
     35 
     36 std::string GetManagedStateLogType(const ManagedState* state) {
     37   switch (state->managed_type()) {
     38     case ManagedState::MANAGED_TYPE_NETWORK:
     39       return "Network";
     40     case ManagedState::MANAGED_TYPE_DEVICE:
     41       return "Device";
     42   }
     43   NOTREACHED();
     44   return "";
     45 }
     46 
     47 std::string GetLogName(const ManagedState* state) {
     48   if (!state)
     49     return "None";
     50   return base::StringPrintf("%s (%s)", state->name().c_str(),
     51                             state->path().c_str());
     52 }
     53 
     54 }  // namespace
     55 
     56 const char NetworkStateHandler::kDefaultCheckPortalList[] =
     57     "ethernet,wifi,cellular";
     58 
     59 NetworkStateHandler::NetworkStateHandler()
     60     : network_list_sorted_(false) {
     61 }
     62 
     63 NetworkStateHandler::~NetworkStateHandler() {
     64   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_, IsShuttingDown());
     65   STLDeleteContainerPointers(network_list_.begin(), network_list_.end());
     66   STLDeleteContainerPointers(device_list_.begin(), device_list_.end());
     67 }
     68 
     69 void NetworkStateHandler::InitShillPropertyHandler() {
     70   shill_property_handler_.reset(new internal::ShillPropertyHandler(this));
     71   shill_property_handler_->Init();
     72 }
     73 
     74 // static
     75 NetworkStateHandler* NetworkStateHandler::InitializeForTest() {
     76   NetworkStateHandler* handler = new NetworkStateHandler();
     77   handler->InitShillPropertyHandler();
     78   return handler;
     79 }
     80 
     81 void NetworkStateHandler::AddObserver(
     82     NetworkStateHandlerObserver* observer,
     83     const tracked_objects::Location& from_here) {
     84   observers_.AddObserver(observer);
     85   network_event_log::internal::AddEntry(
     86       from_here.file_name(), from_here.line_number(),
     87       network_event_log::LOG_LEVEL_DEBUG,
     88       "NetworkStateHandler::AddObserver", "");
     89 }
     90 
     91 void NetworkStateHandler::RemoveObserver(
     92     NetworkStateHandlerObserver* observer,
     93     const tracked_objects::Location& from_here) {
     94   observers_.RemoveObserver(observer);
     95   network_event_log::internal::AddEntry(
     96       from_here.file_name(), from_here.line_number(),
     97       network_event_log::LOG_LEVEL_DEBUG,
     98       "NetworkStateHandler::RemoveObserver", "");
     99 }
    100 
    101 NetworkStateHandler::TechnologyState NetworkStateHandler::GetTechnologyState(
    102     const NetworkTypePattern& type) const {
    103   std::string technology = GetTechnologyForType(type);
    104   TechnologyState state;
    105   if (shill_property_handler_->IsTechnologyEnabled(technology))
    106     state = TECHNOLOGY_ENABLED;
    107   else if (shill_property_handler_->IsTechnologyEnabling(technology))
    108     state = TECHNOLOGY_ENABLING;
    109   else if (shill_property_handler_->IsTechnologyUninitialized(technology))
    110     state = TECHNOLOGY_UNINITIALIZED;
    111   else if (shill_property_handler_->IsTechnologyAvailable(technology))
    112     state = TECHNOLOGY_AVAILABLE;
    113   else
    114     state = TECHNOLOGY_UNAVAILABLE;
    115   VLOG(2) << "GetTechnologyState: " << type.ToDebugString() << " = " << state;
    116   return state;
    117 }
    118 
    119 void NetworkStateHandler::SetTechnologyEnabled(
    120     const NetworkTypePattern& type,
    121     bool enabled,
    122     const network_handler::ErrorCallback& error_callback) {
    123   ScopedVector<std::string> technologies = GetTechnologiesForType(type);
    124   for (ScopedVector<std::string>::iterator it = technologies.begin();
    125       it != technologies.end(); ++it) {
    126     std::string* technology = *it;
    127     DCHECK(technology);
    128     if (!shill_property_handler_->IsTechnologyAvailable(*technology))
    129       continue;
    130     NET_LOG_USER("SetTechnologyEnabled",
    131                  base::StringPrintf("%s:%d", technology->c_str(), enabled));
    132     shill_property_handler_->SetTechnologyEnabled(
    133         *technology, enabled, error_callback);
    134   }
    135   // Signal Device/Technology state changed.
    136   NotifyDeviceListChanged();
    137 }
    138 
    139 const DeviceState* NetworkStateHandler::GetDeviceState(
    140     const std::string& device_path) const {
    141   const DeviceState* device = GetModifiableDeviceState(device_path);
    142   if (device && !device->update_received())
    143     return NULL;
    144   return device;
    145 }
    146 
    147 const DeviceState* NetworkStateHandler::GetDeviceStateByType(
    148     const NetworkTypePattern& type) const {
    149   for (ManagedStateList::const_iterator iter = device_list_.begin();
    150        iter != device_list_.end(); ++iter) {
    151     ManagedState* device = *iter;
    152     if (!device->update_received())
    153       continue;
    154     if (device->Matches(type))
    155       return device->AsDeviceState();
    156   }
    157   return NULL;
    158 }
    159 
    160 bool NetworkStateHandler::GetScanningByType(
    161     const NetworkTypePattern& type) const {
    162   for (ManagedStateList::const_iterator iter = device_list_.begin();
    163        iter != device_list_.end(); ++iter) {
    164     const DeviceState* device = (*iter)->AsDeviceState();
    165     DCHECK(device);
    166     if (!device->update_received())
    167       continue;
    168     if (device->Matches(type) && device->scanning())
    169       return true;
    170   }
    171   return false;
    172 }
    173 
    174 const NetworkState* NetworkStateHandler::GetNetworkState(
    175     const std::string& service_path) const {
    176   const NetworkState* network = GetModifiableNetworkState(service_path);
    177   if (network && !network->update_received())
    178     return NULL;
    179   return network;
    180 }
    181 
    182 const NetworkState* NetworkStateHandler::DefaultNetwork() const {
    183   if (default_network_path_.empty())
    184     return NULL;
    185   return GetNetworkState(default_network_path_);
    186 }
    187 
    188 const NetworkState* NetworkStateHandler::ConnectedNetworkByType(
    189     const NetworkTypePattern& type) const {
    190   // Active networks are always listed first by Shill so no need to sort.
    191   for (ManagedStateList::const_iterator iter = network_list_.begin();
    192        iter != network_list_.end(); ++iter) {
    193     const NetworkState* network = (*iter)->AsNetworkState();
    194     DCHECK(network);
    195     if (!network->update_received())
    196       continue;
    197     if (!network->IsConnectedState())
    198       break;  // Connected networks are listed first.
    199     if (network->Matches(type))
    200       return network;
    201   }
    202   return NULL;
    203 }
    204 
    205 const NetworkState* NetworkStateHandler::ConnectingNetworkByType(
    206     const NetworkTypePattern& type) const {
    207   // Active networks are always listed first by Shill so no need to sort.
    208   for (ManagedStateList::const_iterator iter = network_list_.begin();
    209        iter != network_list_.end(); ++iter) {
    210     const NetworkState* network = (*iter)->AsNetworkState();
    211     DCHECK(network);
    212     if (!network->update_received() || network->IsConnectedState())
    213       continue;
    214     if (!network->IsConnectingState())
    215       break;  // Connected and connecting networks are listed first.
    216     if (network->Matches(type))
    217       return network;
    218   }
    219   return NULL;
    220 }
    221 
    222 const NetworkState* NetworkStateHandler::FirstNetworkByType(
    223     const NetworkTypePattern& type) {
    224   if (!network_list_sorted_)
    225     SortNetworkList();  // Sort to ensure visible networks are listed first.
    226   for (ManagedStateList::const_iterator iter = network_list_.begin();
    227        iter != network_list_.end(); ++iter) {
    228     const NetworkState* network = (*iter)->AsNetworkState();
    229     DCHECK(network);
    230     if (!network->update_received())
    231       continue;
    232     if (!network->visible())
    233       break;
    234     if (network->Matches(type))
    235       return network;
    236   }
    237   return NULL;
    238 }
    239 
    240 std::string NetworkStateHandler::FormattedHardwareAddressForType(
    241     const NetworkTypePattern& type) const {
    242   const DeviceState* device = NULL;
    243   const NetworkState* network = ConnectedNetworkByType(type);
    244   if (network)
    245     device = GetDeviceState(network->device_path());
    246   else
    247     device = GetDeviceStateByType(type);
    248   if (!device)
    249     return std::string();
    250   return network_util::FormattedMacAddress(device->mac_address());
    251 }
    252 
    253 void NetworkStateHandler::GetVisibleNetworkListByType(
    254     const NetworkTypePattern& type,
    255     NetworkStateList* list) {
    256   GetNetworkListByType(type,
    257                        false /* configured_only */,
    258                        true /* visible_only */,
    259                        0 /* no limit */,
    260                        list);
    261 }
    262 
    263 void NetworkStateHandler::GetVisibleNetworkList(NetworkStateList* list) {
    264   GetVisibleNetworkListByType(NetworkTypePattern::Default(), list);
    265 }
    266 
    267 void NetworkStateHandler::GetNetworkListByType(const NetworkTypePattern& type,
    268                                                bool configured_only,
    269                                                bool visible_only,
    270                                                int limit,
    271                                                NetworkStateList* list) {
    272   DCHECK(list);
    273   list->clear();
    274   int count = 0;
    275   // Sort the network list if necessary.
    276   if (!network_list_sorted_)
    277     SortNetworkList();
    278   for (ManagedStateList::const_iterator iter = network_list_.begin();
    279        iter != network_list_.end(); ++iter) {
    280     const NetworkState* network = (*iter)->AsNetworkState();
    281     DCHECK(network);
    282     if (!network->update_received() || !network->Matches(type))
    283       continue;
    284     if (configured_only && !network->IsInProfile())
    285       continue;
    286     if (visible_only && !network->visible())
    287       continue;
    288     list->push_back(network);
    289     if (limit > 0 && ++count >= limit)
    290       break;
    291   }
    292 }
    293 
    294 const NetworkState* NetworkStateHandler::GetNetworkStateFromServicePath(
    295     const std::string& service_path,
    296     bool configured_only) const {
    297   ManagedState* managed =
    298       GetModifiableManagedState(&network_list_, service_path);
    299   if (!managed)
    300     return NULL;
    301   const NetworkState* network = managed->AsNetworkState();
    302   DCHECK(network);
    303   if (!network->update_received() ||
    304       (configured_only && !network->IsInProfile())) {
    305     return NULL;
    306   }
    307   return network;
    308 }
    309 
    310 const NetworkState* NetworkStateHandler::GetNetworkStateFromGuid(
    311     const std::string& guid) const {
    312   DCHECK(!guid.empty());
    313   for (ManagedStateList::const_iterator iter = network_list_.begin();
    314        iter != network_list_.end(); ++iter) {
    315     const NetworkState* network = (*iter)->AsNetworkState();
    316     if (network->guid() == guid)
    317       return network;
    318   }
    319   return NULL;
    320 }
    321 
    322 void NetworkStateHandler::GetDeviceList(DeviceStateList* list) const {
    323   GetDeviceListByType(NetworkTypePattern::Default(), list);
    324 }
    325 
    326 void NetworkStateHandler::GetDeviceListByType(const NetworkTypePattern& type,
    327                                               DeviceStateList* list) const {
    328   DCHECK(list);
    329   list->clear();
    330   for (ManagedStateList::const_iterator iter = device_list_.begin();
    331        iter != device_list_.end(); ++iter) {
    332     const DeviceState* device = (*iter)->AsDeviceState();
    333     DCHECK(device);
    334     if (device->update_received() && device->Matches(type))
    335       list->push_back(device);
    336   }
    337 }
    338 
    339 void NetworkStateHandler::RequestScan() const {
    340   NET_LOG_USER("RequestScan", "");
    341   shill_property_handler_->RequestScan();
    342 }
    343 
    344 void NetworkStateHandler::WaitForScan(const std::string& type,
    345                                       const base::Closure& callback) {
    346   scan_complete_callbacks_[type].push_back(callback);
    347   if (!GetScanningByType(NetworkTypePattern::Primitive(type)))
    348     RequestScan();
    349 }
    350 
    351 void NetworkStateHandler::ConnectToBestWifiNetwork() {
    352   NET_LOG_USER("ConnectToBestWifiNetwork", "");
    353   WaitForScan(shill::kTypeWifi,
    354               base::Bind(&internal::ShillPropertyHandler::ConnectToBestServices,
    355                          shill_property_handler_->AsWeakPtr()));
    356 }
    357 
    358 void NetworkStateHandler::RequestUpdateForNetwork(
    359     const std::string& service_path) {
    360   NetworkState* network = GetModifiableNetworkState(service_path);
    361   if (network)
    362     network->set_update_requested(true);
    363   NET_LOG_EVENT("RequestUpdate", service_path);
    364   shill_property_handler_->RequestProperties(
    365       ManagedState::MANAGED_TYPE_NETWORK, service_path);
    366 }
    367 
    368 void NetworkStateHandler::ClearLastErrorForNetwork(
    369     const std::string& service_path) {
    370   NetworkState* network = GetModifiableNetworkState(service_path);
    371   if (network)
    372     network->clear_last_error();
    373 }
    374 
    375 void NetworkStateHandler::SetCheckPortalList(
    376     const std::string& check_portal_list) {
    377   NET_LOG_EVENT("SetCheckPortalList", check_portal_list);
    378   shill_property_handler_->SetCheckPortalList(check_portal_list);
    379 }
    380 
    381 const NetworkState* NetworkStateHandler::GetEAPForEthernet(
    382     const std::string& service_path) {
    383   const NetworkState* network = GetNetworkState(service_path);
    384   if (!network) {
    385     NET_LOG_ERROR("GetEAPForEthernet", "Unknown service path " + service_path);
    386     return NULL;
    387   }
    388   if (network->type() != shill::kTypeEthernet) {
    389     NET_LOG_ERROR("GetEAPForEthernet", "Not of type Ethernet: " + service_path);
    390     return NULL;
    391   }
    392   if (!network->IsConnectedState())
    393     return NULL;
    394 
    395   // The same EAP service is shared for all ethernet services/devices.
    396   // However EAP is used/enabled per device and only if the connection was
    397   // successfully established.
    398   const DeviceState* device = GetDeviceState(network->device_path());
    399   if (!device) {
    400     NET_LOG_ERROR(
    401         "GetEAPForEthernet",
    402         base::StringPrintf("Unknown device %s of connected ethernet service %s",
    403                            network->device_path().c_str(),
    404                            service_path.c_str()));
    405     return NULL;
    406   }
    407   if (!device->eap_authentication_completed())
    408     return NULL;
    409 
    410   NetworkStateList list;
    411   GetNetworkListByType(NetworkTypePattern::Primitive(shill::kTypeEthernetEap),
    412                        true /* configured_only */,
    413                        false /* visible_only */,
    414                        1 /* limit */,
    415                        &list);
    416   if (list.empty()) {
    417     NET_LOG_ERROR("GetEAPForEthernet",
    418                   base::StringPrintf(
    419                       "Ethernet service %s connected using EAP, but no "
    420                       "EAP service found.",
    421                       service_path.c_str()));
    422     return NULL;
    423   }
    424   return list.front();
    425 }
    426 
    427 //------------------------------------------------------------------------------
    428 // ShillPropertyHandler::Delegate overrides
    429 
    430 void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
    431                                             const base::ListValue& entries) {
    432   ManagedStateList* managed_list = GetManagedList(type);
    433   NET_LOG_DEBUG("UpdateManagedList: " + ManagedState::TypeToString(type),
    434                 base::StringPrintf("%" PRIuS, entries.GetSize()));
    435   // Create a map of existing entries. Assumes all entries in |managed_list|
    436   // are unique.
    437   typedef std::map<std::string, ManagedState*> ManagedMap;
    438   ManagedMap managed_map;
    439   for (ManagedStateList::iterator iter = managed_list->begin();
    440        iter != managed_list->end(); ++iter) {
    441     ManagedState* managed = *iter;
    442     DCHECK(!ContainsKey(managed_map, managed->path()));
    443     managed_map[managed->path()] = managed;
    444   }
    445   // Clear the list (pointers are temporarily owned by managed_map).
    446   managed_list->clear();
    447   // Updates managed_list and request updates for new entries.
    448   std::set<std::string> list_entries;
    449   for (base::ListValue::const_iterator iter = entries.begin();
    450        iter != entries.end(); ++iter) {
    451     std::string path;
    452     (*iter)->GetAsString(&path);
    453     if (path.empty() || path == shill::kFlimflamServicePath) {
    454       NET_LOG_ERROR(base::StringPrintf("Bad path in list:%d", type), path);
    455       continue;
    456     }
    457     ManagedMap::iterator found = managed_map.find(path);
    458     if (found == managed_map.end()) {
    459       if (list_entries.count(path) != 0) {
    460         NET_LOG_ERROR("Duplicate entry in list", path);
    461         continue;
    462       }
    463       ManagedState* managed = ManagedState::Create(type, path);
    464       managed_list->push_back(managed);
    465     } else {
    466       managed_list->push_back(found->second);
    467       managed_map.erase(found);
    468     }
    469     list_entries.insert(path);
    470   }
    471   // Delete any remaining entries in managed_map.
    472   STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
    473 }
    474 
    475 void NetworkStateHandler::ProfileListChanged() {
    476   NET_LOG_EVENT("ProfileListChanged", "Re-Requesting Network Properties");
    477   for (ManagedStateList::iterator iter = network_list_.begin();
    478        iter != network_list_.end(); ++iter) {
    479     NetworkState* network = (*iter)->AsNetworkState();
    480     DCHECK(network);
    481     shill_property_handler_->RequestProperties(
    482         ManagedState::MANAGED_TYPE_NETWORK, network->path());
    483   }
    484 }
    485 
    486 void NetworkStateHandler::UpdateManagedStateProperties(
    487     ManagedState::ManagedType type,
    488     const std::string& path,
    489     const base::DictionaryValue& properties) {
    490   ManagedStateList* managed_list = GetManagedList(type);
    491   ManagedState* managed = GetModifiableManagedState(managed_list, path);
    492   if (!managed) {
    493     // The network has been removed from the list of networks.
    494     NET_LOG_DEBUG("UpdateManagedStateProperties: Not found", path);
    495     return;
    496   }
    497   managed->set_update_received();
    498 
    499   std::string desc = GetManagedStateLogType(managed) + " Properties Received";
    500   NET_LOG_DEBUG(desc, GetLogName(managed));
    501 
    502   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
    503     UpdateNetworkStateProperties(managed->AsNetworkState(), properties);
    504   } else {
    505     // Device
    506     for (base::DictionaryValue::Iterator iter(properties);
    507          !iter.IsAtEnd(); iter.Advance()) {
    508       managed->PropertyChanged(iter.key(), iter.value());
    509     }
    510     managed->InitialPropertiesReceived(properties);
    511   }
    512   managed->set_update_requested(false);
    513 }
    514 
    515 void NetworkStateHandler::UpdateNetworkStateProperties(
    516     NetworkState* network,
    517     const base::DictionaryValue& properties) {
    518   DCHECK(network);
    519   bool network_property_updated = false;
    520   std::string prev_connection_state = network->connection_state();
    521   for (base::DictionaryValue::Iterator iter(properties);
    522        !iter.IsAtEnd(); iter.Advance()) {
    523     if (network->PropertyChanged(iter.key(), iter.value()))
    524       network_property_updated = true;
    525   }
    526   network_property_updated |= network->InitialPropertiesReceived(properties);
    527   UpdateGuid(network);
    528   network_list_sorted_ = false;
    529 
    530   // Notify observers of NetworkState changes.
    531   if (network_property_updated || network->update_requested()) {
    532     // Signal connection state changed after all properties have been updated.
    533     if (ConnectionStateChanged(network, prev_connection_state))
    534       OnNetworkConnectionStateChanged(network);
    535     NET_LOG_EVENT("NetworkPropertiesUpdated", GetLogName(network));
    536     NotifyNetworkPropertiesUpdated(network);
    537   }
    538 }
    539 
    540 void NetworkStateHandler::UpdateNetworkServiceProperty(
    541     const std::string& service_path,
    542     const std::string& key,
    543     const base::Value& value) {
    544   bool changed = false;
    545   NetworkState* network = GetModifiableNetworkState(service_path);
    546   if (!network)
    547     return;
    548   std::string prev_connection_state = network->connection_state();
    549   std::string prev_profile_path = network->profile_path();
    550   changed |= network->PropertyChanged(key, value);
    551   if (!changed)
    552     return;
    553 
    554   if (key == shill::kStateProperty || key == shill::kVisibleProperty) {
    555     network_list_sorted_ = false;
    556     if (ConnectionStateChanged(network, prev_connection_state)) {
    557       OnNetworkConnectionStateChanged(network);
    558       // If the connection state changes, other properties such as IPConfig
    559       // may have changed, so request a full update.
    560       RequestUpdateForNetwork(service_path);
    561     }
    562   } else {
    563     std::string value_str;
    564     value.GetAsString(&value_str);
    565     // Some property changes are noisy and not interesting:
    566     // * Wifi SignalStrength
    567     // * WifiFrequencyList updates
    568     // * Device property changes to "/" (occurs before a service is removed)
    569     if (key != shill::kSignalStrengthProperty &&
    570         key != shill::kWifiFrequencyListProperty &&
    571         (key != shill::kDeviceProperty || value_str != "/")) {
    572       std::string log_event = "NetworkPropertyUpdated";
    573       // Trigger a default network update for interesting changes only.
    574       if (network->path() == default_network_path_) {
    575         NotifyDefaultNetworkChanged(network);
    576         log_event = "Default" + log_event;
    577       }
    578       // Log event.
    579       std::string detail = network->name() + "." + key;
    580       detail += " = " + network_event_log::ValueAsString(value);
    581       network_event_log::LogLevel log_level;
    582       if (key == shill::kErrorProperty || key == shill::kErrorDetailsProperty) {
    583         log_level = network_event_log::LOG_LEVEL_ERROR;
    584       } else {
    585         log_level = network_event_log::LOG_LEVEL_EVENT;
    586       }
    587       NET_LOG_LEVEL(log_level, log_event, detail);
    588     }
    589   }
    590 
    591   // All property updates signal 'NetworkPropertiesUpdated'.
    592   NotifyNetworkPropertiesUpdated(network);
    593 
    594   // If added to a Profile, request a full update so that a NetworkState
    595   // gets created.
    596   if (prev_profile_path.empty() && !network->profile_path().empty())
    597     RequestUpdateForNetwork(service_path);
    598 }
    599 
    600 void NetworkStateHandler::UpdateDeviceProperty(const std::string& device_path,
    601                                                const std::string& key,
    602                                                const base::Value& value) {
    603   DeviceState* device = GetModifiableDeviceState(device_path);
    604   if (!device)
    605     return;
    606   if (!device->PropertyChanged(key, value))
    607     return;
    608 
    609   std::string detail = device->name() + "." + key;
    610   detail += " = " + network_event_log::ValueAsString(value);
    611   NET_LOG_EVENT("DevicePropertyUpdated", detail);
    612 
    613   NotifyDeviceListChanged();
    614 
    615   if (key == shill::kScanningProperty && device->scanning() == false)
    616     ScanCompleted(device->type());
    617   if (key == shill::kEapAuthenticationCompletedProperty) {
    618     // Notify a change for each Ethernet service using this device.
    619     NetworkStateList ethernet_services;
    620     GetNetworkListByType(NetworkTypePattern::Ethernet(),
    621                          false /* configured_only */,
    622                          false /* visible_only */,
    623                          0 /* no limit */,
    624                          &ethernet_services);
    625     for (NetworkStateList::const_iterator it = ethernet_services.begin();
    626          it != ethernet_services.end(); ++it) {
    627       const NetworkState* ethernet_service = *it;
    628       if (ethernet_service->update_received() ||
    629           ethernet_service->device_path() != device->path()) {
    630         continue;
    631       }
    632       RequestUpdateForNetwork(ethernet_service->path());
    633     }
    634   }
    635 }
    636 
    637 void NetworkStateHandler::UpdateIPConfigProperties(
    638     ManagedState::ManagedType type,
    639     const std::string& path,
    640     const std::string& ip_config_path,
    641     const base::DictionaryValue& properties)  {
    642   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
    643     NetworkState* network = GetModifiableNetworkState(path);
    644     if (!network)
    645       return;
    646     network->IPConfigPropertiesChanged(properties);
    647     if (network->path() == default_network_path_)
    648       NotifyDefaultNetworkChanged(network);
    649   } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
    650     DeviceState* device = GetModifiableDeviceState(path);
    651     if (!device)
    652       return;
    653     device->IPConfigPropertiesChanged(ip_config_path, properties);
    654     if (!default_network_path_.empty()) {
    655       const NetworkState* default_network =
    656           GetNetworkState(default_network_path_);
    657       if (default_network && default_network->device_path() == path)
    658         NotifyDefaultNetworkChanged(default_network);
    659     }
    660   }
    661 }
    662 
    663 void NetworkStateHandler::CheckPortalListChanged(
    664     const std::string& check_portal_list) {
    665   check_portal_list_ = check_portal_list;
    666 }
    667 
    668 void NetworkStateHandler::TechnologyListChanged() {
    669   // Eventually we would like to replace Technology state with Device state.
    670   // For now, treat technology state changes as device list changes.
    671   NotifyDeviceListChanged();
    672 }
    673 
    674 void NetworkStateHandler::ManagedStateListChanged(
    675     ManagedState::ManagedType type) {
    676   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
    677     SortNetworkList();
    678     UpdateNetworkStats();
    679     // Notify observers that the list of networks has changed.
    680     NET_LOG_EVENT("NOTIFY:NetworkListChanged",
    681                   base::StringPrintf("Size:%" PRIuS, network_list_.size()));
    682     FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    683                       NetworkListChanged());
    684   } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
    685     std::string devices;
    686     for (ManagedStateList::const_iterator iter = device_list_.begin();
    687          iter != device_list_.end(); ++iter) {
    688       if (iter != device_list_.begin())
    689         devices += ", ";
    690       devices += (*iter)->name();
    691     }
    692     NET_LOG_EVENT("DeviceList", devices);
    693     NotifyDeviceListChanged();
    694   } else {
    695     NOTREACHED();
    696   }
    697 }
    698 
    699 void NetworkStateHandler::SortNetworkList() {
    700   // Note: usually active networks will precede inactive networks, however
    701   // this may briefly be untrue during state transitions (e.g. a network may
    702   // transition to idle before the list is updated).
    703   ManagedStateList active, non_wifi_visible, wifi_visible, hidden, new_networks;
    704   for (ManagedStateList::iterator iter = network_list_.begin();
    705        iter != network_list_.end(); ++iter) {
    706     NetworkState* network = (*iter)->AsNetworkState();
    707     if (!network->update_received()) {
    708       new_networks.push_back(network);
    709       continue;
    710     }
    711     if (network->IsConnectedState() || network->IsConnectingState()) {
    712       active.push_back(network);
    713       continue;
    714     }
    715     if (network->visible()) {
    716       if (NetworkTypePattern::WiFi().MatchesType(network->type()))
    717         wifi_visible.push_back(network);
    718       else
    719         non_wifi_visible.push_back(network);
    720     } else {
    721       hidden.push_back(network);
    722     }
    723   }
    724   network_list_.clear();
    725   network_list_.insert(network_list_.end(), active.begin(), active.end());
    726   network_list_.insert(
    727       network_list_.end(), non_wifi_visible.begin(), non_wifi_visible.end());
    728   network_list_.insert(
    729       network_list_.end(), wifi_visible.begin(), wifi_visible.end());
    730   network_list_.insert(network_list_.end(), hidden.begin(), hidden.end());
    731   network_list_.insert(
    732       network_list_.end(), new_networks.begin(), new_networks.end());
    733   network_list_sorted_ = true;
    734 }
    735 
    736 void NetworkStateHandler::UpdateNetworkStats() {
    737   size_t shared = 0, unshared = 0, visible = 0;
    738   for (ManagedStateList::iterator iter = network_list_.begin();
    739        iter != network_list_.end(); ++iter) {
    740     NetworkState* network = (*iter)->AsNetworkState();
    741     if (network->visible())
    742       ++visible;
    743     if (network->IsInProfile()) {
    744       if (network->IsPrivate())
    745         ++unshared;
    746       else
    747         ++shared;
    748     }
    749   }
    750   UMA_HISTOGRAM_COUNTS_100("Networks.Visible", visible);
    751   UMA_HISTOGRAM_COUNTS_100("Networks.RememberedShared", shared);
    752   UMA_HISTOGRAM_COUNTS_100("Networks.RememberedUnshared", unshared);
    753 }
    754 
    755 void NetworkStateHandler::DefaultNetworkServiceChanged(
    756     const std::string& service_path) {
    757   // Shill uses '/' for empty service path values; check explicitly for that.
    758   const char* kEmptyServicePath = "/";
    759   std::string new_service_path =
    760       (service_path != kEmptyServicePath) ? service_path : "";
    761   if (new_service_path == default_network_path_)
    762     return;
    763 
    764   default_network_path_ = service_path;
    765   NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_);
    766   const NetworkState* network = NULL;
    767   if (!default_network_path_.empty()) {
    768     network = GetNetworkState(default_network_path_);
    769     if (!network) {
    770       // If NetworkState is not available yet, do not notify observers here,
    771       // they will be notified when the state is received.
    772       NET_LOG_DEBUG("Default NetworkState not available",
    773                     default_network_path_);
    774       return;
    775     }
    776   }
    777   if (network && !network->IsConnectedState()) {
    778     NET_LOG_ERROR(
    779         "DefaultNetwork is not connected: " + network->connection_state(),
    780         network->path());
    781   }
    782   NotifyDefaultNetworkChanged(network);
    783 }
    784 
    785 //------------------------------------------------------------------------------
    786 // Private methods
    787 
    788 void NetworkStateHandler::UpdateGuid(NetworkState* network) {
    789   std::string specifier = network->GetSpecifier();
    790   DCHECK(!specifier.empty());
    791   if (!network->guid().empty()) {
    792     // If the network is saved in a profile, remove the entry from the map.
    793     // Otherwise ensure that the entry matches the specified GUID. (e.g. in
    794     // case a visible network with a specified guid gets configured with a
    795     // new guid).
    796     if (network->IsInProfile())
    797       specifier_guid_map_.erase(specifier);
    798     else
    799       specifier_guid_map_[specifier] = network->guid();
    800     return;
    801   }
    802   // Ensure that the NetworkState has a valid GUID.
    803   std::string guid;
    804   SpecifierGuidMap::iterator iter = specifier_guid_map_.find(specifier);
    805   if (iter != specifier_guid_map_.end()) {
    806     guid = iter->second;
    807   } else {
    808     guid = base::GenerateGUID();
    809     specifier_guid_map_[specifier] = guid;
    810   }
    811   network->SetGuid(guid);
    812 }
    813 
    814 void NetworkStateHandler::NotifyDeviceListChanged() {
    815   NET_LOG_DEBUG("NOTIFY:DeviceListChanged",
    816                 base::StringPrintf("Size:%" PRIuS, device_list_.size()));
    817   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    818                     DeviceListChanged());
    819 }
    820 
    821 DeviceState* NetworkStateHandler::GetModifiableDeviceState(
    822     const std::string& device_path) const {
    823   ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
    824   if (!managed)
    825     return NULL;
    826   return managed->AsDeviceState();
    827 }
    828 
    829 NetworkState* NetworkStateHandler::GetModifiableNetworkState(
    830     const std::string& service_path) const {
    831   ManagedState* managed =
    832       GetModifiableManagedState(&network_list_, service_path);
    833   if (!managed)
    834     return NULL;
    835   return managed->AsNetworkState();
    836 }
    837 
    838 ManagedState* NetworkStateHandler::GetModifiableManagedState(
    839     const ManagedStateList* managed_list,
    840     const std::string& path) const {
    841   for (ManagedStateList::const_iterator iter = managed_list->begin();
    842        iter != managed_list->end(); ++iter) {
    843     ManagedState* managed = *iter;
    844     if (managed->path() == path)
    845       return managed;
    846   }
    847   return NULL;
    848 }
    849 
    850 NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
    851     ManagedState::ManagedType type) {
    852   switch (type) {
    853     case ManagedState::MANAGED_TYPE_NETWORK:
    854       return &network_list_;
    855     case ManagedState::MANAGED_TYPE_DEVICE:
    856       return &device_list_;
    857   }
    858   NOTREACHED();
    859   return NULL;
    860 }
    861 
    862 void NetworkStateHandler::OnNetworkConnectionStateChanged(
    863     NetworkState* network) {
    864   DCHECK(network);
    865   std::string event = "NetworkConnectionStateChanged";
    866   if (network->path() == default_network_path_) {
    867     event = "Default" + event;
    868     if (!network->IsConnectedState()) {
    869       NET_LOG_EVENT(
    870           "DefaultNetwork is not connected: " + network->connection_state(),
    871           network->path());
    872       default_network_path_.clear();
    873       SortNetworkList();
    874       NotifyDefaultNetworkChanged(NULL);
    875     }
    876   }
    877   NET_LOG_EVENT("NOTIFY:" + event + ": " + network->connection_state(),
    878                 GetLogName(network));
    879   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    880                     NetworkConnectionStateChanged(network));
    881   if (network->path() == default_network_path_)
    882     NotifyDefaultNetworkChanged(network);
    883 }
    884 
    885 void NetworkStateHandler::NotifyDefaultNetworkChanged(
    886     const NetworkState* default_network) {
    887   NET_LOG_EVENT("NOTIFY:DefaultNetworkChanged", GetLogName(default_network));
    888   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    889                     DefaultNetworkChanged(default_network));
    890 }
    891 
    892 void NetworkStateHandler::NotifyNetworkPropertiesUpdated(
    893     const NetworkState* network) {
    894   NET_LOG_DEBUG("NOTIFY:NetworkPropertiesUpdated", GetLogName(network));
    895   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    896                     NetworkPropertiesUpdated(network));
    897 }
    898 
    899 void NetworkStateHandler::ScanCompleted(const std::string& type) {
    900   size_t num_callbacks = scan_complete_callbacks_.count(type);
    901   NET_LOG_EVENT("ScanCompleted",
    902                 base::StringPrintf("%s:%" PRIuS, type.c_str(), num_callbacks));
    903   if (num_callbacks == 0)
    904     return;
    905   ScanCallbackList& callback_list = scan_complete_callbacks_[type];
    906   for (ScanCallbackList::iterator iter = callback_list.begin();
    907        iter != callback_list.end(); ++iter) {
    908     (*iter).Run();
    909   }
    910   scan_complete_callbacks_.erase(type);
    911 }
    912 
    913 std::string NetworkStateHandler::GetTechnologyForType(
    914     const NetworkTypePattern& type) const {
    915   if (type.MatchesType(shill::kTypeEthernet))
    916     return shill::kTypeEthernet;
    917 
    918   if (type.MatchesType(shill::kTypeWifi))
    919     return shill::kTypeWifi;
    920 
    921   if (type.Equals(NetworkTypePattern::Wimax()))
    922     return shill::kTypeWimax;
    923 
    924   // Prefer Wimax over Cellular only if it's available.
    925   if (type.MatchesType(shill::kTypeWimax) &&
    926       shill_property_handler_->IsTechnologyAvailable(shill::kTypeWimax)) {
    927     return shill::kTypeWimax;
    928   }
    929 
    930   if (type.MatchesType(shill::kTypeCellular))
    931     return shill::kTypeCellular;
    932 
    933   NOTREACHED();
    934   return std::string();
    935 }
    936 
    937 ScopedVector<std::string> NetworkStateHandler::GetTechnologiesForType(
    938     const NetworkTypePattern& type) const {
    939   ScopedVector<std::string> technologies;
    940   if (type.MatchesType(shill::kTypeEthernet))
    941     technologies.push_back(new std::string(shill::kTypeEthernet));
    942   if (type.MatchesType(shill::kTypeWifi))
    943     technologies.push_back(new std::string(shill::kTypeWifi));
    944   if (type.MatchesType(shill::kTypeWimax))
    945     technologies.push_back(new std::string(shill::kTypeWimax));
    946   if (type.MatchesType(shill::kTypeCellular))
    947     technologies.push_back(new std::string(shill::kTypeCellular));
    948   if (type.MatchesType(shill::kTypeBluetooth))
    949     technologies.push_back(new std::string(shill::kTypeBluetooth));
    950   if (type.MatchesType(shill::kTypeVPN))
    951     technologies.push_back(new std::string(shill::kTypeVPN));
    952 
    953   CHECK_GT(technologies.size(), 0ul);
    954   return technologies.Pass();
    955 }
    956 
    957 }  // namespace chromeos
    958