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