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