network_state_handler.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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->is_favorite() &&
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->is_favorite())
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::RequestUpdateForAllNetworks() {
357  NET_LOG_EVENT("RequestUpdateForAllNetworks", "");
358  for (ManagedStateList::iterator iter = network_list_.begin();
359       iter != network_list_.end(); ++iter) {
360    ManagedState* network = *iter;
361    network->set_update_requested(true);
362    shill_property_handler_->RequestProperties(
363        ManagedState::MANAGED_TYPE_NETWORK, network->path());
364  }
365}
366
367void NetworkStateHandler::ClearLastErrorForNetwork(
368    const std::string& service_path) {
369  NetworkState* network = GetModifiableNetworkState(service_path);
370  if (network)
371    network->clear_last_error();
372}
373
374void NetworkStateHandler::SetCheckPortalList(
375    const std::string& check_portal_list) {
376  NET_LOG_EVENT("SetCheckPortalList", check_portal_list);
377  shill_property_handler_->SetCheckPortalList(check_portal_list);
378}
379
380const FavoriteState* NetworkStateHandler::GetEAPForEthernet(
381    const std::string& service_path) const {
382  const NetworkState* network = GetNetworkState(service_path);
383  if (!network) {
384    NET_LOG_ERROR("GetEAPForEthernet", "Unknown service path " + service_path);
385    return NULL;
386  }
387  if (network->type() != shill::kTypeEthernet) {
388    NET_LOG_ERROR("GetEAPForEthernet", "Not of type Ethernet: " + service_path);
389    return NULL;
390  }
391  if (!network->IsConnectedState())
392    return NULL;
393
394  // The same EAP service is shared for all ethernet services/devices.
395  // However EAP is used/enabled per device and only if the connection was
396  // successfully established.
397  const DeviceState* device = GetDeviceState(network->device_path());
398  if (!device) {
399    NET_LOG_ERROR(
400        "GetEAPForEthernet",
401        base::StringPrintf("Unknown device %s of connected ethernet service %s",
402                           network->device_path().c_str(),
403                           service_path.c_str()));
404    return NULL;
405  }
406  if (!device->eap_authentication_completed())
407    return NULL;
408
409  FavoriteStateList list;
410  GetFavoriteListByType(NetworkTypePattern::Primitive(shill::kTypeEthernetEap),
411                        &list);
412  if (list.empty()) {
413    NET_LOG_ERROR("GetEAPForEthernet",
414                  base::StringPrintf(
415                      "Ethernet service %s connected using EAP, but no "
416                      "EAP service found.",
417                      service_path.c_str()));
418    return NULL;
419  }
420  DCHECK(list.size() == 1);
421  return list.front();
422}
423
424void NetworkStateHandler::GetNetworkStatePropertiesForTest(
425    base::DictionaryValue* dictionary) const {
426  for (ManagedStateList::const_iterator iter = network_list_.begin();
427       iter != network_list_.end(); ++iter) {
428    base::DictionaryValue* network_dict = new base::DictionaryValue;
429    (*iter)->AsNetworkState()->GetProperties(network_dict);
430    dictionary->SetWithoutPathExpansion((*iter)->path(), network_dict);
431  }
432}
433
434//------------------------------------------------------------------------------
435// ShillPropertyHandler::Delegate overrides
436
437void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
438                                            const base::ListValue& entries) {
439  ManagedStateList* managed_list = GetManagedList(type);
440  NET_LOG_DEBUG(base::StringPrintf("UpdateManagedList:%d", type),
441                base::StringPrintf("%" PRIuS, entries.GetSize()));
442  // Create a map of existing entries. Assumes all entries in |managed_list|
443  // are unique.
444  std::map<std::string, ManagedState*> managed_map;
445  for (ManagedStateList::iterator iter = managed_list->begin();
446       iter != managed_list->end(); ++iter) {
447    ManagedState* managed = *iter;
448    DCHECK(!ContainsKey(managed_map, managed->path()));
449    managed_map[managed->path()] = managed;
450  }
451  // Clear the list (pointers are temporarily owned by managed_map).
452  managed_list->clear();
453  // Updates managed_list and request updates for new entries.
454  std::set<std::string> list_entries;
455  for (base::ListValue::const_iterator iter = entries.begin();
456       iter != entries.end(); ++iter) {
457    std::string path;
458    (*iter)->GetAsString(&path);
459    if (path.empty() || path == shill::kFlimflamServicePath) {
460      NET_LOG_ERROR(base::StringPrintf("Bad path in list:%d", type), path);
461      continue;
462    }
463    std::map<std::string, ManagedState*>::iterator found =
464        managed_map.find(path);
465    ManagedState* managed;
466    if (found == managed_map.end()) {
467      if (list_entries.count(path) != 0) {
468        NET_LOG_ERROR("Duplicate entry in list", path);
469        continue;
470      }
471      managed = ManagedState::Create(type, path);
472      managed_list->push_back(managed);
473    } else {
474      managed = found->second;
475      managed_list->push_back(managed);
476      managed_map.erase(found);
477    }
478    list_entries.insert(path);
479  }
480  // Delete any remaining entries in managed_map.
481  STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
482}
483
484void NetworkStateHandler::ProfileListChanged() {
485  NET_LOG_EVENT("ProfileListChanged", "Re-Requesting Network Properties");
486  for (ManagedStateList::iterator iter = network_list_.begin();
487       iter != network_list_.end(); ++iter) {
488    shill_property_handler_->RequestProperties(
489        ManagedState::MANAGED_TYPE_NETWORK, (*iter)->path());
490  }
491}
492
493void NetworkStateHandler::UpdateManagedStateProperties(
494    ManagedState::ManagedType type,
495    const std::string& path,
496    const base::DictionaryValue& properties) {
497  ManagedStateList* managed_list = GetManagedList(type);
498  ManagedState* managed = GetModifiableManagedState(managed_list, path);
499  if (!managed) {
500    if (type != ManagedState::MANAGED_TYPE_FAVORITE) {
501      // The network has been removed from the list of visible networks.
502      NET_LOG_DEBUG("UpdateManagedStateProperties: Not found", path);
503      return;
504    }
505    // A Favorite may not have been created yet if it was added later (e.g.
506    // through ConfigureService) since ServiceCompleteList updates are not
507    // emitted. Add and update the state here.
508    managed = new FavoriteState(path);
509    managed_list->push_back(managed);
510  }
511  managed->set_update_received();
512
513  std::string desc = GetManagedStateLogType(managed) + " PropertiesReceived";
514  NET_LOG_DEBUG(desc, GetManagedStateLogName(managed));
515
516  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
517    UpdateNetworkStateProperties(managed->AsNetworkState(), properties);
518  } else {
519    // Device, Favorite
520    for (base::DictionaryValue::Iterator iter(properties);
521         !iter.IsAtEnd(); iter.Advance()) {
522      managed->PropertyChanged(iter.key(), iter.value());
523    }
524    managed->InitialPropertiesReceived(properties);
525  }
526  managed->set_update_requested(false);
527}
528
529void NetworkStateHandler::UpdateNetworkStateProperties(
530    NetworkState* network,
531    const base::DictionaryValue& properties) {
532  DCHECK(network);
533  bool network_property_updated = false;
534  std::string prev_connection_state = network->connection_state();
535  for (base::DictionaryValue::Iterator iter(properties);
536       !iter.IsAtEnd(); iter.Advance()) {
537    if (network->PropertyChanged(iter.key(), iter.value()))
538      network_property_updated = true;
539  }
540  network_property_updated |= network->InitialPropertiesReceived(properties);
541  // Notify observers of NetworkState changes.
542  if (network_property_updated || network->update_requested()) {
543    // Signal connection state changed after all properties have been updated.
544    if (ConnectionStateChanged(network, prev_connection_state))
545      OnNetworkConnectionStateChanged(network);
546    NET_LOG_EVENT("NetworkPropertiesUpdated", GetManagedStateLogName(network));
547    NotifyNetworkPropertiesUpdated(network);
548  }
549}
550
551void NetworkStateHandler::UpdateNetworkServiceProperty(
552    const std::string& service_path,
553    const std::string& key,
554    const base::Value& value) {
555  // Update any associated FavoriteState.
556  ManagedState* favorite =
557      GetModifiableManagedState(&favorite_list_, service_path);
558  bool changed = false;
559  if (favorite)
560    changed |= favorite->PropertyChanged(key, value);
561
562  // Update the NetworkState.
563  NetworkState* network = GetModifiableNetworkState(service_path);
564  if (!network)
565    return;
566  std::string prev_connection_state = network->connection_state();
567  std::string prev_profile_path = network->profile_path();
568  changed |= network->PropertyChanged(key, value);
569  if (!changed)
570    return;
571
572  if (key == shill::kStateProperty) {
573    if (ConnectionStateChanged(network, prev_connection_state)) {
574      OnNetworkConnectionStateChanged(network);
575      // If the connection state changes, other properties such as IPConfig
576      // may have changed, so request a full update.
577      RequestUpdateForNetwork(service_path);
578    }
579  } else {
580    std::string value_str;
581    value.GetAsString(&value_str);
582    // Some property changes are noisy and not interesting:
583    // * Wifi SignalStrength
584    // * WifiFrequencyList updates
585    // * Device property changes to "/" (occurs before a service is removed)
586    if (key != shill::kSignalStrengthProperty &&
587        key != shill::kWifiFrequencyListProperty &&
588        (key != shill::kDeviceProperty || value_str != "/")) {
589      std::string log_event = "NetworkPropertyUpdated";
590      // Trigger a default network update for interesting changes only.
591      if (network->path() == default_network_path_) {
592        NotifyDefaultNetworkChanged(network);
593        log_event = "Default" + log_event;
594      }
595      // Log event.
596      std::string detail = network->name() + "." + key;
597      detail += " = " + network_event_log::ValueAsString(value);
598      network_event_log::LogLevel log_level;
599      if (key == shill::kErrorProperty || key == shill::kErrorDetailsProperty) {
600        log_level = network_event_log::LOG_LEVEL_ERROR;
601      } else {
602        log_level = network_event_log::LOG_LEVEL_EVENT;
603      }
604      NET_LOG_LEVEL(log_level, log_event, detail);
605    }
606  }
607
608  // All property updates signal 'NetworkPropertiesUpdated'.
609  NotifyNetworkPropertiesUpdated(network);
610
611  // If added to a Profile, request a full update so that a FavoriteState
612  // gets created.
613  if (prev_profile_path.empty() && !network->profile_path().empty())
614    RequestUpdateForNetwork(service_path);
615}
616
617void NetworkStateHandler::UpdateDeviceProperty(const std::string& device_path,
618                                               const std::string& key,
619                                               const base::Value& value) {
620  DeviceState* device = GetModifiableDeviceState(device_path);
621  if (!device)
622    return;
623  if (!device->PropertyChanged(key, value))
624    return;
625
626  std::string detail = device->name() + "." + key;
627  detail += " = " + network_event_log::ValueAsString(value);
628  NET_LOG_EVENT("DevicePropertyUpdated", detail);
629
630  NotifyDeviceListChanged();
631
632  if (key == shill::kScanningProperty && device->scanning() == false)
633    ScanCompleted(device->type());
634  if (key == shill::kEapAuthenticationCompletedProperty) {
635    // Notify a change for each Ethernet service using this device.
636    NetworkStateList ethernet_services;
637    GetNetworkListByType(NetworkTypePattern::Ethernet(), &ethernet_services);
638    for (NetworkStateList::const_iterator it = ethernet_services.begin();
639         it != ethernet_services.end(); ++it) {
640      const NetworkState* ethernet_service = *it;
641      if (ethernet_service->update_received() ||
642          ethernet_service->device_path() != device->path()) {
643        continue;
644      }
645      RequestUpdateForNetwork(ethernet_service->path());
646    }
647  }
648}
649
650void NetworkStateHandler::CheckPortalListChanged(
651    const std::string& check_portal_list) {
652  check_portal_list_ = check_portal_list;
653}
654
655void NetworkStateHandler::TechnologyListChanged() {
656  // Eventually we would like to replace Technology state with Device state.
657  // For now, treat technology state changes as device list changes.
658  NotifyDeviceListChanged();
659}
660
661void NetworkStateHandler::ManagedStateListChanged(
662    ManagedState::ManagedType type) {
663  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
664    // Notify observers that the list of networks has changed.
665    NET_LOG_EVENT("NetworkListChanged",
666                  base::StringPrintf("Size:%" PRIuS, network_list_.size()));
667    FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
668                      NetworkListChanged());
669    // Update UMA stats.
670    UMA_HISTOGRAM_COUNTS_100("Networks.Visible", network_list_.size());
671  } else if (type == ManagedState::MANAGED_TYPE_FAVORITE) {
672    NET_LOG_DEBUG("FavoriteListChanged",
673                  base::StringPrintf("Size:%" PRIuS, favorite_list_.size()));
674    // The FavoriteState list only changes when the NetworkState list changes,
675    // so no need to signal observers here again.
676
677    // Update UMA stats.
678    size_t shared = 0, unshared = 0;
679    for (ManagedStateList::iterator iter = favorite_list_.begin();
680         iter != favorite_list_.end(); ++iter) {
681      FavoriteState* favorite = (*iter)->AsFavoriteState();
682      if (!favorite->is_favorite())
683        continue;
684      if (favorite->IsPrivate())
685        ++unshared;
686      else
687        ++shared;
688    }
689    UMA_HISTOGRAM_COUNTS_100("Networks.RememberedShared", shared);
690    UMA_HISTOGRAM_COUNTS_100("Networks.RememberedUnshared", unshared);
691  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
692    NotifyDeviceListChanged();
693  } else {
694    NOTREACHED();
695  }
696}
697
698void NetworkStateHandler::DefaultNetworkServiceChanged(
699    const std::string& service_path) {
700  // Shill uses '/' for empty service path values; check explicitly for that.
701  const char* kEmptyServicePath = "/";
702  if (service_path == kEmptyServicePath)
703    default_network_path_.clear();
704  else
705    default_network_path_ = service_path;
706  NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_);
707  const NetworkState* network = NULL;
708  if (!default_network_path_.empty()) {
709    network = GetNetworkState(default_network_path_);
710    if (!network) {
711      // If NetworkState is not available yet, do not notify observers here,
712      // they will be notified when the state is received.
713      NET_LOG_DEBUG("Default NetworkState not available",
714                    default_network_path_);
715      return;
716    }
717  }
718  if (network && !network->IsConnectedState()) {
719    NET_LOG_ERROR(
720        "DefaultNetwork is not connected: " + network->connection_state(),
721        network->path());
722  }
723  NotifyDefaultNetworkChanged(network);
724}
725
726//------------------------------------------------------------------------------
727// Private methods
728
729void NetworkStateHandler::NotifyDeviceListChanged() {
730  NET_LOG_DEBUG("NotifyDeviceListChanged",
731                base::StringPrintf("Size:%" PRIuS, device_list_.size()));
732  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
733                    DeviceListChanged());
734}
735
736DeviceState* NetworkStateHandler::GetModifiableDeviceState(
737    const std::string& device_path) const {
738  ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
739  if (!managed)
740    return NULL;
741  return managed->AsDeviceState();
742}
743
744NetworkState* NetworkStateHandler::GetModifiableNetworkState(
745    const std::string& service_path) const {
746  ManagedState* managed =
747      GetModifiableManagedState(&network_list_, service_path);
748  if (!managed)
749    return NULL;
750  return managed->AsNetworkState();
751}
752
753ManagedState* NetworkStateHandler::GetModifiableManagedState(
754    const ManagedStateList* managed_list,
755    const std::string& path) const {
756  for (ManagedStateList::const_iterator iter = managed_list->begin();
757       iter != managed_list->end(); ++iter) {
758    ManagedState* managed = *iter;
759    if (managed->path() == path)
760      return managed;
761  }
762  return NULL;
763}
764
765NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
766    ManagedState::ManagedType type) {
767  switch (type) {
768    case ManagedState::MANAGED_TYPE_NETWORK:
769      return &network_list_;
770    case ManagedState::MANAGED_TYPE_FAVORITE:
771      return &favorite_list_;
772    case ManagedState::MANAGED_TYPE_DEVICE:
773      return &device_list_;
774  }
775  NOTREACHED();
776  return NULL;
777}
778
779void NetworkStateHandler::OnNetworkConnectionStateChanged(
780    NetworkState* network) {
781  DCHECK(network);
782  std::string event = "NetworkConnectionStateChanged";
783  if (network->path() == default_network_path_) {
784    event = "Default" + event;
785    if (!network->IsConnectedState()) {
786      NET_LOG_ERROR(
787          "DefaultNetwork is not connected: " + network->connection_state(),
788          network->path());
789    }
790  }
791  NET_LOG_EVENT(event + ": " + network->connection_state(),
792                GetManagedStateLogName(network));
793  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
794                    NetworkConnectionStateChanged(network));
795  if (network->path() == default_network_path_)
796    NotifyDefaultNetworkChanged(network);
797}
798
799void NetworkStateHandler::NotifyDefaultNetworkChanged(
800    const NetworkState* default_network) {
801  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
802                    DefaultNetworkChanged(default_network));
803}
804
805void NetworkStateHandler::NotifyNetworkPropertiesUpdated(
806    const NetworkState* network) {
807  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
808                    NetworkPropertiesUpdated(network));
809}
810
811void NetworkStateHandler::ScanCompleted(const std::string& type) {
812  size_t num_callbacks = scan_complete_callbacks_.count(type);
813  NET_LOG_EVENT("ScanCompleted",
814                base::StringPrintf("%s:%" PRIuS, type.c_str(), num_callbacks));
815  if (num_callbacks == 0)
816    return;
817  ScanCallbackList& callback_list = scan_complete_callbacks_[type];
818  for (ScanCallbackList::iterator iter = callback_list.begin();
819       iter != callback_list.end(); ++iter) {
820    (*iter).Run();
821  }
822  scan_complete_callbacks_.erase(type);
823}
824
825std::string NetworkStateHandler::GetTechnologyForType(
826    const NetworkTypePattern& type) const {
827  if (type.MatchesType(shill::kTypeEthernet))
828    return shill::kTypeEthernet;
829
830  if (type.MatchesType(shill::kTypeWifi))
831    return shill::kTypeWifi;
832
833  if (type.Equals(NetworkTypePattern::Wimax()))
834    return shill::kTypeWimax;
835
836  // Prefer Wimax over Cellular only if it's available.
837  if (type.MatchesType(shill::kTypeWimax) &&
838      shill_property_handler_->IsTechnologyAvailable(shill::kTypeWimax)) {
839    return shill::kTypeWimax;
840  }
841
842  if (type.MatchesType(shill::kTypeCellular))
843    return shill::kTypeCellular;
844
845  NOTREACHED();
846  return std::string();
847}
848
849}  // namespace chromeos
850