network_state_handler.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/favorite_state.h"
19#include "chromeos/network/managed_state.h"
20#include "chromeos/network/network_event_log.h"
21#include "chromeos/network/network_state.h"
22#include "chromeos/network/network_state_handler_observer.h"
23#include "chromeos/network/shill_property_handler.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 = GetFavoriteStateFromServicePath(
198      default_network->path(), true /* configured_only */);
199  DCHECK(default_network->type() != shill::kTypeWifi || default_favorite)
200      << "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 network_util::FormattedMacAddress(device->mac_address());
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(),
301                        true /* configured_only */,
302                        false /* visible_only */,
303                        0 /* no limit */,
304                        list);
305}
306
307void NetworkStateHandler::GetFavoriteListByType(const NetworkTypePattern& type,
308                                                bool configured_only,
309                                                bool visible_only,
310                                                int limit,
311                                                FavoriteStateList* list) const {
312  DCHECK(list);
313  std::set<std::string> visible_networks;
314  if (visible_only) {
315    // Prepare a set of visible network service paths for fast lookup.
316    for (ManagedStateList::const_iterator iter = network_list_.begin();
317         iter != network_list_.end(); ++iter) {
318      visible_networks.insert((*iter)->path());
319    }
320  }
321  FavoriteStateList result;
322  list->clear();
323  int count = 0;
324  for (ManagedStateList::const_iterator iter = favorite_list_.begin();
325       iter != favorite_list_.end(); ++iter) {
326    const FavoriteState* favorite = (*iter)->AsFavoriteState();
327    DCHECK(favorite);
328    if (!favorite->update_received() || !favorite->Matches(type))
329      continue;
330    if (configured_only && !favorite->IsInProfile())
331      continue;
332    if (visible_only && !ContainsKey(visible_networks, favorite->path()))
333      continue;
334    list->push_back(favorite);
335    if (limit > 0 && ++count >= limit)
336      break;
337  }
338}
339
340const FavoriteState* NetworkStateHandler::GetFavoriteStateFromServicePath(
341    const std::string& service_path,
342    bool configured_only) const {
343  ManagedState* managed =
344      GetModifiableManagedState(&favorite_list_, service_path);
345  if (!managed)
346    return NULL;
347  const FavoriteState* favorite = managed->AsFavoriteState();
348  DCHECK(favorite);
349  if (!favorite->update_received() ||
350      (configured_only && !favorite->IsInProfile())) {
351    return NULL;
352  }
353  return favorite;
354}
355
356const FavoriteState* NetworkStateHandler::GetFavoriteStateFromGuid(
357    const std::string& guid) const {
358  DCHECK(!guid.empty());
359  for (ManagedStateList::const_iterator iter = favorite_list_.begin();
360       iter != favorite_list_.end(); ++iter) {
361    const FavoriteState* favorite = (*iter)->AsFavoriteState();
362    if (favorite->guid() == guid)
363      return favorite;
364  }
365  return NULL;
366}
367
368void NetworkStateHandler::RequestScan() const {
369  NET_LOG_USER("RequestScan", "");
370  shill_property_handler_->RequestScan();
371}
372
373void NetworkStateHandler::WaitForScan(const std::string& type,
374                                      const base::Closure& callback) {
375  scan_complete_callbacks_[type].push_back(callback);
376  if (!GetScanningByType(NetworkTypePattern::Primitive(type)))
377    RequestScan();
378}
379
380void NetworkStateHandler::ConnectToBestWifiNetwork() {
381  NET_LOG_USER("ConnectToBestWifiNetwork", "");
382  WaitForScan(shill::kTypeWifi,
383              base::Bind(&internal::ShillPropertyHandler::ConnectToBestServices,
384                         shill_property_handler_->AsWeakPtr()));
385}
386
387void NetworkStateHandler::RequestUpdateForNetwork(
388    const std::string& service_path) {
389  NetworkState* network = GetModifiableNetworkState(service_path);
390  if (network)
391    network->set_update_requested(true);
392  NET_LOG_EVENT("RequestUpdate", service_path);
393  shill_property_handler_->RequestProperties(
394      ManagedState::MANAGED_TYPE_NETWORK, service_path);
395}
396
397void NetworkStateHandler::ClearLastErrorForNetwork(
398    const std::string& service_path) {
399  NetworkState* network = GetModifiableNetworkState(service_path);
400  if (network)
401    network->clear_last_error();
402}
403
404void NetworkStateHandler::SetCheckPortalList(
405    const std::string& check_portal_list) {
406  NET_LOG_EVENT("SetCheckPortalList", check_portal_list);
407  shill_property_handler_->SetCheckPortalList(check_portal_list);
408}
409
410const FavoriteState* NetworkStateHandler::GetEAPForEthernet(
411    const std::string& service_path) const {
412  const NetworkState* network = GetNetworkState(service_path);
413  if (!network) {
414    NET_LOG_ERROR("GetEAPForEthernet", "Unknown service path " + service_path);
415    return NULL;
416  }
417  if (network->type() != shill::kTypeEthernet) {
418    NET_LOG_ERROR("GetEAPForEthernet", "Not of type Ethernet: " + service_path);
419    return NULL;
420  }
421  if (!network->IsConnectedState())
422    return NULL;
423
424  // The same EAP service is shared for all ethernet services/devices.
425  // However EAP is used/enabled per device and only if the connection was
426  // successfully established.
427  const DeviceState* device = GetDeviceState(network->device_path());
428  if (!device) {
429    NET_LOG_ERROR(
430        "GetEAPForEthernet",
431        base::StringPrintf("Unknown device %s of connected ethernet service %s",
432                           network->device_path().c_str(),
433                           service_path.c_str()));
434    return NULL;
435  }
436  if (!device->eap_authentication_completed())
437    return NULL;
438
439  FavoriteStateList list;
440  GetFavoriteListByType(NetworkTypePattern::Primitive(shill::kTypeEthernetEap),
441                        true /* configured_only */,
442                        false /* visible_only */,
443                        1 /* limit */,
444                        &list);
445  if (list.empty()) {
446    NET_LOG_ERROR("GetEAPForEthernet",
447                  base::StringPrintf(
448                      "Ethernet service %s connected using EAP, but no "
449                      "EAP service found.",
450                      service_path.c_str()));
451    return NULL;
452  }
453  return list.front();
454}
455
456//------------------------------------------------------------------------------
457// ShillPropertyHandler::Delegate overrides
458
459void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
460                                            const base::ListValue& entries) {
461  ManagedStateList* managed_list = GetManagedList(type);
462  NET_LOG_DEBUG(base::StringPrintf("UpdateManagedList:%d", type),
463                base::StringPrintf("%" PRIuS, entries.GetSize()));
464  // Create a map of existing entries. Assumes all entries in |managed_list|
465  // are unique.
466  std::map<std::string, ManagedState*> managed_map;
467  for (ManagedStateList::iterator iter = managed_list->begin();
468       iter != managed_list->end(); ++iter) {
469    ManagedState* managed = *iter;
470    DCHECK(!ContainsKey(managed_map, managed->path()));
471    managed_map[managed->path()] = managed;
472  }
473  // Clear the list (pointers are temporarily owned by managed_map).
474  managed_list->clear();
475  // Updates managed_list and request updates for new entries.
476  std::set<std::string> list_entries;
477  for (base::ListValue::const_iterator iter = entries.begin();
478       iter != entries.end(); ++iter) {
479    std::string path;
480    (*iter)->GetAsString(&path);
481    if (path.empty() || path == shill::kFlimflamServicePath) {
482      NET_LOG_ERROR(base::StringPrintf("Bad path in list:%d", type), path);
483      continue;
484    }
485    std::map<std::string, ManagedState*>::iterator found =
486        managed_map.find(path);
487    ManagedState* managed;
488    if (found == managed_map.end()) {
489      if (list_entries.count(path) != 0) {
490        NET_LOG_ERROR("Duplicate entry in list", path);
491        continue;
492      }
493      managed = ManagedState::Create(type, path);
494      managed_list->push_back(managed);
495    } else {
496      managed = found->second;
497      managed_list->push_back(managed);
498      managed_map.erase(found);
499    }
500    list_entries.insert(path);
501  }
502  // Delete any remaining entries in managed_map.
503  STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
504}
505
506void NetworkStateHandler::ProfileListChanged() {
507  NET_LOG_EVENT("ProfileListChanged", "Re-Requesting Network Properties");
508  for (ManagedStateList::iterator iter = favorite_list_.begin();
509       iter != favorite_list_.end(); ++iter) {
510    shill_property_handler_->RequestProperties(
511        ManagedState::MANAGED_TYPE_NETWORK, (*iter)->path());
512  }
513}
514
515void NetworkStateHandler::UpdateManagedStateProperties(
516    ManagedState::ManagedType type,
517    const std::string& path,
518    const base::DictionaryValue& properties) {
519  ManagedStateList* managed_list = GetManagedList(type);
520  ManagedState* managed = GetModifiableManagedState(managed_list, path);
521  if (!managed) {
522    if (type != ManagedState::MANAGED_TYPE_FAVORITE) {
523      // The network has been removed from the list of visible networks.
524      NET_LOG_DEBUG("UpdateManagedStateProperties: Not found", path);
525      return;
526    }
527    // A Favorite may not have been created yet if it was added later (e.g.
528    // through ConfigureService) since ServiceCompleteList updates are not
529    // emitted. Add and update the state here.
530    managed = ManagedState::Create(type, path);
531    managed_list->push_back(managed);
532  }
533  managed->set_update_received();
534
535  std::string desc = GetManagedStateLogType(managed) + " Properties Received";
536  NET_LOG_DEBUG(desc, GetManagedStateLogName(managed));
537
538  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
539    UpdateNetworkStateProperties(managed->AsNetworkState(), properties);
540  } else {
541    // Device, Favorite
542    for (base::DictionaryValue::Iterator iter(properties);
543         !iter.IsAtEnd(); iter.Advance()) {
544      managed->PropertyChanged(iter.key(), iter.value());
545    }
546    managed->InitialPropertiesReceived(properties);
547  }
548  UpdateGuid(managed);
549  managed->set_update_requested(false);
550}
551
552void NetworkStateHandler::UpdateNetworkStateProperties(
553    NetworkState* network,
554    const base::DictionaryValue& properties) {
555  DCHECK(network);
556  bool network_property_updated = false;
557  std::string prev_connection_state = network->connection_state();
558  for (base::DictionaryValue::Iterator iter(properties);
559       !iter.IsAtEnd(); iter.Advance()) {
560    if (network->PropertyChanged(iter.key(), iter.value()))
561      network_property_updated = true;
562  }
563  network_property_updated |= network->InitialPropertiesReceived(properties);
564  // Notify observers of NetworkState changes.
565  if (network_property_updated || network->update_requested()) {
566    // Signal connection state changed after all properties have been updated.
567    if (ConnectionStateChanged(network, prev_connection_state))
568      OnNetworkConnectionStateChanged(network);
569    NET_LOG_EVENT("NetworkPropertiesUpdated", GetManagedStateLogName(network));
570    NotifyNetworkPropertiesUpdated(network);
571  }
572}
573
574void NetworkStateHandler::UpdateNetworkServiceProperty(
575    const std::string& service_path,
576    const std::string& key,
577    const base::Value& value) {
578  // Update any associated FavoriteState.
579  ManagedState* favorite =
580      GetModifiableManagedState(&favorite_list_, service_path);
581  bool changed = false;
582  if (favorite)
583    changed |= favorite->PropertyChanged(key, value);
584
585  // Update the NetworkState.
586  NetworkState* network = GetModifiableNetworkState(service_path);
587  if (!network)
588    return;
589  std::string prev_connection_state = network->connection_state();
590  std::string prev_profile_path = network->profile_path();
591  changed |= network->PropertyChanged(key, value);
592  if (!changed)
593    return;
594
595  if (key == shill::kStateProperty) {
596    if (ConnectionStateChanged(network, prev_connection_state)) {
597      OnNetworkConnectionStateChanged(network);
598      // If the connection state changes, other properties such as IPConfig
599      // may have changed, so request a full update.
600      RequestUpdateForNetwork(service_path);
601    }
602  } else {
603    std::string value_str;
604    value.GetAsString(&value_str);
605    // Some property changes are noisy and not interesting:
606    // * Wifi SignalStrength
607    // * WifiFrequencyList updates
608    // * Device property changes to "/" (occurs before a service is removed)
609    if (key != shill::kSignalStrengthProperty &&
610        key != shill::kWifiFrequencyListProperty &&
611        (key != shill::kDeviceProperty || value_str != "/")) {
612      std::string log_event = "NetworkPropertyUpdated";
613      // Trigger a default network update for interesting changes only.
614      if (network->path() == default_network_path_) {
615        NotifyDefaultNetworkChanged(network);
616        log_event = "Default" + log_event;
617      }
618      // Log event.
619      std::string detail = network->name() + "." + key;
620      detail += " = " + network_event_log::ValueAsString(value);
621      network_event_log::LogLevel log_level;
622      if (key == shill::kErrorProperty || key == shill::kErrorDetailsProperty) {
623        log_level = network_event_log::LOG_LEVEL_ERROR;
624      } else {
625        log_level = network_event_log::LOG_LEVEL_EVENT;
626      }
627      NET_LOG_LEVEL(log_level, log_event, detail);
628    }
629  }
630
631  // All property updates signal 'NetworkPropertiesUpdated'.
632  NotifyNetworkPropertiesUpdated(network);
633
634  // If added to a Profile, request a full update so that a FavoriteState
635  // gets created.
636  if (prev_profile_path.empty() && !network->profile_path().empty())
637    RequestUpdateForNetwork(service_path);
638}
639
640void NetworkStateHandler::UpdateDeviceProperty(const std::string& device_path,
641                                               const std::string& key,
642                                               const base::Value& value) {
643  DeviceState* device = GetModifiableDeviceState(device_path);
644  if (!device)
645    return;
646  if (!device->PropertyChanged(key, value))
647    return;
648
649  std::string detail = device->name() + "." + key;
650  detail += " = " + network_event_log::ValueAsString(value);
651  NET_LOG_EVENT("DevicePropertyUpdated", detail);
652
653  NotifyDeviceListChanged();
654
655  if (key == shill::kScanningProperty && device->scanning() == false)
656    ScanCompleted(device->type());
657  if (key == shill::kEapAuthenticationCompletedProperty) {
658    // Notify a change for each Ethernet service using this device.
659    NetworkStateList ethernet_services;
660    GetNetworkListByType(NetworkTypePattern::Ethernet(), &ethernet_services);
661    for (NetworkStateList::const_iterator it = ethernet_services.begin();
662         it != ethernet_services.end(); ++it) {
663      const NetworkState* ethernet_service = *it;
664      if (ethernet_service->update_received() ||
665          ethernet_service->device_path() != device->path()) {
666        continue;
667      }
668      RequestUpdateForNetwork(ethernet_service->path());
669    }
670  }
671}
672
673void NetworkStateHandler::UpdateIPConfigProperties(
674    ManagedState::ManagedType type,
675    const std::string& path,
676    const std::string& ip_config_path,
677    const base::DictionaryValue& properties)  {
678  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
679    NetworkState* network = GetModifiableNetworkState(path);
680    if (!network)
681      return;
682    network->IPConfigPropertiesChanged(properties);
683  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
684    DeviceState* device = GetModifiableDeviceState(path);
685    if (!device)
686      return;
687    device->IPConfigPropertiesChanged(ip_config_path, properties);
688  }
689}
690
691void NetworkStateHandler::CheckPortalListChanged(
692    const std::string& check_portal_list) {
693  check_portal_list_ = check_portal_list;
694}
695
696void NetworkStateHandler::TechnologyListChanged() {
697  // Eventually we would like to replace Technology state with Device state.
698  // For now, treat technology state changes as device list changes.
699  NotifyDeviceListChanged();
700}
701
702void NetworkStateHandler::ManagedStateListChanged(
703    ManagedState::ManagedType type) {
704  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
705    // Notify observers that the list of networks has changed.
706    NET_LOG_EVENT("NetworkListChanged",
707                  base::StringPrintf("Size:%" PRIuS, network_list_.size()));
708    FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
709                      NetworkListChanged());
710    // Update UMA stats.
711    UMA_HISTOGRAM_COUNTS_100("Networks.Visible", network_list_.size());
712  } else if (type == ManagedState::MANAGED_TYPE_FAVORITE) {
713    NET_LOG_DEBUG("FavoriteListChanged",
714                  base::StringPrintf("Size:%" PRIuS, favorite_list_.size()));
715    // The FavoriteState list only changes when the NetworkState list changes,
716    // so no need to signal observers here again.
717
718    // Update UMA stats.
719    size_t shared = 0, unshared = 0;
720    for (ManagedStateList::iterator iter = favorite_list_.begin();
721         iter != favorite_list_.end(); ++iter) {
722      FavoriteState* favorite = (*iter)->AsFavoriteState();
723      if (!favorite->IsInProfile())
724        continue;
725      if (favorite->IsPrivate())
726        ++unshared;
727      else
728        ++shared;
729    }
730    UMA_HISTOGRAM_COUNTS_100("Networks.RememberedShared", shared);
731    UMA_HISTOGRAM_COUNTS_100("Networks.RememberedUnshared", unshared);
732  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
733    std::string devices;
734    for (ManagedStateList::const_iterator iter = device_list_.begin();
735         iter != device_list_.end(); ++iter) {
736      if (iter != device_list_.begin())
737        devices += ", ";
738      devices += (*iter)->name();
739    }
740    NET_LOG_EVENT("DeviceList:", devices);
741    NotifyDeviceListChanged();
742  } else {
743    NOTREACHED();
744  }
745}
746
747void NetworkStateHandler::DefaultNetworkServiceChanged(
748    const std::string& service_path) {
749  // Shill uses '/' for empty service path values; check explicitly for that.
750  const char* kEmptyServicePath = "/";
751  if (service_path == kEmptyServicePath)
752    default_network_path_.clear();
753  else
754    default_network_path_ = service_path;
755  NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_);
756  const NetworkState* network = NULL;
757  if (!default_network_path_.empty()) {
758    network = GetNetworkState(default_network_path_);
759    if (!network) {
760      // If NetworkState is not available yet, do not notify observers here,
761      // they will be notified when the state is received.
762      NET_LOG_DEBUG("Default NetworkState not available",
763                    default_network_path_);
764      return;
765    }
766  }
767  if (network && !network->IsConnectedState()) {
768    NET_LOG_ERROR(
769        "DefaultNetwork is not connected: " + network->connection_state(),
770        network->path());
771  }
772  NotifyDefaultNetworkChanged(network);
773}
774
775//------------------------------------------------------------------------------
776// Private methods
777
778void NetworkStateHandler::UpdateGuid(ManagedState* managed) {
779  if (managed->managed_type() == ManagedState::MANAGED_TYPE_FAVORITE) {
780    FavoriteState* favorite = managed->AsFavoriteState();
781    std::string specifier = favorite->GetSpecifier();
782    if (!favorite->guid().empty()) {
783      // If the favorite is saved in a profile, remove the entry from the map.
784      // Otherwise ensure that the entry matches the specified GUID.
785      if (favorite->IsInProfile())
786        specifier_guid_map_.erase(specifier);
787      else
788        specifier_guid_map_[specifier] = favorite->guid();
789      return;
790    }
791    // Ensure that the FavoriteState has a valid GUID.
792    std::string guid;
793    SpecifierGuidMap::iterator iter = specifier_guid_map_.find(specifier);
794    if (iter != specifier_guid_map_.end()) {
795      guid = iter->second;
796    } else {
797      guid = base::GenerateGUID();
798      specifier_guid_map_[specifier] = guid;
799    }
800    favorite->SetGuid(guid);
801    NetworkState* network = GetModifiableNetworkState(favorite->path());
802    if (network)
803      network->SetGuid(guid);
804  } else if (managed->managed_type() == ManagedState::MANAGED_TYPE_NETWORK) {
805    // If the GUID is not set and a corresponding FavoriteState exists, get the
806    // GUID from the FavoriteState. Otherwise it will get set when the Favorite
807    // is created.
808    NetworkState* network = managed->AsNetworkState();
809    if (!network->guid().empty())
810      return;
811    // ShillPropertyHandler will always call UpdateManagedStateProperties with
812    // type FAVORITE before type NETWORK, so there should always be a
813    // corresponding FavoriteState here.
814    FavoriteState* favorite = GetModifiableFavoriteState(network->path());
815    DCHECK(favorite);
816    if (favorite && !favorite->guid().empty())
817      network->SetGuid(favorite->guid());
818  }
819}
820
821void NetworkStateHandler::NotifyDeviceListChanged() {
822  NET_LOG_DEBUG("NotifyDeviceListChanged",
823                base::StringPrintf("Size:%" PRIuS, device_list_.size()));
824  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
825                    DeviceListChanged());
826}
827
828DeviceState* NetworkStateHandler::GetModifiableDeviceState(
829    const std::string& device_path) const {
830  ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
831  if (!managed)
832    return NULL;
833  return managed->AsDeviceState();
834}
835
836NetworkState* NetworkStateHandler::GetModifiableNetworkState(
837    const std::string& service_path) const {
838  ManagedState* managed =
839      GetModifiableManagedState(&network_list_, service_path);
840  if (!managed)
841    return NULL;
842  return managed->AsNetworkState();
843}
844
845FavoriteState* NetworkStateHandler::GetModifiableFavoriteState(
846    const std::string& service_path) const {
847  ManagedState* managed =
848      GetModifiableManagedState(&favorite_list_, service_path);
849  if (!managed)
850    return NULL;
851  return managed->AsFavoriteState();
852}
853
854ManagedState* NetworkStateHandler::GetModifiableManagedState(
855    const ManagedStateList* managed_list,
856    const std::string& path) const {
857  for (ManagedStateList::const_iterator iter = managed_list->begin();
858       iter != managed_list->end(); ++iter) {
859    ManagedState* managed = *iter;
860    if (managed->path() == path)
861      return managed;
862  }
863  return NULL;
864}
865
866NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
867    ManagedState::ManagedType type) {
868  switch (type) {
869    case ManagedState::MANAGED_TYPE_NETWORK:
870      return &network_list_;
871    case ManagedState::MANAGED_TYPE_FAVORITE:
872      return &favorite_list_;
873    case ManagedState::MANAGED_TYPE_DEVICE:
874      return &device_list_;
875  }
876  NOTREACHED();
877  return NULL;
878}
879
880void NetworkStateHandler::OnNetworkConnectionStateChanged(
881    NetworkState* network) {
882  DCHECK(network);
883  std::string event = "NetworkConnectionStateChanged";
884  if (network->path() == default_network_path_) {
885    event = "Default" + event;
886    if (!network->IsConnectedState()) {
887      NET_LOG_ERROR(
888          "DefaultNetwork is not connected: " + network->connection_state(),
889          network->path());
890    }
891  }
892  NET_LOG_EVENT(event + ": " + network->connection_state(),
893                GetManagedStateLogName(network));
894  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
895                    NetworkConnectionStateChanged(network));
896  if (network->path() == default_network_path_)
897    NotifyDefaultNetworkChanged(network);
898}
899
900void NetworkStateHandler::NotifyDefaultNetworkChanged(
901    const NetworkState* default_network) {
902  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
903                    DefaultNetworkChanged(default_network));
904}
905
906void NetworkStateHandler::NotifyNetworkPropertiesUpdated(
907    const NetworkState* network) {
908  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
909                    NetworkPropertiesUpdated(network));
910}
911
912void NetworkStateHandler::ScanCompleted(const std::string& type) {
913  size_t num_callbacks = scan_complete_callbacks_.count(type);
914  NET_LOG_EVENT("ScanCompleted",
915                base::StringPrintf("%s:%" PRIuS, type.c_str(), num_callbacks));
916  if (num_callbacks == 0)
917    return;
918  ScanCallbackList& callback_list = scan_complete_callbacks_[type];
919  for (ScanCallbackList::iterator iter = callback_list.begin();
920       iter != callback_list.end(); ++iter) {
921    (*iter).Run();
922  }
923  scan_complete_callbacks_.erase(type);
924}
925
926std::string NetworkStateHandler::GetTechnologyForType(
927    const NetworkTypePattern& type) const {
928  if (type.MatchesType(shill::kTypeEthernet))
929    return shill::kTypeEthernet;
930
931  if (type.MatchesType(shill::kTypeWifi))
932    return shill::kTypeWifi;
933
934  if (type.Equals(NetworkTypePattern::Wimax()))
935    return shill::kTypeWimax;
936
937  // Prefer Wimax over Cellular only if it's available.
938  if (type.MatchesType(shill::kTypeWimax) &&
939      shill_property_handler_->IsTechnologyAvailable(shill::kTypeWimax)) {
940    return shill::kTypeWimax;
941  }
942
943  if (type.MatchesType(shill::kTypeCellular))
944    return shill::kTypeCellular;
945
946  NOTREACHED();
947  return std::string();
948}
949
950ScopedVector<std::string> NetworkStateHandler::GetTechnologiesForType(
951    const NetworkTypePattern& type) const {
952  ScopedVector<std::string> technologies;
953  if (type.MatchesType(shill::kTypeEthernet))
954    technologies.push_back(new std::string(shill::kTypeEthernet));
955  if (type.MatchesType(shill::kTypeWifi))
956    technologies.push_back(new std::string(shill::kTypeWifi));
957  if (type.MatchesType(shill::kTypeWimax))
958    technologies.push_back(new std::string(shill::kTypeWimax));
959  if (type.MatchesType(shill::kTypeCellular))
960    technologies.push_back(new std::string(shill::kTypeCellular));
961  if (type.MatchesType(shill::kTypeBluetooth))
962    technologies.push_back(new std::string(shill::kTypeBluetooth));
963  if (type.MatchesType(shill::kTypeVPN))
964    technologies.push_back(new std::string(shill::kTypeVPN));
965
966  CHECK_GT(technologies.size(), 0ul);
967  return technologies.Pass();
968}
969
970}  // namespace chromeos
971