network_state_handler.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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  ScopedVector<std::string> technologies = GetTechnologiesForType(type);
131  for (ScopedVector<std::string>::iterator it = technologies.begin();
132      it != technologies.end(); ++it) {
133    std::string* technology = *it;
134    DCHECK(technology);
135    NET_LOG_USER("SetTechnologyEnabled",
136                 base::StringPrintf("%s:%d", technology->c_str(), enabled));
137    shill_property_handler_->SetTechnologyEnabled(
138        *technology, enabled, error_callback);
139  }
140  // Signal Device/Technology state changed.
141  NotifyDeviceListChanged();
142}
143
144const DeviceState* NetworkStateHandler::GetDeviceState(
145    const std::string& device_path) const {
146  const DeviceState* device = GetModifiableDeviceState(device_path);
147  if (device && !device->update_received())
148    return NULL;
149  return device;
150}
151
152const DeviceState* NetworkStateHandler::GetDeviceStateByType(
153    const NetworkTypePattern& type) const {
154  for (ManagedStateList::const_iterator iter = device_list_.begin();
155       iter != device_list_.end(); ++iter) {
156    ManagedState* device = *iter;
157    if (!device->update_received())
158      continue;
159    if (device->Matches(type))
160      return device->AsDeviceState();
161  }
162  return NULL;
163}
164
165bool NetworkStateHandler::GetScanningByType(
166    const NetworkTypePattern& type) const {
167  for (ManagedStateList::const_iterator iter = device_list_.begin();
168       iter != device_list_.end(); ++iter) {
169    const DeviceState* device = (*iter)->AsDeviceState();
170    DCHECK(device);
171    if (!device->update_received())
172      continue;
173    if (device->Matches(type) && device->scanning())
174      return true;
175  }
176  return false;
177}
178
179const NetworkState* NetworkStateHandler::GetNetworkState(
180    const std::string& service_path) const {
181  const NetworkState* network = GetModifiableNetworkState(service_path);
182  if (network && !network->update_received())
183    return NULL;
184  return network;
185}
186
187const NetworkState* NetworkStateHandler::DefaultNetwork() const {
188  if (default_network_path_.empty())
189    return NULL;
190  return GetNetworkState(default_network_path_);
191}
192
193const FavoriteState* NetworkStateHandler::DefaultFavoriteNetwork() const {
194  const NetworkState* default_network = DefaultNetwork();
195  if (!default_network)
196    return NULL;
197  const FavoriteState* default_favorite =
198      GetFavoriteState(default_network->path());
199  DCHECK(default_network->type() != shill::kTypeWifi ||
200         default_favorite) << "No favorite for: " << default_network->path();
201  DCHECK(!default_favorite || default_favorite->update_received())
202      << "No update received for: " << default_network->path();
203  return default_favorite;
204}
205
206const NetworkState* NetworkStateHandler::ConnectedNetworkByType(
207    const NetworkTypePattern& type) const {
208  for (ManagedStateList::const_iterator iter = network_list_.begin();
209       iter != network_list_.end(); ++iter) {
210    const NetworkState* network = (*iter)->AsNetworkState();
211    DCHECK(network);
212    if (!network->update_received())
213      continue;
214    if (!network->IsConnectedState())
215      break;  // Connected networks are listed first.
216    if (network->Matches(type))
217      return network;
218  }
219  return NULL;
220}
221
222const NetworkState* NetworkStateHandler::ConnectingNetworkByType(
223    const NetworkTypePattern& type) const {
224  for (ManagedStateList::const_iterator iter = network_list_.begin();
225       iter != network_list_.end(); ++iter) {
226    const NetworkState* network = (*iter)->AsNetworkState();
227    DCHECK(network);
228    if (!network->update_received() || network->IsConnectedState())
229      continue;
230    if (!network->IsConnectingState())
231      break;  // Connected and connecting networks are listed first.
232    if (network->Matches(type))
233      return network;
234  }
235  return NULL;
236}
237
238const NetworkState* NetworkStateHandler::FirstNetworkByType(
239    const NetworkTypePattern& type) const {
240  for (ManagedStateList::const_iterator iter = network_list_.begin();
241       iter != network_list_.end(); ++iter) {
242    const NetworkState* network = (*iter)->AsNetworkState();
243    DCHECK(network);
244    if (!network->update_received())
245      continue;
246    if (network->Matches(type))
247      return network;
248  }
249  return NULL;
250}
251
252std::string NetworkStateHandler::FormattedHardwareAddressForType(
253    const NetworkTypePattern& type) const {
254  const DeviceState* device = NULL;
255  const NetworkState* network = ConnectedNetworkByType(type);
256  if (network)
257    device = GetDeviceState(network->device_path());
258  else
259    device = GetDeviceStateByType(type);
260  if (!device)
261    return std::string();
262  return device->GetFormattedMacAddress();
263}
264
265void NetworkStateHandler::GetNetworkList(NetworkStateList* list) const {
266  GetNetworkListByType(NetworkTypePattern::Default(), list);
267}
268
269void NetworkStateHandler::GetNetworkListByType(const NetworkTypePattern& type,
270                                               NetworkStateList* list) const {
271  DCHECK(list);
272  list->clear();
273  for (ManagedStateList::const_iterator iter = network_list_.begin();
274       iter != network_list_.end(); ++iter) {
275    const NetworkState* network = (*iter)->AsNetworkState();
276    DCHECK(network);
277    if (network->update_received() && network->Matches(type))
278      list->push_back(network);
279  }
280}
281
282void NetworkStateHandler::GetDeviceList(DeviceStateList* list) const {
283  GetDeviceListByType(NetworkTypePattern::Default(), list);
284}
285
286void NetworkStateHandler::GetDeviceListByType(const NetworkTypePattern& type,
287                                              DeviceStateList* list) const {
288  DCHECK(list);
289  list->clear();
290  for (ManagedStateList::const_iterator iter = device_list_.begin();
291       iter != device_list_.end(); ++iter) {
292    const DeviceState* device = (*iter)->AsDeviceState();
293    DCHECK(device);
294    if (device->update_received() && device->Matches(type))
295      list->push_back(device);
296  }
297}
298
299void NetworkStateHandler::GetFavoriteList(FavoriteStateList* list) const {
300  GetFavoriteListByType(NetworkTypePattern::Default(), list);
301}
302
303void NetworkStateHandler::GetFavoriteListByType(const NetworkTypePattern& type,
304                                                FavoriteStateList* list) const {
305  DCHECK(list);
306  FavoriteStateList result;
307  list->clear();
308  for (ManagedStateList::const_iterator iter = favorite_list_.begin();
309       iter != favorite_list_.end(); ++iter) {
310    const FavoriteState* favorite = (*iter)->AsFavoriteState();
311    DCHECK(favorite);
312    if (favorite->update_received() && favorite->IsFavorite() &&
313        favorite->Matches(type)) {
314      list->push_back(favorite);
315    }
316  }
317}
318
319const FavoriteState* NetworkStateHandler::GetFavoriteState(
320    const std::string& service_path) const {
321  ManagedState* managed =
322      GetModifiableManagedState(&favorite_list_, service_path);
323  if (!managed)
324    return NULL;
325  const FavoriteState* favorite = managed->AsFavoriteState();
326  DCHECK(favorite);
327  if (!favorite->update_received() || !favorite->IsFavorite())
328    return NULL;
329  return favorite;
330}
331
332void NetworkStateHandler::RequestScan() const {
333  NET_LOG_USER("RequestScan", "");
334  shill_property_handler_->RequestScan();
335}
336
337void NetworkStateHandler::WaitForScan(const std::string& type,
338                                      const base::Closure& callback) {
339  scan_complete_callbacks_[type].push_back(callback);
340  if (!GetScanningByType(NetworkTypePattern::Primitive(type)))
341    RequestScan();
342}
343
344void NetworkStateHandler::ConnectToBestWifiNetwork() {
345  NET_LOG_USER("ConnectToBestWifiNetwork", "");
346  WaitForScan(shill::kTypeWifi,
347              base::Bind(&internal::ShillPropertyHandler::ConnectToBestServices,
348                         shill_property_handler_->AsWeakPtr()));
349}
350
351void NetworkStateHandler::RequestUpdateForNetwork(
352    const std::string& service_path) {
353  NetworkState* network = GetModifiableNetworkState(service_path);
354  if (network)
355    network->set_update_requested(true);
356  NET_LOG_EVENT("RequestUpdate", service_path);
357  shill_property_handler_->RequestProperties(
358      ManagedState::MANAGED_TYPE_NETWORK, service_path);
359}
360
361void NetworkStateHandler::ClearLastErrorForNetwork(
362    const std::string& service_path) {
363  NetworkState* network = GetModifiableNetworkState(service_path);
364  if (network)
365    network->clear_last_error();
366}
367
368void NetworkStateHandler::SetCheckPortalList(
369    const std::string& check_portal_list) {
370  NET_LOG_EVENT("SetCheckPortalList", check_portal_list);
371  shill_property_handler_->SetCheckPortalList(check_portal_list);
372}
373
374const FavoriteState* NetworkStateHandler::GetEAPForEthernet(
375    const std::string& service_path) const {
376  const NetworkState* network = GetNetworkState(service_path);
377  if (!network) {
378    NET_LOG_ERROR("GetEAPForEthernet", "Unknown service path " + service_path);
379    return NULL;
380  }
381  if (network->type() != shill::kTypeEthernet) {
382    NET_LOG_ERROR("GetEAPForEthernet", "Not of type Ethernet: " + service_path);
383    return NULL;
384  }
385  if (!network->IsConnectedState())
386    return NULL;
387
388  // The same EAP service is shared for all ethernet services/devices.
389  // However EAP is used/enabled per device and only if the connection was
390  // successfully established.
391  const DeviceState* device = GetDeviceState(network->device_path());
392  if (!device) {
393    NET_LOG_ERROR(
394        "GetEAPForEthernet",
395        base::StringPrintf("Unknown device %s of connected ethernet service %s",
396                           network->device_path().c_str(),
397                           service_path.c_str()));
398    return NULL;
399  }
400  if (!device->eap_authentication_completed())
401    return NULL;
402
403  FavoriteStateList list;
404  GetFavoriteListByType(NetworkTypePattern::Primitive(shill::kTypeEthernetEap),
405                        &list);
406  if (list.empty()) {
407    NET_LOG_ERROR("GetEAPForEthernet",
408                  base::StringPrintf(
409                      "Ethernet service %s connected using EAP, but no "
410                      "EAP service found.",
411                      service_path.c_str()));
412    return NULL;
413  }
414  DCHECK(list.size() == 1);
415  return list.front();
416}
417
418void NetworkStateHandler::GetNetworkStatePropertiesForTest(
419    base::DictionaryValue* dictionary) const {
420  for (ManagedStateList::const_iterator iter = network_list_.begin();
421       iter != network_list_.end(); ++iter) {
422    base::DictionaryValue* network_dict = new base::DictionaryValue;
423    (*iter)->AsNetworkState()->GetProperties(network_dict);
424    dictionary->SetWithoutPathExpansion((*iter)->path(), network_dict);
425  }
426}
427
428//------------------------------------------------------------------------------
429// ShillPropertyHandler::Delegate overrides
430
431void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
432                                            const base::ListValue& entries) {
433  ManagedStateList* managed_list = GetManagedList(type);
434  NET_LOG_DEBUG(base::StringPrintf("UpdateManagedList:%d", type),
435                base::StringPrintf("%" PRIuS, entries.GetSize()));
436  // Create a map of existing entries. Assumes all entries in |managed_list|
437  // are unique.
438  std::map<std::string, ManagedState*> managed_map;
439  for (ManagedStateList::iterator iter = managed_list->begin();
440       iter != managed_list->end(); ++iter) {
441    ManagedState* managed = *iter;
442    DCHECK(!ContainsKey(managed_map, managed->path()));
443    managed_map[managed->path()] = managed;
444  }
445  // Clear the list (pointers are temporarily owned by managed_map).
446  managed_list->clear();
447  // Updates managed_list and request updates for new entries.
448  std::set<std::string> list_entries;
449  for (base::ListValue::const_iterator iter = entries.begin();
450       iter != entries.end(); ++iter) {
451    std::string path;
452    (*iter)->GetAsString(&path);
453    if (path.empty() || path == shill::kFlimflamServicePath) {
454      NET_LOG_ERROR(base::StringPrintf("Bad path in list:%d", type), path);
455      continue;
456    }
457    std::map<std::string, ManagedState*>::iterator found =
458        managed_map.find(path);
459    ManagedState* managed;
460    if (found == managed_map.end()) {
461      if (list_entries.count(path) != 0) {
462        NET_LOG_ERROR("Duplicate entry in list", path);
463        continue;
464      }
465      managed = ManagedState::Create(type, path);
466      managed_list->push_back(managed);
467    } else {
468      managed = found->second;
469      managed_list->push_back(managed);
470      managed_map.erase(found);
471    }
472    list_entries.insert(path);
473  }
474  // Delete any remaining entries in managed_map.
475  STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
476}
477
478void NetworkStateHandler::ProfileListChanged() {
479  NET_LOG_EVENT("ProfileListChanged", "Re-Requesting Network Properties");
480  for (ManagedStateList::iterator iter = favorite_list_.begin();
481       iter != favorite_list_.end(); ++iter) {
482    shill_property_handler_->RequestProperties(
483        ManagedState::MANAGED_TYPE_NETWORK, (*iter)->path());
484  }
485}
486
487void NetworkStateHandler::UpdateManagedStateProperties(
488    ManagedState::ManagedType type,
489    const std::string& path,
490    const base::DictionaryValue& properties) {
491  ManagedStateList* managed_list = GetManagedList(type);
492  ManagedState* managed = GetModifiableManagedState(managed_list, path);
493  if (!managed) {
494    if (type != ManagedState::MANAGED_TYPE_FAVORITE) {
495      // The network has been removed from the list of visible networks.
496      NET_LOG_DEBUG("UpdateManagedStateProperties: Not found", path);
497      return;
498    }
499    // A Favorite may not have been created yet if it was added later (e.g.
500    // through ConfigureService) since ServiceCompleteList updates are not
501    // emitted. Add and update the state here.
502    managed = new FavoriteState(path);
503    managed_list->push_back(managed);
504  }
505  managed->set_update_received();
506
507  std::string desc = GetManagedStateLogType(managed) + " Properties Received";
508  NET_LOG_DEBUG(desc, GetManagedStateLogName(managed));
509
510  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
511    UpdateNetworkStateProperties(managed->AsNetworkState(), properties);
512  } else {
513    // Device, Favorite
514    for (base::DictionaryValue::Iterator iter(properties);
515         !iter.IsAtEnd(); iter.Advance()) {
516      managed->PropertyChanged(iter.key(), iter.value());
517    }
518    managed->InitialPropertiesReceived(properties);
519  }
520  managed->set_update_requested(false);
521}
522
523void NetworkStateHandler::UpdateNetworkStateProperties(
524    NetworkState* network,
525    const base::DictionaryValue& properties) {
526  DCHECK(network);
527  bool network_property_updated = false;
528  std::string prev_connection_state = network->connection_state();
529  for (base::DictionaryValue::Iterator iter(properties);
530       !iter.IsAtEnd(); iter.Advance()) {
531    if (network->PropertyChanged(iter.key(), iter.value()))
532      network_property_updated = true;
533  }
534  network_property_updated |= network->InitialPropertiesReceived(properties);
535  // Notify observers of NetworkState changes.
536  if (network_property_updated || network->update_requested()) {
537    // Signal connection state changed after all properties have been updated.
538    if (ConnectionStateChanged(network, prev_connection_state))
539      OnNetworkConnectionStateChanged(network);
540    NET_LOG_EVENT("NetworkPropertiesUpdated", GetManagedStateLogName(network));
541    NotifyNetworkPropertiesUpdated(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      std::string log_event = "NetworkPropertyUpdated";
584      // Trigger a default network update for interesting changes only.
585      if (network->path() == default_network_path_) {
586        NotifyDefaultNetworkChanged(network);
587        log_event = "Default" + log_event;
588      }
589      // Log event.
590      std::string detail = network->name() + "." + key;
591      detail += " = " + network_event_log::ValueAsString(value);
592      network_event_log::LogLevel log_level;
593      if (key == shill::kErrorProperty || key == shill::kErrorDetailsProperty) {
594        log_level = network_event_log::LOG_LEVEL_ERROR;
595      } else {
596        log_level = network_event_log::LOG_LEVEL_EVENT;
597      }
598      NET_LOG_LEVEL(log_level, log_event, detail);
599    }
600  }
601
602  // All property updates signal 'NetworkPropertiesUpdated'.
603  NotifyNetworkPropertiesUpdated(network);
604
605  // If added to a Profile, request a full update so that a FavoriteState
606  // gets created.
607  if (prev_profile_path.empty() && !network->profile_path().empty())
608    RequestUpdateForNetwork(service_path);
609}
610
611void NetworkStateHandler::UpdateDeviceProperty(const std::string& device_path,
612                                               const std::string& key,
613                                               const base::Value& value) {
614  DeviceState* device = GetModifiableDeviceState(device_path);
615  if (!device)
616    return;
617  if (!device->PropertyChanged(key, value))
618    return;
619
620  std::string detail = device->name() + "." + key;
621  detail += " = " + network_event_log::ValueAsString(value);
622  NET_LOG_EVENT("DevicePropertyUpdated", detail);
623
624  NotifyDeviceListChanged();
625
626  if (key == shill::kScanningProperty && device->scanning() == false)
627    ScanCompleted(device->type());
628  if (key == shill::kEapAuthenticationCompletedProperty) {
629    // Notify a change for each Ethernet service using this device.
630    NetworkStateList ethernet_services;
631    GetNetworkListByType(NetworkTypePattern::Ethernet(), &ethernet_services);
632    for (NetworkStateList::const_iterator it = ethernet_services.begin();
633         it != ethernet_services.end(); ++it) {
634      const NetworkState* ethernet_service = *it;
635      if (ethernet_service->update_received() ||
636          ethernet_service->device_path() != device->path()) {
637        continue;
638      }
639      RequestUpdateForNetwork(ethernet_service->path());
640    }
641  }
642}
643
644void NetworkStateHandler::CheckPortalListChanged(
645    const std::string& check_portal_list) {
646  check_portal_list_ = check_portal_list;
647}
648
649void NetworkStateHandler::TechnologyListChanged() {
650  // Eventually we would like to replace Technology state with Device state.
651  // For now, treat technology state changes as device list changes.
652  NotifyDeviceListChanged();
653}
654
655void NetworkStateHandler::ManagedStateListChanged(
656    ManagedState::ManagedType type) {
657  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
658    // Notify observers that the list of networks has changed.
659    NET_LOG_EVENT("NetworkListChanged",
660                  base::StringPrintf("Size:%" PRIuS, network_list_.size()));
661    FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
662                      NetworkListChanged());
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->IsFavorite())
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
692void NetworkStateHandler::DefaultNetworkServiceChanged(
693    const std::string& service_path) {
694  // Shill uses '/' for empty service path values; check explicitly for that.
695  const char* kEmptyServicePath = "/";
696  if (service_path == kEmptyServicePath)
697    default_network_path_.clear();
698  else
699    default_network_path_ = service_path;
700  NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_);
701  const NetworkState* network = NULL;
702  if (!default_network_path_.empty()) {
703    network = GetNetworkState(default_network_path_);
704    if (!network) {
705      // If NetworkState is not available yet, do not notify observers here,
706      // they will be notified when the state is received.
707      NET_LOG_DEBUG("Default NetworkState not available",
708                    default_network_path_);
709      return;
710    }
711  }
712  if (network && !network->IsConnectedState()) {
713    NET_LOG_ERROR(
714        "DefaultNetwork is not connected: " + network->connection_state(),
715        network->path());
716  }
717  NotifyDefaultNetworkChanged(network);
718}
719
720//------------------------------------------------------------------------------
721// Private methods
722
723void NetworkStateHandler::NotifyDeviceListChanged() {
724  NET_LOG_DEBUG("NotifyDeviceListChanged",
725                base::StringPrintf("Size:%" PRIuS, device_list_.size()));
726  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
727                    DeviceListChanged());
728}
729
730DeviceState* NetworkStateHandler::GetModifiableDeviceState(
731    const std::string& device_path) const {
732  ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
733  if (!managed)
734    return NULL;
735  return managed->AsDeviceState();
736}
737
738NetworkState* NetworkStateHandler::GetModifiableNetworkState(
739    const std::string& service_path) const {
740  ManagedState* managed =
741      GetModifiableManagedState(&network_list_, service_path);
742  if (!managed)
743    return NULL;
744  return managed->AsNetworkState();
745}
746
747ManagedState* NetworkStateHandler::GetModifiableManagedState(
748    const ManagedStateList* managed_list,
749    const std::string& path) const {
750  for (ManagedStateList::const_iterator iter = managed_list->begin();
751       iter != managed_list->end(); ++iter) {
752    ManagedState* managed = *iter;
753    if (managed->path() == path)
754      return managed;
755  }
756  return NULL;
757}
758
759NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
760    ManagedState::ManagedType type) {
761  switch (type) {
762    case ManagedState::MANAGED_TYPE_NETWORK:
763      return &network_list_;
764    case ManagedState::MANAGED_TYPE_FAVORITE:
765      return &favorite_list_;
766    case ManagedState::MANAGED_TYPE_DEVICE:
767      return &device_list_;
768  }
769  NOTREACHED();
770  return NULL;
771}
772
773void NetworkStateHandler::OnNetworkConnectionStateChanged(
774    NetworkState* network) {
775  DCHECK(network);
776  std::string event = "NetworkConnectionStateChanged";
777  if (network->path() == default_network_path_) {
778    event = "Default" + event;
779    if (!network->IsConnectedState()) {
780      NET_LOG_ERROR(
781          "DefaultNetwork is not connected: " + network->connection_state(),
782          network->path());
783    }
784  }
785  NET_LOG_EVENT(event + ": " + network->connection_state(),
786                GetManagedStateLogName(network));
787  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
788                    NetworkConnectionStateChanged(network));
789  if (network->path() == default_network_path_)
790    NotifyDefaultNetworkChanged(network);
791}
792
793void NetworkStateHandler::NotifyDefaultNetworkChanged(
794    const NetworkState* default_network) {
795  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
796                    DefaultNetworkChanged(default_network));
797}
798
799void NetworkStateHandler::NotifyNetworkPropertiesUpdated(
800    const NetworkState* network) {
801  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
802                    NetworkPropertiesUpdated(network));
803}
804
805void NetworkStateHandler::ScanCompleted(const std::string& type) {
806  size_t num_callbacks = scan_complete_callbacks_.count(type);
807  NET_LOG_EVENT("ScanCompleted",
808                base::StringPrintf("%s:%" PRIuS, type.c_str(), num_callbacks));
809  if (num_callbacks == 0)
810    return;
811  ScanCallbackList& callback_list = scan_complete_callbacks_[type];
812  for (ScanCallbackList::iterator iter = callback_list.begin();
813       iter != callback_list.end(); ++iter) {
814    (*iter).Run();
815  }
816  scan_complete_callbacks_.erase(type);
817}
818
819std::string NetworkStateHandler::GetTechnologyForType(
820    const NetworkTypePattern& type) const {
821  if (type.MatchesType(shill::kTypeEthernet))
822    return shill::kTypeEthernet;
823
824  if (type.MatchesType(shill::kTypeWifi))
825    return shill::kTypeWifi;
826
827  if (type.Equals(NetworkTypePattern::Wimax()))
828    return shill::kTypeWimax;
829
830  // Prefer Wimax over Cellular only if it's available.
831  if (type.MatchesType(shill::kTypeWimax) &&
832      shill_property_handler_->IsTechnologyAvailable(shill::kTypeWimax)) {
833    return shill::kTypeWimax;
834  }
835
836  if (type.MatchesType(shill::kTypeCellular))
837    return shill::kTypeCellular;
838
839  NOTREACHED();
840  return std::string();
841}
842
843ScopedVector<std::string> NetworkStateHandler::GetTechnologiesForType(
844    const NetworkTypePattern& type) const {
845  ScopedVector<std::string> technologies;
846  if (type.MatchesType(shill::kTypeEthernet))
847    technologies.push_back(new std::string(shill::kTypeEthernet));
848  if (type.MatchesType(shill::kTypeWifi))
849    technologies.push_back(new std::string(shill::kTypeWifi));
850  if (type.MatchesType(shill::kTypeWimax))
851    technologies.push_back(new std::string(shill::kTypeWimax));
852  if (type.MatchesType(shill::kTypeCellular))
853    technologies.push_back(new std::string(shill::kTypeCellular));
854  if (type.MatchesType(shill::kTypeBluetooth))
855    technologies.push_back(new std::string(shill::kTypeBluetooth));
856  if (type.MatchesType(shill::kTypeVPN))
857    technologies.push_back(new std::string(shill::kTypeVPN));
858
859  CHECK_GT(technologies.size(), 0ul);
860  return technologies.Pass();
861}
862
863}  // namespace chromeos
864