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