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