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