network_state_handler.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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/guid.h"
10#include "base/location.h"
11#include "base/logging.h"
12#include "base/metrics/histogram.h"
13#include "base/stl_util.h"
14#include "base/strings/string_util.h"
15#include "base/strings/stringprintf.h"
16#include "base/values.h"
17#include "chromeos/network/device_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 "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_DEVICE:
41      return "Device";
42  }
43  NOTREACHED();
44  return "";
45}
46
47std::string GetLogName(const ManagedState* state) {
48  if (!state)
49    return "None";
50  return base::StringPrintf("%s (%s)", state->name().c_str(),
51                            state->path().c_str());
52}
53
54}  // namespace
55
56const char NetworkStateHandler::kDefaultCheckPortalList[] =
57    "ethernet,wifi,cellular";
58
59NetworkStateHandler::NetworkStateHandler()
60    : network_list_sorted_(false) {
61}
62
63NetworkStateHandler::~NetworkStateHandler() {
64  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_, IsShuttingDown());
65  STLDeleteContainerPointers(network_list_.begin(), network_list_.end());
66  STLDeleteContainerPointers(device_list_.begin(), device_list_.end());
67}
68
69void NetworkStateHandler::InitShillPropertyHandler() {
70  shill_property_handler_.reset(new internal::ShillPropertyHandler(this));
71  shill_property_handler_->Init();
72}
73
74// static
75NetworkStateHandler* NetworkStateHandler::InitializeForTest() {
76  NetworkStateHandler* handler = new NetworkStateHandler();
77  handler->InitShillPropertyHandler();
78  return handler;
79}
80
81void NetworkStateHandler::AddObserver(
82    NetworkStateHandlerObserver* observer,
83    const tracked_objects::Location& from_here) {
84  observers_.AddObserver(observer);
85  network_event_log::internal::AddEntry(
86      from_here.file_name(), from_here.line_number(),
87      network_event_log::LOG_LEVEL_DEBUG,
88      "NetworkStateHandler::AddObserver", "");
89}
90
91void NetworkStateHandler::RemoveObserver(
92    NetworkStateHandlerObserver* observer,
93    const tracked_objects::Location& from_here) {
94  observers_.RemoveObserver(observer);
95  network_event_log::internal::AddEntry(
96      from_here.file_name(), from_here.line_number(),
97      network_event_log::LOG_LEVEL_DEBUG,
98      "NetworkStateHandler::RemoveObserver", "");
99}
100
101NetworkStateHandler::TechnologyState NetworkStateHandler::GetTechnologyState(
102    const NetworkTypePattern& type) const {
103  std::string technology = GetTechnologyForType(type);
104  TechnologyState state;
105  if (shill_property_handler_->IsTechnologyEnabled(technology))
106    state = TECHNOLOGY_ENABLED;
107  else if (shill_property_handler_->IsTechnologyEnabling(technology))
108    state = TECHNOLOGY_ENABLING;
109  else if (shill_property_handler_->IsTechnologyUninitialized(technology))
110    state = TECHNOLOGY_UNINITIALIZED;
111  else if (shill_property_handler_->IsTechnologyAvailable(technology))
112    state = TECHNOLOGY_AVAILABLE;
113  else
114    state = TECHNOLOGY_UNAVAILABLE;
115  VLOG(2) << "GetTechnologyState: " << type.ToDebugString() << " = " << state;
116  return state;
117}
118
119void NetworkStateHandler::SetTechnologyEnabled(
120    const NetworkTypePattern& type,
121    bool enabled,
122    const network_handler::ErrorCallback& error_callback) {
123  ScopedVector<std::string> technologies = GetTechnologiesForType(type);
124  for (ScopedVector<std::string>::iterator it = technologies.begin();
125      it != technologies.end(); ++it) {
126    std::string* technology = *it;
127    DCHECK(technology);
128    if (!shill_property_handler_->IsTechnologyAvailable(*technology))
129      continue;
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  }
135  // Signal Device/Technology state changed.
136  NotifyDeviceListChanged();
137}
138
139const DeviceState* NetworkStateHandler::GetDeviceState(
140    const std::string& device_path) const {
141  const DeviceState* device = GetModifiableDeviceState(device_path);
142  if (device && !device->update_received())
143    return NULL;
144  return device;
145}
146
147const DeviceState* NetworkStateHandler::GetDeviceStateByType(
148    const NetworkTypePattern& type) const {
149  for (ManagedStateList::const_iterator iter = device_list_.begin();
150       iter != device_list_.end(); ++iter) {
151    ManagedState* device = *iter;
152    if (!device->update_received())
153      continue;
154    if (device->Matches(type))
155      return device->AsDeviceState();
156  }
157  return NULL;
158}
159
160bool NetworkStateHandler::GetScanningByType(
161    const NetworkTypePattern& type) const {
162  for (ManagedStateList::const_iterator iter = device_list_.begin();
163       iter != device_list_.end(); ++iter) {
164    const DeviceState* device = (*iter)->AsDeviceState();
165    DCHECK(device);
166    if (!device->update_received())
167      continue;
168    if (device->Matches(type) && device->scanning())
169      return true;
170  }
171  return false;
172}
173
174const NetworkState* NetworkStateHandler::GetNetworkState(
175    const std::string& service_path) const {
176  const NetworkState* network = GetModifiableNetworkState(service_path);
177  if (network && !network->update_received())
178    return NULL;
179  return network;
180}
181
182const NetworkState* NetworkStateHandler::DefaultNetwork() const {
183  if (default_network_path_.empty())
184    return NULL;
185  return GetNetworkState(default_network_path_);
186}
187
188const NetworkState* NetworkStateHandler::ConnectedNetworkByType(
189    const NetworkTypePattern& type) const {
190  // Active networks are always listed first by Shill so no need to sort.
191  for (ManagedStateList::const_iterator iter = network_list_.begin();
192       iter != network_list_.end(); ++iter) {
193    const NetworkState* network = (*iter)->AsNetworkState();
194    DCHECK(network);
195    if (!network->update_received())
196      continue;
197    if (!network->IsConnectedState())
198      break;  // Connected networks are listed first.
199    if (network->Matches(type))
200      return network;
201  }
202  return NULL;
203}
204
205const NetworkState* NetworkStateHandler::ConnectingNetworkByType(
206    const NetworkTypePattern& type) const {
207  // Active networks are always listed first by Shill so no need to sort.
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() || network->IsConnectedState())
213      continue;
214    if (!network->IsConnectingState())
215      break;  // Connected and connecting networks are listed first.
216    if (network->Matches(type))
217      return network;
218  }
219  return NULL;
220}
221
222const NetworkState* NetworkStateHandler::FirstNetworkByType(
223    const NetworkTypePattern& type) {
224  if (!network_list_sorted_)
225    SortNetworkList();  // Sort to ensure visible networks are listed first.
226  for (ManagedStateList::const_iterator iter = network_list_.begin();
227       iter != network_list_.end(); ++iter) {
228    const NetworkState* network = (*iter)->AsNetworkState();
229    DCHECK(network);
230    if (!network->update_received())
231      continue;
232    if (!network->visible())
233      break;
234    if (network->Matches(type))
235      return network;
236  }
237  return NULL;
238}
239
240std::string NetworkStateHandler::FormattedHardwareAddressForType(
241    const NetworkTypePattern& type) const {
242  const DeviceState* device = NULL;
243  const NetworkState* network = ConnectedNetworkByType(type);
244  if (network)
245    device = GetDeviceState(network->device_path());
246  else
247    device = GetDeviceStateByType(type);
248  if (!device)
249    return std::string();
250  return network_util::FormattedMacAddress(device->mac_address());
251}
252
253void NetworkStateHandler::GetVisibleNetworkListByType(
254    const NetworkTypePattern& type,
255    NetworkStateList* list) {
256  GetNetworkListByType(type,
257                       false /* configured_only */,
258                       true /* visible_only */,
259                       0 /* no limit */,
260                       list);
261}
262
263void NetworkStateHandler::GetVisibleNetworkList(NetworkStateList* list) {
264  GetVisibleNetworkListByType(NetworkTypePattern::Default(), list);
265}
266
267void NetworkStateHandler::GetNetworkListByType(const NetworkTypePattern& type,
268                                               bool configured_only,
269                                               bool visible_only,
270                                               int limit,
271                                               NetworkStateList* list) {
272  DCHECK(list);
273  list->clear();
274  int count = 0;
275  // Sort the network list if necessary.
276  if (!network_list_sorted_)
277    SortNetworkList();
278  for (ManagedStateList::const_iterator iter = network_list_.begin();
279       iter != network_list_.end(); ++iter) {
280    const NetworkState* network = (*iter)->AsNetworkState();
281    DCHECK(network);
282    if (!network->update_received() || !network->Matches(type))
283      continue;
284    if (configured_only && !network->IsInProfile())
285      continue;
286    if (visible_only && !network->visible())
287      continue;
288    list->push_back(network);
289    if (limit > 0 && ++count >= limit)
290      break;
291  }
292}
293
294const NetworkState* NetworkStateHandler::GetNetworkStateFromServicePath(
295    const std::string& service_path,
296    bool configured_only) const {
297  ManagedState* managed =
298      GetModifiableManagedState(&network_list_, service_path);
299  if (!managed)
300    return NULL;
301  const NetworkState* network = managed->AsNetworkState();
302  DCHECK(network);
303  if (!network->update_received() ||
304      (configured_only && !network->IsInProfile())) {
305    return NULL;
306  }
307  return network;
308}
309
310const NetworkState* NetworkStateHandler::GetNetworkStateFromGuid(
311    const std::string& guid) const {
312  DCHECK(!guid.empty());
313  for (ManagedStateList::const_iterator iter = network_list_.begin();
314       iter != network_list_.end(); ++iter) {
315    const NetworkState* network = (*iter)->AsNetworkState();
316    if (network->guid() == guid)
317      return network;
318  }
319  return NULL;
320}
321
322void NetworkStateHandler::GetDeviceList(DeviceStateList* list) const {
323  GetDeviceListByType(NetworkTypePattern::Default(), list);
324}
325
326void NetworkStateHandler::GetDeviceListByType(const NetworkTypePattern& type,
327                                              DeviceStateList* list) const {
328  DCHECK(list);
329  list->clear();
330  for (ManagedStateList::const_iterator iter = device_list_.begin();
331       iter != device_list_.end(); ++iter) {
332    const DeviceState* device = (*iter)->AsDeviceState();
333    DCHECK(device);
334    if (device->update_received() && device->Matches(type))
335      list->push_back(device);
336  }
337}
338
339void NetworkStateHandler::RequestScan() const {
340  NET_LOG_USER("RequestScan", "");
341  shill_property_handler_->RequestScan();
342}
343
344void NetworkStateHandler::WaitForScan(const std::string& type,
345                                      const base::Closure& callback) {
346  scan_complete_callbacks_[type].push_back(callback);
347  if (!GetScanningByType(NetworkTypePattern::Primitive(type)))
348    RequestScan();
349}
350
351void NetworkStateHandler::ConnectToBestWifiNetwork() {
352  NET_LOG_USER("ConnectToBestWifiNetwork", "");
353  WaitForScan(shill::kTypeWifi,
354              base::Bind(&internal::ShillPropertyHandler::ConnectToBestServices,
355                         shill_property_handler_->AsWeakPtr()));
356}
357
358void NetworkStateHandler::RequestUpdateForNetwork(
359    const std::string& service_path) {
360  NetworkState* network = GetModifiableNetworkState(service_path);
361  if (network)
362    network->set_update_requested(true);
363  NET_LOG_EVENT("RequestUpdate", service_path);
364  shill_property_handler_->RequestProperties(
365      ManagedState::MANAGED_TYPE_NETWORK, service_path);
366}
367
368void NetworkStateHandler::ClearLastErrorForNetwork(
369    const std::string& service_path) {
370  NetworkState* network = GetModifiableNetworkState(service_path);
371  if (network)
372    network->clear_last_error();
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 NetworkState* NetworkStateHandler::GetEAPForEthernet(
382    const std::string& service_path) {
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  NetworkStateList list;
411  GetNetworkListByType(NetworkTypePattern::Primitive(shill::kTypeEthernetEap),
412                       true /* configured_only */,
413                       false /* visible_only */,
414                       1 /* limit */,
415                       &list);
416  if (list.empty()) {
417    NET_LOG_ERROR("GetEAPForEthernet",
418                  base::StringPrintf(
419                      "Ethernet service %s connected using EAP, but no "
420                      "EAP service found.",
421                      service_path.c_str()));
422    return NULL;
423  }
424  return list.front();
425}
426
427//------------------------------------------------------------------------------
428// ShillPropertyHandler::Delegate overrides
429
430void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
431                                            const base::ListValue& entries) {
432  ManagedStateList* managed_list = GetManagedList(type);
433  NET_LOG_DEBUG("UpdateManagedList: " + ManagedState::TypeToString(type),
434                base::StringPrintf("%" PRIuS, entries.GetSize()));
435  // Create a map of existing entries. Assumes all entries in |managed_list|
436  // are unique.
437  typedef std::map<std::string, ManagedState*> ManagedMap;
438  ManagedMap 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    ManagedMap::iterator found = managed_map.find(path);
458    if (found == managed_map.end()) {
459      if (list_entries.count(path) != 0) {
460        NET_LOG_ERROR("Duplicate entry in list", path);
461        continue;
462      }
463      ManagedState* managed = ManagedState::Create(type, path);
464      managed_list->push_back(managed);
465    } else {
466      managed_list->push_back(found->second);
467      managed_map.erase(found);
468    }
469    list_entries.insert(path);
470  }
471  // Delete any remaining entries in managed_map.
472  STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
473}
474
475void NetworkStateHandler::ProfileListChanged() {
476  NET_LOG_EVENT("ProfileListChanged", "Re-Requesting Network Properties");
477  for (ManagedStateList::iterator iter = network_list_.begin();
478       iter != network_list_.end(); ++iter) {
479    NetworkState* network = (*iter)->AsNetworkState();
480    DCHECK(network);
481    shill_property_handler_->RequestProperties(
482        ManagedState::MANAGED_TYPE_NETWORK, network->path());
483  }
484}
485
486void NetworkStateHandler::UpdateManagedStateProperties(
487    ManagedState::ManagedType type,
488    const std::string& path,
489    const base::DictionaryValue& properties) {
490  ManagedStateList* managed_list = GetManagedList(type);
491  ManagedState* managed = GetModifiableManagedState(managed_list, path);
492  if (!managed) {
493    // The network has been removed from the list of networks.
494    NET_LOG_DEBUG("UpdateManagedStateProperties: Not found", path);
495    return;
496  }
497  managed->set_update_received();
498
499  std::string desc = GetManagedStateLogType(managed) + " Properties Received";
500  NET_LOG_DEBUG(desc, GetLogName(managed));
501
502  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
503    UpdateNetworkStateProperties(managed->AsNetworkState(), properties);
504  } else {
505    // Device
506    for (base::DictionaryValue::Iterator iter(properties);
507         !iter.IsAtEnd(); iter.Advance()) {
508      managed->PropertyChanged(iter.key(), iter.value());
509    }
510    managed->InitialPropertiesReceived(properties);
511  }
512  managed->set_update_requested(false);
513}
514
515void NetworkStateHandler::UpdateNetworkStateProperties(
516    NetworkState* network,
517    const base::DictionaryValue& properties) {
518  DCHECK(network);
519  bool network_property_updated = false;
520  std::string prev_connection_state = network->connection_state();
521  for (base::DictionaryValue::Iterator iter(properties);
522       !iter.IsAtEnd(); iter.Advance()) {
523    if (network->PropertyChanged(iter.key(), iter.value()))
524      network_property_updated = true;
525  }
526  network_property_updated |= network->InitialPropertiesReceived(properties);
527  UpdateGuid(network);
528  network_list_sorted_ = false;
529
530  // Notify observers of NetworkState changes.
531  if (network_property_updated || network->update_requested()) {
532    // Signal connection state changed after all properties have been updated.
533    if (ConnectionStateChanged(network, prev_connection_state))
534      OnNetworkConnectionStateChanged(network);
535    NET_LOG_EVENT("NetworkPropertiesUpdated", GetLogName(network));
536    NotifyNetworkPropertiesUpdated(network);
537  }
538}
539
540void NetworkStateHandler::UpdateNetworkServiceProperty(
541    const std::string& service_path,
542    const std::string& key,
543    const base::Value& value) {
544  bool changed = false;
545  NetworkState* network = GetModifiableNetworkState(service_path);
546  if (!network)
547    return;
548  std::string prev_connection_state = network->connection_state();
549  std::string prev_profile_path = network->profile_path();
550  changed |= network->PropertyChanged(key, value);
551  if (!changed)
552    return;
553
554  if (key == shill::kStateProperty || key == shill::kVisibleProperty) {
555    network_list_sorted_ = false;
556    if (ConnectionStateChanged(network, prev_connection_state)) {
557      OnNetworkConnectionStateChanged(network);
558      // If the connection state changes, other properties such as IPConfig
559      // may have changed, so request a full update.
560      RequestUpdateForNetwork(service_path);
561    }
562  } else {
563    std::string value_str;
564    value.GetAsString(&value_str);
565    // Some property changes are noisy and not interesting:
566    // * Wifi SignalStrength
567    // * WifiFrequencyList updates
568    // * Device property changes to "/" (occurs before a service is removed)
569    if (key != shill::kSignalStrengthProperty &&
570        key != shill::kWifiFrequencyListProperty &&
571        (key != shill::kDeviceProperty || value_str != "/")) {
572      std::string log_event = "NetworkPropertyUpdated";
573      // Trigger a default network update for interesting changes only.
574      if (network->path() == default_network_path_) {
575        NotifyDefaultNetworkChanged(network);
576        log_event = "Default" + log_event;
577      }
578      // Log event.
579      std::string detail = network->name() + "." + key;
580      detail += " = " + network_event_log::ValueAsString(value);
581      network_event_log::LogLevel log_level;
582      if (key == shill::kErrorProperty || key == shill::kErrorDetailsProperty) {
583        log_level = network_event_log::LOG_LEVEL_ERROR;
584      } else {
585        log_level = network_event_log::LOG_LEVEL_EVENT;
586      }
587      NET_LOG_LEVEL(log_level, log_event, detail);
588    }
589  }
590
591  // All property updates signal 'NetworkPropertiesUpdated'.
592  NotifyNetworkPropertiesUpdated(network);
593
594  // If added to a Profile, request a full update so that a NetworkState
595  // gets created.
596  if (prev_profile_path.empty() && !network->profile_path().empty())
597    RequestUpdateForNetwork(service_path);
598}
599
600void NetworkStateHandler::UpdateDeviceProperty(const std::string& device_path,
601                                               const std::string& key,
602                                               const base::Value& value) {
603  DeviceState* device = GetModifiableDeviceState(device_path);
604  if (!device)
605    return;
606  if (!device->PropertyChanged(key, value))
607    return;
608
609  std::string detail = device->name() + "." + key;
610  detail += " = " + network_event_log::ValueAsString(value);
611  NET_LOG_EVENT("DevicePropertyUpdated", detail);
612
613  NotifyDeviceListChanged();
614
615  if (key == shill::kScanningProperty && device->scanning() == false)
616    ScanCompleted(device->type());
617  if (key == shill::kEapAuthenticationCompletedProperty) {
618    // Notify a change for each Ethernet service using this device.
619    NetworkStateList ethernet_services;
620    GetNetworkListByType(NetworkTypePattern::Ethernet(),
621                         false /* configured_only */,
622                         false /* visible_only */,
623                         0 /* no limit */,
624                         &ethernet_services);
625    for (NetworkStateList::const_iterator it = ethernet_services.begin();
626         it != ethernet_services.end(); ++it) {
627      const NetworkState* ethernet_service = *it;
628      if (ethernet_service->update_received() ||
629          ethernet_service->device_path() != device->path()) {
630        continue;
631      }
632      RequestUpdateForNetwork(ethernet_service->path());
633    }
634  }
635}
636
637void NetworkStateHandler::UpdateIPConfigProperties(
638    ManagedState::ManagedType type,
639    const std::string& path,
640    const std::string& ip_config_path,
641    const base::DictionaryValue& properties)  {
642  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
643    NetworkState* network = GetModifiableNetworkState(path);
644    if (!network)
645      return;
646    network->IPConfigPropertiesChanged(properties);
647    if (network->path() == default_network_path_)
648      NotifyDefaultNetworkChanged(network);
649  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
650    DeviceState* device = GetModifiableDeviceState(path);
651    if (!device)
652      return;
653    device->IPConfigPropertiesChanged(ip_config_path, properties);
654    if (!default_network_path_.empty()) {
655      const NetworkState* default_network =
656          GetNetworkState(default_network_path_);
657      if (default_network && default_network->device_path() == path)
658        NotifyDefaultNetworkChanged(default_network);
659    }
660  }
661}
662
663void NetworkStateHandler::CheckPortalListChanged(
664    const std::string& check_portal_list) {
665  check_portal_list_ = check_portal_list;
666}
667
668void NetworkStateHandler::TechnologyListChanged() {
669  // Eventually we would like to replace Technology state with Device state.
670  // For now, treat technology state changes as device list changes.
671  NotifyDeviceListChanged();
672}
673
674void NetworkStateHandler::ManagedStateListChanged(
675    ManagedState::ManagedType type) {
676  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
677    SortNetworkList();
678    UpdateNetworkStats();
679    // Notify observers that the list of networks has changed.
680    NET_LOG_EVENT("NOTIFY:NetworkListChanged",
681                  base::StringPrintf("Size:%" PRIuS, network_list_.size()));
682    FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
683                      NetworkListChanged());
684  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
685    std::string devices;
686    for (ManagedStateList::const_iterator iter = device_list_.begin();
687         iter != device_list_.end(); ++iter) {
688      if (iter != device_list_.begin())
689        devices += ", ";
690      devices += (*iter)->name();
691    }
692    NET_LOG_EVENT("DeviceList", devices);
693    NotifyDeviceListChanged();
694  } else {
695    NOTREACHED();
696  }
697}
698
699void NetworkStateHandler::SortNetworkList() {
700  bool listing_active_networks = true;
701  ManagedStateList active, non_wifi_visible, wifi_visible, hidden, new_networks;
702  for (ManagedStateList::iterator iter = network_list_.begin();
703       iter != network_list_.end(); ++iter) {
704    NetworkState* network = (*iter)->AsNetworkState();
705    if (!network->update_received()) {
706      new_networks.push_back(network);
707      continue;
708    }
709    if (network->IsConnectedState() || network->IsConnectingState()) {
710      active.push_back(network);
711      if (!listing_active_networks) {
712        NET_LOG_ERROR("Active network follows inactive network",
713                      GetLogName(network));
714      }
715      continue;
716    }
717    listing_active_networks = false;
718    if (network->visible()) {
719      if (NetworkTypePattern::WiFi().MatchesType(network->type()))
720        wifi_visible.push_back(network);
721      else
722        non_wifi_visible.push_back(network);
723    } else {
724      hidden.push_back(network);
725    }
726  }
727  network_list_.clear();
728  network_list_.insert(network_list_.end(), active.begin(), active.end());
729  network_list_.insert(
730      network_list_.end(), non_wifi_visible.begin(), non_wifi_visible.end());
731  network_list_.insert(
732      network_list_.end(), wifi_visible.begin(), wifi_visible.end());
733  network_list_.insert(network_list_.end(), hidden.begin(), hidden.end());
734  network_list_.insert(
735      network_list_.end(), new_networks.begin(), new_networks.end());
736  network_list_sorted_ = true;
737}
738
739void NetworkStateHandler::UpdateNetworkStats() {
740  size_t shared = 0, unshared = 0, visible = 0;
741  for (ManagedStateList::iterator iter = network_list_.begin();
742       iter != network_list_.end(); ++iter) {
743    NetworkState* network = (*iter)->AsNetworkState();
744    if (network->visible())
745      ++visible;
746    if (network->IsInProfile()) {
747      if (network->IsPrivate())
748        ++unshared;
749      else
750        ++shared;
751    }
752  }
753  UMA_HISTOGRAM_COUNTS_100("Networks.Visible", visible);
754  UMA_HISTOGRAM_COUNTS_100("Networks.RememberedShared", shared);
755  UMA_HISTOGRAM_COUNTS_100("Networks.RememberedUnshared", unshared);
756}
757
758void NetworkStateHandler::DefaultNetworkServiceChanged(
759    const std::string& service_path) {
760  // Shill uses '/' for empty service path values; check explicitly for that.
761  const char* kEmptyServicePath = "/";
762  std::string new_service_path =
763      (service_path != kEmptyServicePath) ? service_path : "";
764  if (new_service_path == default_network_path_)
765    return;
766
767  default_network_path_ = service_path;
768  NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_);
769  const NetworkState* network = NULL;
770  if (!default_network_path_.empty()) {
771    network = GetNetworkState(default_network_path_);
772    if (!network) {
773      // If NetworkState is not available yet, do not notify observers here,
774      // they will be notified when the state is received.
775      NET_LOG_DEBUG("Default NetworkState not available",
776                    default_network_path_);
777      return;
778    }
779  }
780  if (network && !network->IsConnectedState()) {
781    NET_LOG_ERROR(
782        "DefaultNetwork is not connected: " + network->connection_state(),
783        network->path());
784  }
785  NotifyDefaultNetworkChanged(network);
786}
787
788//------------------------------------------------------------------------------
789// Private methods
790
791void NetworkStateHandler::UpdateGuid(NetworkState* network) {
792  std::string specifier = network->GetSpecifier();
793  DCHECK(!specifier.empty());
794  if (!network->guid().empty()) {
795    // If the network is saved in a profile, remove the entry from the map.
796    // Otherwise ensure that the entry matches the specified GUID. (e.g. in
797    // case a visible network with a specified guid gets configured with a
798    // new guid).
799    if (network->IsInProfile())
800      specifier_guid_map_.erase(specifier);
801    else
802      specifier_guid_map_[specifier] = network->guid();
803    return;
804  }
805  // Ensure that the NetworkState has a valid GUID.
806  std::string guid;
807  SpecifierGuidMap::iterator iter = specifier_guid_map_.find(specifier);
808  if (iter != specifier_guid_map_.end()) {
809    guid = iter->second;
810  } else {
811    guid = base::GenerateGUID();
812    specifier_guid_map_[specifier] = guid;
813  }
814  network->SetGuid(guid);
815}
816
817void NetworkStateHandler::NotifyDeviceListChanged() {
818  NET_LOG_DEBUG("NOTIFY:DeviceListChanged",
819                base::StringPrintf("Size:%" PRIuS, device_list_.size()));
820  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
821                    DeviceListChanged());
822}
823
824DeviceState* NetworkStateHandler::GetModifiableDeviceState(
825    const std::string& device_path) const {
826  ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
827  if (!managed)
828    return NULL;
829  return managed->AsDeviceState();
830}
831
832NetworkState* NetworkStateHandler::GetModifiableNetworkState(
833    const std::string& service_path) const {
834  ManagedState* managed =
835      GetModifiableManagedState(&network_list_, service_path);
836  if (!managed)
837    return NULL;
838  return managed->AsNetworkState();
839}
840
841ManagedState* NetworkStateHandler::GetModifiableManagedState(
842    const ManagedStateList* managed_list,
843    const std::string& path) const {
844  for (ManagedStateList::const_iterator iter = managed_list->begin();
845       iter != managed_list->end(); ++iter) {
846    ManagedState* managed = *iter;
847    if (managed->path() == path)
848      return managed;
849  }
850  return NULL;
851}
852
853NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
854    ManagedState::ManagedType type) {
855  switch (type) {
856    case ManagedState::MANAGED_TYPE_NETWORK:
857      return &network_list_;
858    case ManagedState::MANAGED_TYPE_DEVICE:
859      return &device_list_;
860  }
861  NOTREACHED();
862  return NULL;
863}
864
865void NetworkStateHandler::OnNetworkConnectionStateChanged(
866    NetworkState* network) {
867  DCHECK(network);
868  std::string event = "NetworkConnectionStateChanged";
869  if (network->path() == default_network_path_) {
870    event = "Default" + event;
871    if (!network->IsConnectedState()) {
872      NET_LOG_ERROR(
873          "DefaultNetwork is not connected: " + network->connection_state(),
874          network->path());
875    }
876  }
877  NET_LOG_EVENT("NOTIFY:" + event + ": " + network->connection_state(),
878                GetLogName(network));
879  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
880                    NetworkConnectionStateChanged(network));
881  if (network->path() == default_network_path_)
882    NotifyDefaultNetworkChanged(network);
883}
884
885void NetworkStateHandler::NotifyDefaultNetworkChanged(
886    const NetworkState* default_network) {
887  NET_LOG_EVENT("NOTIFY:DefaultNetworkChanged", GetLogName(default_network));
888  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
889                    DefaultNetworkChanged(default_network));
890}
891
892void NetworkStateHandler::NotifyNetworkPropertiesUpdated(
893    const NetworkState* network) {
894  NET_LOG_DEBUG("NOTIFY:NetworkPropertiesUpdated", GetLogName(network));
895  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
896                    NetworkPropertiesUpdated(network));
897}
898
899void NetworkStateHandler::ScanCompleted(const std::string& type) {
900  size_t num_callbacks = scan_complete_callbacks_.count(type);
901  NET_LOG_EVENT("ScanCompleted",
902                base::StringPrintf("%s:%" PRIuS, type.c_str(), num_callbacks));
903  if (num_callbacks == 0)
904    return;
905  ScanCallbackList& callback_list = scan_complete_callbacks_[type];
906  for (ScanCallbackList::iterator iter = callback_list.begin();
907       iter != callback_list.end(); ++iter) {
908    (*iter).Run();
909  }
910  scan_complete_callbacks_.erase(type);
911}
912
913std::string NetworkStateHandler::GetTechnologyForType(
914    const NetworkTypePattern& type) const {
915  if (type.MatchesType(shill::kTypeEthernet))
916    return shill::kTypeEthernet;
917
918  if (type.MatchesType(shill::kTypeWifi))
919    return shill::kTypeWifi;
920
921  if (type.Equals(NetworkTypePattern::Wimax()))
922    return shill::kTypeWimax;
923
924  // Prefer Wimax over Cellular only if it's available.
925  if (type.MatchesType(shill::kTypeWimax) &&
926      shill_property_handler_->IsTechnologyAvailable(shill::kTypeWimax)) {
927    return shill::kTypeWimax;
928  }
929
930  if (type.MatchesType(shill::kTypeCellular))
931    return shill::kTypeCellular;
932
933  NOTREACHED();
934  return std::string();
935}
936
937ScopedVector<std::string> NetworkStateHandler::GetTechnologiesForType(
938    const NetworkTypePattern& type) const {
939  ScopedVector<std::string> technologies;
940  if (type.MatchesType(shill::kTypeEthernet))
941    technologies.push_back(new std::string(shill::kTypeEthernet));
942  if (type.MatchesType(shill::kTypeWifi))
943    technologies.push_back(new std::string(shill::kTypeWifi));
944  if (type.MatchesType(shill::kTypeWimax))
945    technologies.push_back(new std::string(shill::kTypeWimax));
946  if (type.MatchesType(shill::kTypeCellular))
947    technologies.push_back(new std::string(shill::kTypeCellular));
948  if (type.MatchesType(shill::kTypeBluetooth))
949    technologies.push_back(new std::string(shill::kTypeBluetooth));
950  if (type.MatchesType(shill::kTypeVPN))
951    technologies.push_back(new std::string(shill::kTypeVPN));
952
953  CHECK_GT(technologies.size(), 0ul);
954  return technologies.Pass();
955}
956
957}  // namespace chromeos
958