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   NotifyDevicePropertiesUpdated(device);
    615 
    616   if (key == shill::kScanningProperty && device->scanning() == false)
    617     ScanCompleted(device->type());
    618   if (key == shill::kEapAuthenticationCompletedProperty) {
    619     // Notify a change for each Ethernet service using this device.
    620     NetworkStateList ethernet_services;
    621     GetNetworkListByType(NetworkTypePattern::Ethernet(),
    622                          false /* configured_only */,
    623                          false /* visible_only */,
    624                          0 /* no limit */,
    625                          &ethernet_services);
    626     for (NetworkStateList::const_iterator it = ethernet_services.begin();
    627          it != ethernet_services.end(); ++it) {
    628       const NetworkState* ethernet_service = *it;
    629       if (ethernet_service->update_received() ||
    630           ethernet_service->device_path() != device->path()) {
    631         continue;
    632       }
    633       RequestUpdateForNetwork(ethernet_service->path());
    634     }
    635   }
    636 }
    637 
    638 void NetworkStateHandler::UpdateIPConfigProperties(
    639     ManagedState::ManagedType type,
    640     const std::string& path,
    641     const std::string& ip_config_path,
    642     const base::DictionaryValue& properties)  {
    643   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
    644     NetworkState* network = GetModifiableNetworkState(path);
    645     if (!network)
    646       return;
    647     network->IPConfigPropertiesChanged(properties);
    648     NotifyNetworkPropertiesUpdated(network);
    649     if (network->path() == default_network_path_)
    650       NotifyDefaultNetworkChanged(network);
    651   } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
    652     DeviceState* device = GetModifiableDeviceState(path);
    653     if (!device)
    654       return;
    655     device->IPConfigPropertiesChanged(ip_config_path, properties);
    656     NotifyDevicePropertiesUpdated(device);
    657     if (!default_network_path_.empty()) {
    658       const NetworkState* default_network =
    659           GetNetworkState(default_network_path_);
    660       if (default_network && default_network->device_path() == path)
    661         NotifyDefaultNetworkChanged(default_network);
    662     }
    663   }
    664 }
    665 
    666 void NetworkStateHandler::CheckPortalListChanged(
    667     const std::string& check_portal_list) {
    668   check_portal_list_ = check_portal_list;
    669 }
    670 
    671 void NetworkStateHandler::TechnologyListChanged() {
    672   // Eventually we would like to replace Technology state with Device state.
    673   // For now, treat technology state changes as device list changes.
    674   NotifyDeviceListChanged();
    675 }
    676 
    677 void NetworkStateHandler::ManagedStateListChanged(
    678     ManagedState::ManagedType type) {
    679   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
    680     SortNetworkList();
    681     UpdateNetworkStats();
    682     // Notify observers that the list of networks has changed.
    683     NET_LOG_EVENT("NOTIFY:NetworkListChanged",
    684                   base::StringPrintf("Size:%" PRIuS, network_list_.size()));
    685     FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    686                       NetworkListChanged());
    687   } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
    688     std::string devices;
    689     for (ManagedStateList::const_iterator iter = device_list_.begin();
    690          iter != device_list_.end(); ++iter) {
    691       if (iter != device_list_.begin())
    692         devices += ", ";
    693       devices += (*iter)->name();
    694     }
    695     NET_LOG_EVENT("DeviceList", devices);
    696     NotifyDeviceListChanged();
    697   } else {
    698     NOTREACHED();
    699   }
    700 }
    701 
    702 void NetworkStateHandler::SortNetworkList() {
    703   // Note: usually active networks will precede inactive networks, however
    704   // this may briefly be untrue during state transitions (e.g. a network may
    705   // transition to idle before the list is updated).
    706   ManagedStateList active, non_wifi_visible, wifi_visible, hidden, new_networks;
    707   for (ManagedStateList::iterator iter = network_list_.begin();
    708        iter != network_list_.end(); ++iter) {
    709     NetworkState* network = (*iter)->AsNetworkState();
    710     if (!network->update_received()) {
    711       new_networks.push_back(network);
    712       continue;
    713     }
    714     if (network->IsConnectedState() || network->IsConnectingState()) {
    715       active.push_back(network);
    716       continue;
    717     }
    718     if (network->visible()) {
    719       if (NetworkTypePattern::WiFi().MatchesType(network->type()))
    720         wifi_visible.push_back(network);
    721       else
    722         non_wifi_visible.push_back(network);
    723     } else {
    724       hidden.push_back(network);
    725     }
    726   }
    727   network_list_.clear();
    728   network_list_.insert(network_list_.end(), active.begin(), active.end());
    729   network_list_.insert(
    730       network_list_.end(), non_wifi_visible.begin(), non_wifi_visible.end());
    731   network_list_.insert(
    732       network_list_.end(), wifi_visible.begin(), wifi_visible.end());
    733   network_list_.insert(network_list_.end(), hidden.begin(), hidden.end());
    734   network_list_.insert(
    735       network_list_.end(), new_networks.begin(), new_networks.end());
    736   network_list_sorted_ = true;
    737 }
    738 
    739 void NetworkStateHandler::UpdateNetworkStats() {
    740   size_t shared = 0, unshared = 0, visible = 0;
    741   for (ManagedStateList::iterator iter = network_list_.begin();
    742        iter != network_list_.end(); ++iter) {
    743     NetworkState* network = (*iter)->AsNetworkState();
    744     if (network->visible())
    745       ++visible;
    746     if (network->IsInProfile()) {
    747       if (network->IsPrivate())
    748         ++unshared;
    749       else
    750         ++shared;
    751     }
    752   }
    753   UMA_HISTOGRAM_COUNTS_100("Networks.Visible", visible);
    754   UMA_HISTOGRAM_COUNTS_100("Networks.RememberedShared", shared);
    755   UMA_HISTOGRAM_COUNTS_100("Networks.RememberedUnshared", unshared);
    756 }
    757 
    758 void NetworkStateHandler::DefaultNetworkServiceChanged(
    759     const std::string& service_path) {
    760   // Shill uses '/' for empty service path values; check explicitly for that.
    761   const char* kEmptyServicePath = "/";
    762   std::string new_service_path =
    763       (service_path != kEmptyServicePath) ? service_path : "";
    764   if (new_service_path == default_network_path_)
    765     return;
    766 
    767   default_network_path_ = service_path;
    768   NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_);
    769   const NetworkState* network = NULL;
    770   if (!default_network_path_.empty()) {
    771     network = GetNetworkState(default_network_path_);
    772     if (!network) {
    773       // If NetworkState is not available yet, do not notify observers here,
    774       // they will be notified when the state is received.
    775       NET_LOG_DEBUG("Default NetworkState not available",
    776                     default_network_path_);
    777       return;
    778     }
    779   }
    780   if (network && !network->IsConnectedState()) {
    781     NET_LOG_ERROR(
    782         "DefaultNetwork is not connected: " + network->connection_state(),
    783         network->path());
    784   }
    785   NotifyDefaultNetworkChanged(network);
    786 }
    787 
    788 //------------------------------------------------------------------------------
    789 // Private methods
    790 
    791 void NetworkStateHandler::UpdateGuid(NetworkState* network) {
    792   std::string specifier = network->GetSpecifier();
    793   DCHECK(!specifier.empty());
    794   if (!network->guid().empty()) {
    795     // If the network is saved in a profile, remove the entry from the map.
    796     // Otherwise ensure that the entry matches the specified GUID. (e.g. in
    797     // case a visible network with a specified guid gets configured with a
    798     // new guid).
    799     if (network->IsInProfile())
    800       specifier_guid_map_.erase(specifier);
    801     else
    802       specifier_guid_map_[specifier] = network->guid();
    803     return;
    804   }
    805   // Ensure that the NetworkState has a valid GUID.
    806   std::string guid;
    807   SpecifierGuidMap::iterator iter = specifier_guid_map_.find(specifier);
    808   if (iter != specifier_guid_map_.end()) {
    809     guid = iter->second;
    810   } else {
    811     guid = base::GenerateGUID();
    812     specifier_guid_map_[specifier] = guid;
    813   }
    814   network->SetGuid(guid);
    815 }
    816 
    817 void NetworkStateHandler::NotifyDeviceListChanged() {
    818   NET_LOG_DEBUG("NOTIFY:DeviceListChanged",
    819                 base::StringPrintf("Size:%" PRIuS, device_list_.size()));
    820   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    821                     DeviceListChanged());
    822 }
    823 
    824 DeviceState* NetworkStateHandler::GetModifiableDeviceState(
    825     const std::string& device_path) const {
    826   ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
    827   if (!managed)
    828     return NULL;
    829   return managed->AsDeviceState();
    830 }
    831 
    832 NetworkState* NetworkStateHandler::GetModifiableNetworkState(
    833     const std::string& service_path) const {
    834   ManagedState* managed =
    835       GetModifiableManagedState(&network_list_, service_path);
    836   if (!managed)
    837     return NULL;
    838   return managed->AsNetworkState();
    839 }
    840 
    841 ManagedState* NetworkStateHandler::GetModifiableManagedState(
    842     const ManagedStateList* managed_list,
    843     const std::string& path) const {
    844   for (ManagedStateList::const_iterator iter = managed_list->begin();
    845        iter != managed_list->end(); ++iter) {
    846     ManagedState* managed = *iter;
    847     if (managed->path() == path)
    848       return managed;
    849   }
    850   return NULL;
    851 }
    852 
    853 NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
    854     ManagedState::ManagedType type) {
    855   switch (type) {
    856     case ManagedState::MANAGED_TYPE_NETWORK:
    857       return &network_list_;
    858     case ManagedState::MANAGED_TYPE_DEVICE:
    859       return &device_list_;
    860   }
    861   NOTREACHED();
    862   return NULL;
    863 }
    864 
    865 void NetworkStateHandler::OnNetworkConnectionStateChanged(
    866     NetworkState* network) {
    867   DCHECK(network);
    868   std::string event = "NetworkConnectionStateChanged";
    869   if (network->path() == default_network_path_) {
    870     event = "Default" + event;
    871     if (!network->IsConnectedState()) {
    872       NET_LOG_EVENT(
    873           "DefaultNetwork is not connected: " + network->connection_state(),
    874           network->path());
    875       default_network_path_.clear();
    876       SortNetworkList();
    877       NotifyDefaultNetworkChanged(NULL);
    878     }
    879   }
    880   NET_LOG_EVENT("NOTIFY:" + event + ": " + network->connection_state(),
    881                 GetLogName(network));
    882   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    883                     NetworkConnectionStateChanged(network));
    884   if (network->path() == default_network_path_)
    885     NotifyDefaultNetworkChanged(network);
    886 }
    887 
    888 void NetworkStateHandler::NotifyDefaultNetworkChanged(
    889     const NetworkState* default_network) {
    890   NET_LOG_EVENT("NOTIFY:DefaultNetworkChanged", GetLogName(default_network));
    891   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    892                     DefaultNetworkChanged(default_network));
    893 }
    894 
    895 void NetworkStateHandler::NotifyNetworkPropertiesUpdated(
    896     const NetworkState* network) {
    897   NET_LOG_DEBUG("NOTIFY:NetworkPropertiesUpdated", GetLogName(network));
    898   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    899                     NetworkPropertiesUpdated(network));
    900 }
    901 
    902 void NetworkStateHandler::NotifyDevicePropertiesUpdated(
    903     const DeviceState* device) {
    904   NET_LOG_DEBUG("NOTIFY:DevicePropertiesUpdated", GetLogName(device));
    905   FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
    906                     DevicePropertiesUpdated(device));
    907 }
    908 
    909 void NetworkStateHandler::ScanCompleted(const std::string& type) {
    910   size_t num_callbacks = scan_complete_callbacks_.count(type);
    911   NET_LOG_EVENT("ScanCompleted",
    912                 base::StringPrintf("%s:%" PRIuS, type.c_str(), num_callbacks));
    913   if (num_callbacks == 0)
    914     return;
    915   ScanCallbackList& callback_list = scan_complete_callbacks_[type];
    916   for (ScanCallbackList::iterator iter = callback_list.begin();
    917        iter != callback_list.end(); ++iter) {
    918     (*iter).Run();
    919   }
    920   scan_complete_callbacks_.erase(type);
    921 }
    922 
    923 std::string NetworkStateHandler::GetTechnologyForType(
    924     const NetworkTypePattern& type) const {
    925   if (type.MatchesType(shill::kTypeEthernet))
    926     return shill::kTypeEthernet;
    927 
    928   if (type.MatchesType(shill::kTypeWifi))
    929     return shill::kTypeWifi;
    930 
    931   if (type.Equals(NetworkTypePattern::Wimax()))
    932     return shill::kTypeWimax;
    933 
    934   // Prefer Wimax over Cellular only if it's available.
    935   if (type.MatchesType(shill::kTypeWimax) &&
    936       shill_property_handler_->IsTechnologyAvailable(shill::kTypeWimax)) {
    937     return shill::kTypeWimax;
    938   }
    939 
    940   if (type.MatchesType(shill::kTypeCellular))
    941     return shill::kTypeCellular;
    942 
    943   NOTREACHED();
    944   return std::string();
    945 }
    946 
    947 ScopedVector<std::string> NetworkStateHandler::GetTechnologiesForType(
    948     const NetworkTypePattern& type) const {
    949   ScopedVector<std::string> technologies;
    950   if (type.MatchesType(shill::kTypeEthernet))
    951     technologies.push_back(new std::string(shill::kTypeEthernet));
    952   if (type.MatchesType(shill::kTypeWifi))
    953     technologies.push_back(new std::string(shill::kTypeWifi));
    954   if (type.MatchesType(shill::kTypeWimax))
    955     technologies.push_back(new std::string(shill::kTypeWimax));
    956   if (type.MatchesType(shill::kTypeCellular))
    957     technologies.push_back(new std::string(shill::kTypeCellular));
    958   if (type.MatchesType(shill::kTypeBluetooth))
    959     technologies.push_back(new std::string(shill::kTypeBluetooth));
    960   if (type.MatchesType(shill::kTypeVPN))
    961     technologies.push_back(new std::string(shill::kTypeVPN));
    962 
    963   CHECK_GT(technologies.size(), 0ul);
    964   return technologies.Pass();
    965 }
    966 
    967 }  // namespace chromeos
    968