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