Fix race condition in WebstoreInstallHelper.
[chromium-blink-merge.git] / chromeos / network / network_state_handler.cc
blobe7ddbcf93abcf43803ca937d8722f40183cdedd5
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.
5 #include "chromeos/network/network_state_handler.h"
7 #include "base/bind.h"
8 #include "base/format_macros.h"
9 #include "base/guid.h"
10 #include "base/json/json_string_value_serializer.h"
11 #include "base/json/json_writer.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "chromeos/network/device_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 "third_party/cros_system_api/dbus/service_constants.h"
25 namespace chromeos {
27 namespace {
29 bool ConnectionStateChanged(NetworkState* network,
30 const std::string& prev_connection_state,
31 bool prev_is_captive_portal) {
32 return ((network->connection_state() != prev_connection_state) &&
33 !((network->connection_state() == shill::kStateIdle) &&
34 prev_connection_state.empty())) ||
35 (network->is_captive_portal() != prev_is_captive_portal);
38 std::string GetManagedStateLogType(const ManagedState* state) {
39 switch (state->managed_type()) {
40 case ManagedState::MANAGED_TYPE_NETWORK:
41 return "Network";
42 case ManagedState::MANAGED_TYPE_DEVICE:
43 return "Device";
45 NOTREACHED();
46 return "";
49 std::string GetLogName(const ManagedState* state) {
50 if (!state)
51 return "None";
52 return base::StringPrintf("%s (%s)", state->name().c_str(),
53 state->path().c_str());
56 std::string ValueAsString(const base::Value& value) {
57 std::string vstr;
58 base::JSONWriter::WriteWithOptions(
59 value, base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &vstr);
60 return vstr.empty() ? "''" : vstr;
63 } // namespace
65 const char NetworkStateHandler::kDefaultCheckPortalList[] =
66 "ethernet,wifi,cellular";
68 NetworkStateHandler::NetworkStateHandler() : network_list_sorted_(false) {
71 NetworkStateHandler::~NetworkStateHandler() {
72 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_, IsShuttingDown());
73 STLDeleteContainerPointers(network_list_.begin(), network_list_.end());
74 STLDeleteContainerPointers(device_list_.begin(), device_list_.end());
77 void NetworkStateHandler::InitShillPropertyHandler() {
78 shill_property_handler_.reset(new internal::ShillPropertyHandler(this));
79 shill_property_handler_->Init();
82 // static
83 NetworkStateHandler* NetworkStateHandler::InitializeForTest() {
84 NetworkStateHandler* handler = new NetworkStateHandler();
85 handler->InitShillPropertyHandler();
86 return handler;
89 void NetworkStateHandler::AddObserver(
90 NetworkStateHandlerObserver* observer,
91 const tracked_objects::Location& from_here) {
92 observers_.AddObserver(observer);
93 device_event_log::AddEntry(from_here.file_name(), from_here.line_number(),
94 device_event_log::LOG_TYPE_NETWORK,
95 device_event_log::LOG_LEVEL_DEBUG,
96 "NetworkStateHandler::AddObserver");
99 void NetworkStateHandler::RemoveObserver(
100 NetworkStateHandlerObserver* observer,
101 const tracked_objects::Location& from_here) {
102 observers_.RemoveObserver(observer);
103 device_event_log::AddEntry(from_here.file_name(), from_here.line_number(),
104 device_event_log::LOG_TYPE_NETWORK,
105 device_event_log::LOG_LEVEL_DEBUG,
106 "NetworkStateHandler::RemoveObserver");
109 NetworkStateHandler::TechnologyState NetworkStateHandler::GetTechnologyState(
110 const NetworkTypePattern& type) const {
111 std::string technology = GetTechnologyForType(type);
112 TechnologyState state;
113 if (shill_property_handler_->IsTechnologyEnabled(technology))
114 state = TECHNOLOGY_ENABLED;
115 else if (shill_property_handler_->IsTechnologyEnabling(technology))
116 state = TECHNOLOGY_ENABLING;
117 else if (shill_property_handler_->IsTechnologyUninitialized(technology))
118 state = TECHNOLOGY_UNINITIALIZED;
119 else if (shill_property_handler_->IsTechnologyAvailable(technology))
120 state = TECHNOLOGY_AVAILABLE;
121 else
122 state = TECHNOLOGY_UNAVAILABLE;
123 VLOG(2) << "GetTechnologyState: " << type.ToDebugString() << " = " << state;
124 return state;
127 void NetworkStateHandler::SetTechnologyEnabled(
128 const NetworkTypePattern& type,
129 bool enabled,
130 const network_handler::ErrorCallback& error_callback) {
131 ScopedVector<std::string> technologies = GetTechnologiesForType(type);
132 for (ScopedVector<std::string>::iterator it = technologies.begin();
133 it != technologies.end(); ++it) {
134 std::string* technology = *it;
135 DCHECK(technology);
136 if (!shill_property_handler_->IsTechnologyAvailable(*technology))
137 continue;
138 NET_LOG_USER("SetTechnologyEnabled",
139 base::StringPrintf("%s:%d", technology->c_str(), enabled));
140 shill_property_handler_->SetTechnologyEnabled(*technology, enabled,
141 error_callback);
143 // Signal Device/Technology state changed.
144 NotifyDeviceListChanged();
147 const DeviceState* NetworkStateHandler::GetDeviceState(
148 const std::string& device_path) const {
149 const DeviceState* device = GetModifiableDeviceState(device_path);
150 if (device && !device->update_received())
151 return nullptr;
152 return device;
155 const DeviceState* NetworkStateHandler::GetDeviceStateByType(
156 const NetworkTypePattern& type) const {
157 for (ManagedStateList::const_iterator iter = device_list_.begin();
158 iter != device_list_.end(); ++iter) {
159 ManagedState* device = *iter;
160 if (!device->update_received())
161 continue;
162 if (device->Matches(type))
163 return device->AsDeviceState();
165 return nullptr;
168 bool NetworkStateHandler::GetScanningByType(
169 const NetworkTypePattern& type) const {
170 for (ManagedStateList::const_iterator iter = device_list_.begin();
171 iter != device_list_.end(); ++iter) {
172 const DeviceState* device = (*iter)->AsDeviceState();
173 DCHECK(device);
174 if (!device->update_received())
175 continue;
176 if (device->Matches(type) && device->scanning())
177 return true;
179 return false;
182 const NetworkState* NetworkStateHandler::GetNetworkState(
183 const std::string& service_path) const {
184 const NetworkState* network = GetModifiableNetworkState(service_path);
185 if (network && !network->update_received())
186 return nullptr;
187 return network;
190 const NetworkState* NetworkStateHandler::DefaultNetwork() const {
191 if (default_network_path_.empty())
192 return nullptr;
193 return GetNetworkState(default_network_path_);
196 const NetworkState* NetworkStateHandler::ConnectedNetworkByType(
197 const NetworkTypePattern& type) const {
198 // Active networks are always listed first by Shill so no need to sort.
199 for (ManagedStateList::const_iterator iter = network_list_.begin();
200 iter != network_list_.end(); ++iter) {
201 const NetworkState* network = (*iter)->AsNetworkState();
202 DCHECK(network);
203 if (!network->update_received())
204 continue;
205 if (!network->IsConnectedState())
206 break; // Connected networks are listed first.
207 if (network->Matches(type))
208 return network;
210 return nullptr;
213 const NetworkState* NetworkStateHandler::ConnectingNetworkByType(
214 const NetworkTypePattern& type) const {
215 // Active networks are always listed first by Shill so no need to sort.
216 for (ManagedStateList::const_iterator iter = network_list_.begin();
217 iter != network_list_.end(); ++iter) {
218 const NetworkState* network = (*iter)->AsNetworkState();
219 DCHECK(network);
220 if (!network->update_received() || network->IsConnectedState())
221 continue;
222 if (!network->IsConnectingState())
223 break; // Connected and connecting networks are listed first.
224 if (network->Matches(type))
225 return network;
227 return nullptr;
230 const NetworkState* NetworkStateHandler::FirstNetworkByType(
231 const NetworkTypePattern& type) {
232 if (!network_list_sorted_)
233 SortNetworkList(); // Sort to ensure visible networks are listed first.
234 for (ManagedStateList::const_iterator iter = network_list_.begin();
235 iter != network_list_.end(); ++iter) {
236 const NetworkState* network = (*iter)->AsNetworkState();
237 DCHECK(network);
238 if (!network->update_received())
239 continue;
240 if (!network->visible())
241 break;
242 if (network->Matches(type))
243 return network;
245 return nullptr;
248 std::string NetworkStateHandler::FormattedHardwareAddressForType(
249 const NetworkTypePattern& type) const {
250 const DeviceState* device = nullptr;
251 const NetworkState* network = ConnectedNetworkByType(type);
252 if (network)
253 device = GetDeviceState(network->device_path());
254 else
255 device = GetDeviceStateByType(type);
256 if (!device)
257 return std::string();
258 return network_util::FormattedMacAddress(device->mac_address());
261 void NetworkStateHandler::GetVisibleNetworkListByType(
262 const NetworkTypePattern& type,
263 NetworkStateList* list) {
264 GetNetworkListByType(type, false /* configured_only */,
265 true /* visible_only */, 0 /* no limit */, list);
268 void NetworkStateHandler::GetVisibleNetworkList(NetworkStateList* list) {
269 GetVisibleNetworkListByType(NetworkTypePattern::Default(), list);
272 void NetworkStateHandler::GetNetworkListByType(const NetworkTypePattern& type,
273 bool configured_only,
274 bool visible_only,
275 int limit,
276 NetworkStateList* list) {
277 DCHECK(list);
278 list->clear();
279 int count = 0;
280 // Sort the network list if necessary.
281 if (!network_list_sorted_)
282 SortNetworkList();
283 for (ManagedStateList::const_iterator iter = network_list_.begin();
284 iter != network_list_.end(); ++iter) {
285 const NetworkState* network = (*iter)->AsNetworkState();
286 DCHECK(network);
287 if (!network->update_received() || !network->Matches(type))
288 continue;
289 if (configured_only && !network->IsInProfile())
290 continue;
291 if (visible_only && !network->visible())
292 continue;
293 list->push_back(network);
294 if (limit > 0 && ++count >= limit)
295 break;
299 const NetworkState* NetworkStateHandler::GetNetworkStateFromServicePath(
300 const std::string& service_path,
301 bool configured_only) const {
302 ManagedState* managed =
303 GetModifiableManagedState(&network_list_, service_path);
304 if (!managed)
305 return nullptr;
306 const NetworkState* network = managed->AsNetworkState();
307 DCHECK(network);
308 if (!network->update_received() ||
309 (configured_only && !network->IsInProfile())) {
310 return nullptr;
312 return network;
315 const NetworkState* NetworkStateHandler::GetNetworkStateFromGuid(
316 const std::string& guid) const {
317 DCHECK(!guid.empty());
318 for (ManagedStateList::const_iterator iter = network_list_.begin();
319 iter != network_list_.end(); ++iter) {
320 const NetworkState* network = (*iter)->AsNetworkState();
321 if (network->guid() == guid)
322 return network;
324 return nullptr;
327 void NetworkStateHandler::GetDeviceList(DeviceStateList* list) const {
328 GetDeviceListByType(NetworkTypePattern::Default(), list);
331 void NetworkStateHandler::GetDeviceListByType(const NetworkTypePattern& type,
332 DeviceStateList* list) const {
333 DCHECK(list);
334 list->clear();
335 for (ManagedStateList::const_iterator iter = device_list_.begin();
336 iter != device_list_.end(); ++iter) {
337 const DeviceState* device = (*iter)->AsDeviceState();
338 DCHECK(device);
339 if (device->update_received() && device->Matches(type))
340 list->push_back(device);
344 void NetworkStateHandler::RequestScan() const {
345 NET_LOG_USER("RequestScan", "");
346 shill_property_handler_->RequestScan();
349 void NetworkStateHandler::RequestUpdateForNetwork(
350 const std::string& service_path) {
351 NetworkState* network = GetModifiableNetworkState(service_path);
352 if (network)
353 network->set_update_requested(true);
354 NET_LOG_EVENT("RequestUpdate", service_path);
355 shill_property_handler_->RequestProperties(ManagedState::MANAGED_TYPE_NETWORK,
356 service_path);
359 void NetworkStateHandler::ClearLastErrorForNetwork(
360 const std::string& service_path) {
361 NetworkState* network = GetModifiableNetworkState(service_path);
362 if (network)
363 network->clear_last_error();
366 void NetworkStateHandler::SetCheckPortalList(
367 const std::string& check_portal_list) {
368 NET_LOG_EVENT("SetCheckPortalList", check_portal_list);
369 shill_property_handler_->SetCheckPortalList(check_portal_list);
372 void NetworkStateHandler::SetWakeOnLanEnabled(bool enabled) {
373 NET_LOG_EVENT("SetWakeOnLanEnabled",
374 base::StringPrintf("%s", enabled ? "true" : "false"));
375 shill_property_handler_->SetWakeOnLanEnabled(enabled);
378 const NetworkState* NetworkStateHandler::GetEAPForEthernet(
379 const std::string& service_path) {
380 const NetworkState* network = GetNetworkState(service_path);
381 if (!network) {
382 NET_LOG_ERROR("GetEAPForEthernet", "Unknown service path " + service_path);
383 return nullptr;
385 if (network->type() != shill::kTypeEthernet) {
386 NET_LOG_ERROR("GetEAPForEthernet", "Not of type Ethernet: " + service_path);
387 return nullptr;
389 if (!network->IsConnectedState())
390 return nullptr;
392 // The same EAP service is shared for all ethernet services/devices.
393 // However EAP is used/enabled per device and only if the connection was
394 // successfully established.
395 const DeviceState* device = GetDeviceState(network->device_path());
396 if (!device) {
397 NET_LOG(ERROR) << "GetEAPForEthernet: Unknown device "
398 << network->device_path()
399 << " for connected ethernet service: " << service_path;
400 return nullptr;
402 if (!device->eap_authentication_completed())
403 return nullptr;
405 NetworkStateList list;
406 GetNetworkListByType(NetworkTypePattern::Primitive(shill::kTypeEthernetEap),
407 true /* configured_only */, false /* visible_only */,
408 1 /* limit */, &list);
409 if (list.empty()) {
410 NET_LOG_ERROR("GetEAPForEthernet",
411 base::StringPrintf(
412 "Ethernet service %s connected using EAP, but no "
413 "EAP service found.",
414 service_path.c_str()));
415 return nullptr;
417 return list.front();
420 void NetworkStateHandler::SetLastErrorForTest(const std::string& service_path,
421 const std::string& error) {
422 NetworkState* network_state = GetModifiableNetworkState(service_path);
423 if (!network_state) {
424 LOG(ERROR) << "No matching NetworkState for: " << service_path;
425 return;
427 network_state->last_error_ = error;
430 //------------------------------------------------------------------------------
431 // ShillPropertyHandler::Delegate overrides
433 void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
434 const base::ListValue& entries) {
435 ManagedStateList* managed_list = GetManagedList(type);
436 NET_LOG_DEBUG("UpdateManagedList: " + ManagedState::TypeToString(type),
437 base::StringPrintf("%" PRIuS, entries.GetSize()));
438 // Create a map of existing entries. Assumes all entries in |managed_list|
439 // are unique.
440 typedef std::map<std::string, ManagedState*> ManagedMap;
441 ManagedMap managed_map;
442 for (ManagedStateList::iterator iter = managed_list->begin();
443 iter != managed_list->end(); ++iter) {
444 ManagedState* managed = *iter;
445 DCHECK(!ContainsKey(managed_map, managed->path()));
446 managed_map[managed->path()] = managed;
448 // Clear the list (pointers are temporarily owned by managed_map).
449 managed_list->clear();
450 // Updates managed_list and request updates for new entries.
451 std::set<std::string> list_entries;
452 for (base::ListValue::const_iterator iter = entries.begin();
453 iter != entries.end(); ++iter) {
454 std::string path;
455 (*iter)->GetAsString(&path);
456 if (path.empty() || path == shill::kFlimflamServicePath) {
457 NET_LOG_ERROR(base::StringPrintf("Bad path in list:%d", type), path);
458 continue;
460 ManagedMap::iterator found = managed_map.find(path);
461 if (found == managed_map.end()) {
462 if (list_entries.count(path) != 0) {
463 NET_LOG_ERROR("Duplicate entry in list", path);
464 continue;
466 ManagedState* managed = ManagedState::Create(type, path);
467 managed_list->push_back(managed);
468 } else {
469 managed_list->push_back(found->second);
470 managed_map.erase(found);
472 list_entries.insert(path);
474 // Delete any remaining entries in managed_map.
475 STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
478 void NetworkStateHandler::ProfileListChanged() {
479 NET_LOG_EVENT("ProfileListChanged", "Re-Requesting Network Properties");
480 for (ManagedStateList::iterator iter = network_list_.begin();
481 iter != network_list_.end(); ++iter) {
482 NetworkState* network = (*iter)->AsNetworkState();
483 DCHECK(network);
484 shill_property_handler_->RequestProperties(
485 ManagedState::MANAGED_TYPE_NETWORK, network->path());
489 void NetworkStateHandler::UpdateManagedStateProperties(
490 ManagedState::ManagedType type,
491 const std::string& path,
492 const base::DictionaryValue& properties) {
493 ManagedStateList* managed_list = GetManagedList(type);
494 ManagedState* managed = GetModifiableManagedState(managed_list, path);
495 if (!managed) {
496 // The network has been removed from the list of networks.
497 NET_LOG_DEBUG("UpdateManagedStateProperties: Not found", path);
498 return;
500 managed->set_update_received();
502 std::string desc = GetManagedStateLogType(managed) + " Properties Received";
503 NET_LOG_DEBUG(desc, GetLogName(managed));
505 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
506 UpdateNetworkStateProperties(managed->AsNetworkState(), properties);
507 } else {
508 // Device
509 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
510 iter.Advance()) {
511 managed->PropertyChanged(iter.key(), iter.value());
513 managed->InitialPropertiesReceived(properties);
515 managed->set_update_requested(false);
518 void NetworkStateHandler::UpdateNetworkStateProperties(
519 NetworkState* network,
520 const base::DictionaryValue& properties) {
521 DCHECK(network);
522 bool network_property_updated = false;
523 std::string prev_connection_state = network->connection_state();
524 bool prev_is_captive_portal = network->is_captive_portal();
525 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
526 iter.Advance()) {
527 if (network->PropertyChanged(iter.key(), iter.value()))
528 network_property_updated = true;
530 network_property_updated |= network->InitialPropertiesReceived(properties);
531 UpdateGuid(network);
532 network_list_sorted_ = false;
534 // Notify observers of NetworkState changes.
535 if (network_property_updated || network->update_requested()) {
536 // Signal connection state changed after all properties have been updated.
537 if (ConnectionStateChanged(network, prev_connection_state,
538 prev_is_captive_portal)) {
539 OnNetworkConnectionStateChanged(network);
541 NET_LOG_EVENT("NetworkPropertiesUpdated", GetLogName(network));
542 NotifyNetworkPropertiesUpdated(network);
546 void NetworkStateHandler::UpdateNetworkServiceProperty(
547 const std::string& service_path,
548 const std::string& key,
549 const base::Value& value) {
550 SCOPED_NET_LOG_IF_SLOW();
551 bool changed = false;
552 NetworkState* network = GetModifiableNetworkState(service_path);
553 if (!network)
554 return;
555 std::string prev_connection_state = network->connection_state();
556 bool prev_is_captive_portal = network->is_captive_portal();
557 std::string prev_profile_path = network->profile_path();
558 changed |= network->PropertyChanged(key, value);
559 if (!changed)
560 return;
562 if (key == shill::kStateProperty || key == shill::kVisibleProperty) {
563 network_list_sorted_ = false;
564 if (ConnectionStateChanged(network, prev_connection_state,
565 prev_is_captive_portal)) {
566 OnNetworkConnectionStateChanged(network);
567 // If the connection state changes, other properties such as IPConfig
568 // may have changed, so request a full update.
569 RequestUpdateForNetwork(service_path);
571 } else {
572 std::string value_str;
573 value.GetAsString(&value_str);
574 // Some property changes are noisy and not interesting:
575 // * Wifi SignalStrength
576 // * WifiFrequencyList updates
577 // * Device property changes to "/" (occurs before a service is removed)
578 if (key != shill::kSignalStrengthProperty &&
579 key != shill::kWifiFrequencyListProperty &&
580 (key != shill::kDeviceProperty || value_str != "/")) {
581 std::string log_event = "NetworkPropertyUpdated";
582 // Trigger a default network update for interesting changes only.
583 if (network->path() == default_network_path_) {
584 NotifyDefaultNetworkChanged(network);
585 log_event = "Default" + log_event;
587 // Log event.
588 std::string detail = network->name() + "." + key;
589 detail += " = " + ValueAsString(value);
590 device_event_log::LogLevel log_level;
591 if (key == shill::kErrorProperty || key == shill::kErrorDetailsProperty) {
592 log_level = device_event_log::LOG_LEVEL_ERROR;
593 } else {
594 log_level = device_event_log::LOG_LEVEL_EVENT;
596 NET_LOG_LEVEL(log_level, log_event, detail);
600 // All property updates signal 'NetworkPropertiesUpdated'.
601 NotifyNetworkPropertiesUpdated(network);
603 // If added to a Profile, request a full update so that a NetworkState
604 // gets created.
605 if (prev_profile_path.empty() && !network->profile_path().empty())
606 RequestUpdateForNetwork(service_path);
609 void NetworkStateHandler::UpdateDeviceProperty(const std::string& device_path,
610 const std::string& key,
611 const base::Value& value) {
612 SCOPED_NET_LOG_IF_SLOW();
613 DeviceState* device = GetModifiableDeviceState(device_path);
614 if (!device)
615 return;
616 if (!device->PropertyChanged(key, value))
617 return;
619 std::string detail = device->name() + "." + key;
620 detail += " = " + ValueAsString(value);
621 NET_LOG_EVENT("DevicePropertyUpdated", detail);
623 NotifyDeviceListChanged();
624 NotifyDevicePropertiesUpdated(device);
626 if (key == shill::kScanningProperty && device->scanning() == false) {
627 NotifyScanCompleted(device);
629 if (key == shill::kEapAuthenticationCompletedProperty) {
630 // Notify a change for each Ethernet service using this device.
631 NetworkStateList ethernet_services;
632 GetNetworkListByType(NetworkTypePattern::Ethernet(),
633 false /* configured_only */, false /* visible_only */,
634 0 /* no limit */, &ethernet_services);
635 for (NetworkStateList::const_iterator it = ethernet_services.begin();
636 it != ethernet_services.end(); ++it) {
637 const NetworkState* ethernet_service = *it;
638 if (ethernet_service->update_received() ||
639 ethernet_service->device_path() != device->path()) {
640 continue;
642 RequestUpdateForNetwork(ethernet_service->path());
647 void NetworkStateHandler::UpdateIPConfigProperties(
648 ManagedState::ManagedType type,
649 const std::string& path,
650 const std::string& ip_config_path,
651 const base::DictionaryValue& properties) {
652 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
653 NetworkState* network = GetModifiableNetworkState(path);
654 if (!network)
655 return;
656 network->IPConfigPropertiesChanged(properties);
657 NotifyNetworkPropertiesUpdated(network);
658 if (network->path() == default_network_path_)
659 NotifyDefaultNetworkChanged(network);
660 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
661 DeviceState* device = GetModifiableDeviceState(path);
662 if (!device)
663 return;
664 device->IPConfigPropertiesChanged(ip_config_path, properties);
665 NotifyDevicePropertiesUpdated(device);
666 if (!default_network_path_.empty()) {
667 const NetworkState* default_network =
668 GetNetworkState(default_network_path_);
669 if (default_network && default_network->device_path() == path)
670 NotifyDefaultNetworkChanged(default_network);
675 void NetworkStateHandler::CheckPortalListChanged(
676 const std::string& check_portal_list) {
677 check_portal_list_ = check_portal_list;
680 void NetworkStateHandler::TechnologyListChanged() {
681 // Eventually we would like to replace Technology state with Device state.
682 // For now, treat technology state changes as device list changes.
683 NotifyDeviceListChanged();
686 void NetworkStateHandler::ManagedStateListChanged(
687 ManagedState::ManagedType type) {
688 SCOPED_NET_LOG_IF_SLOW();
689 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
690 SortNetworkList();
691 UpdateNetworkStats();
692 // Notify observers that the list of networks has changed.
693 NET_LOG_EVENT("NOTIFY:NetworkListChanged",
694 base::StringPrintf("Size:%" PRIuS, network_list_.size()));
695 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
696 NetworkListChanged());
697 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
698 std::string devices;
699 for (ManagedStateList::const_iterator iter = device_list_.begin();
700 iter != device_list_.end(); ++iter) {
701 if (iter != device_list_.begin())
702 devices += ", ";
703 devices += (*iter)->name();
705 NET_LOG_EVENT("DeviceList", devices);
706 NotifyDeviceListChanged();
707 } else {
708 NOTREACHED();
712 void NetworkStateHandler::SortNetworkList() {
713 // Note: usually active networks will precede inactive networks, however
714 // this may briefly be untrue during state transitions (e.g. a network may
715 // transition to idle before the list is updated).
716 ManagedStateList active, non_wifi_visible, wifi_visible, hidden, new_networks;
717 for (ManagedStateList::iterator iter = network_list_.begin();
718 iter != network_list_.end(); ++iter) {
719 NetworkState* network = (*iter)->AsNetworkState();
720 if (!network->update_received()) {
721 new_networks.push_back(network);
722 continue;
724 if (network->IsConnectedState() || network->IsConnectingState()) {
725 active.push_back(network);
726 continue;
728 if (network->visible()) {
729 if (NetworkTypePattern::WiFi().MatchesType(network->type()))
730 wifi_visible.push_back(network);
731 else
732 non_wifi_visible.push_back(network);
733 } else {
734 hidden.push_back(network);
737 network_list_.clear();
738 network_list_.insert(network_list_.end(), active.begin(), active.end());
739 network_list_.insert(network_list_.end(), non_wifi_visible.begin(),
740 non_wifi_visible.end());
741 network_list_.insert(network_list_.end(), wifi_visible.begin(),
742 wifi_visible.end());
743 network_list_.insert(network_list_.end(), hidden.begin(), hidden.end());
744 network_list_.insert(network_list_.end(), new_networks.begin(),
745 new_networks.end());
746 network_list_sorted_ = true;
749 void NetworkStateHandler::UpdateNetworkStats() {
750 size_t shared = 0, unshared = 0, visible = 0;
751 for (ManagedStateList::iterator iter = network_list_.begin();
752 iter != network_list_.end(); ++iter) {
753 NetworkState* network = (*iter)->AsNetworkState();
754 if (network->visible())
755 ++visible;
756 if (network->IsInProfile()) {
757 if (network->IsPrivate())
758 ++unshared;
759 else
760 ++shared;
763 UMA_HISTOGRAM_COUNTS_100("Networks.Visible", visible);
764 UMA_HISTOGRAM_COUNTS_100("Networks.RememberedShared", shared);
765 UMA_HISTOGRAM_COUNTS_100("Networks.RememberedUnshared", unshared);
768 void NetworkStateHandler::DefaultNetworkServiceChanged(
769 const std::string& service_path) {
770 // Shill uses '/' for empty service path values; check explicitly for that.
771 const char* kEmptyServicePath = "/";
772 std::string new_service_path =
773 (service_path != kEmptyServicePath) ? service_path : "";
774 if (new_service_path == default_network_path_)
775 return;
777 default_network_path_ = service_path;
778 NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_);
779 const NetworkState* network = nullptr;
780 if (!default_network_path_.empty()) {
781 network = GetNetworkState(default_network_path_);
782 if (!network) {
783 // If NetworkState is not available yet, do not notify observers here,
784 // they will be notified when the state is received.
785 NET_LOG(EVENT) << "Default NetworkState not available: "
786 << default_network_path_;
787 return;
790 if (network && !network->IsConnectedState()) {
791 if (network->IsConnectingState()) {
792 NET_LOG(EVENT) << "DefaultNetwork is connecting: " << GetLogName(network)
793 << ": " << network->connection_state();
794 } else {
795 NET_LOG(ERROR) << "DefaultNetwork in unexpected state: "
796 << GetLogName(network) << ": "
797 << network->connection_state();
799 // Do not notify observers here, the notification will occur when the
800 // connection state changes.
801 return;
803 NotifyDefaultNetworkChanged(network);
806 //------------------------------------------------------------------------------
807 // Private methods
809 void NetworkStateHandler::UpdateGuid(NetworkState* network) {
810 std::string specifier = network->GetSpecifier();
811 DCHECK(!specifier.empty());
812 if (!network->guid().empty()) {
813 // If the network is saved in a profile, remove the entry from the map.
814 // Otherwise ensure that the entry matches the specified GUID. (e.g. in
815 // case a visible network with a specified guid gets configured with a
816 // new guid).
817 if (network->IsInProfile())
818 specifier_guid_map_.erase(specifier);
819 else
820 specifier_guid_map_[specifier] = network->guid();
821 return;
823 // Ensure that the NetworkState has a valid GUID.
824 std::string guid;
825 SpecifierGuidMap::iterator iter = specifier_guid_map_.find(specifier);
826 if (iter != specifier_guid_map_.end()) {
827 guid = iter->second;
828 } else {
829 guid = base::GenerateGUID();
830 specifier_guid_map_[specifier] = guid;
832 network->SetGuid(guid);
835 void NetworkStateHandler::NotifyDeviceListChanged() {
836 SCOPED_NET_LOG_IF_SLOW();
837 NET_LOG_DEBUG("NOTIFY:DeviceListChanged",
838 base::StringPrintf("Size:%" PRIuS, device_list_.size()));
839 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
840 DeviceListChanged());
843 DeviceState* NetworkStateHandler::GetModifiableDeviceState(
844 const std::string& device_path) const {
845 ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
846 if (!managed)
847 return nullptr;
848 return managed->AsDeviceState();
851 NetworkState* NetworkStateHandler::GetModifiableNetworkState(
852 const std::string& service_path) const {
853 ManagedState* managed =
854 GetModifiableManagedState(&network_list_, service_path);
855 if (!managed)
856 return nullptr;
857 return managed->AsNetworkState();
860 ManagedState* NetworkStateHandler::GetModifiableManagedState(
861 const ManagedStateList* managed_list,
862 const std::string& path) const {
863 for (ManagedStateList::const_iterator iter = managed_list->begin();
864 iter != managed_list->end(); ++iter) {
865 ManagedState* managed = *iter;
866 if (managed->path() == path)
867 return managed;
869 return nullptr;
872 NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
873 ManagedState::ManagedType type) {
874 switch (type) {
875 case ManagedState::MANAGED_TYPE_NETWORK:
876 return &network_list_;
877 case ManagedState::MANAGED_TYPE_DEVICE:
878 return &device_list_;
880 NOTREACHED();
881 return nullptr;
884 void NetworkStateHandler::OnNetworkConnectionStateChanged(
885 NetworkState* network) {
886 SCOPED_NET_LOG_IF_SLOW();
887 DCHECK(network);
888 bool notify_default = false;
889 if (network->path() == default_network_path_) {
890 if (network->IsConnectedState()) {
891 notify_default = true;
892 } else if (network->IsConnectingState()) {
893 // Wait until the network is actually connected to notify that the default
894 // network changed.
895 NET_LOG(EVENT) << "Default network is not connected: "
896 << GetLogName(network)
897 << "State: " << network->connection_state();
898 } else {
899 NET_LOG(ERROR) << "Default network in unexpected state: "
900 << GetLogName(network)
901 << "State: " << network->connection_state();
902 default_network_path_.clear();
903 SortNetworkList();
904 NotifyDefaultNetworkChanged(nullptr);
907 std::string desc = "NetworkConnectionStateChanged";
908 if (notify_default)
909 desc = "Default" + desc;
910 NET_LOG(EVENT) << "NOTIFY: " << desc << ": " << GetLogName(network) << ": "
911 << network->connection_state();
912 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
913 NetworkConnectionStateChanged(network));
914 if (notify_default)
915 NotifyDefaultNetworkChanged(network);
918 void NetworkStateHandler::NotifyDefaultNetworkChanged(
919 const NetworkState* default_network) {
920 SCOPED_NET_LOG_IF_SLOW();
921 NET_LOG_EVENT("NOTIFY:DefaultNetworkChanged", GetLogName(default_network));
922 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
923 DefaultNetworkChanged(default_network));
926 void NetworkStateHandler::NotifyNetworkPropertiesUpdated(
927 const NetworkState* network) {
928 SCOPED_NET_LOG_IF_SLOW();
929 NET_LOG_DEBUG("NOTIFY:NetworkPropertiesUpdated", GetLogName(network));
930 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
931 NetworkPropertiesUpdated(network));
934 void NetworkStateHandler::NotifyDevicePropertiesUpdated(
935 const DeviceState* device) {
936 SCOPED_NET_LOG_IF_SLOW();
937 NET_LOG_DEBUG("NOTIFY:DevicePropertiesUpdated", GetLogName(device));
938 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
939 DevicePropertiesUpdated(device));
942 void NetworkStateHandler::NotifyScanCompleted(const DeviceState* device) {
943 SCOPED_NET_LOG_IF_SLOW();
944 NET_LOG_DEBUG("NOTIFY:ScanCompleted", GetLogName(device));
945 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
946 ScanCompleted(device));
949 std::string NetworkStateHandler::GetTechnologyForType(
950 const NetworkTypePattern& type) const {
951 if (type.MatchesType(shill::kTypeEthernet))
952 return shill::kTypeEthernet;
954 if (type.MatchesType(shill::kTypeWifi))
955 return shill::kTypeWifi;
957 if (type.Equals(NetworkTypePattern::Wimax()))
958 return shill::kTypeWimax;
960 // Prefer Wimax over Cellular only if it's available.
961 if (type.MatchesType(shill::kTypeWimax) &&
962 shill_property_handler_->IsTechnologyAvailable(shill::kTypeWimax)) {
963 return shill::kTypeWimax;
966 if (type.MatchesType(shill::kTypeCellular))
967 return shill::kTypeCellular;
969 NOTREACHED();
970 return std::string();
973 ScopedVector<std::string> NetworkStateHandler::GetTechnologiesForType(
974 const NetworkTypePattern& type) const {
975 ScopedVector<std::string> technologies;
976 if (type.MatchesType(shill::kTypeEthernet))
977 technologies.push_back(new std::string(shill::kTypeEthernet));
978 if (type.MatchesType(shill::kTypeWifi))
979 technologies.push_back(new std::string(shill::kTypeWifi));
980 if (type.MatchesType(shill::kTypeWimax))
981 technologies.push_back(new std::string(shill::kTypeWimax));
982 if (type.MatchesType(shill::kTypeCellular))
983 technologies.push_back(new std::string(shill::kTypeCellular));
984 if (type.MatchesType(shill::kTypeBluetooth))
985 technologies.push_back(new std::string(shill::kTypeBluetooth));
986 if (type.MatchesType(shill::kTypeVPN))
987 technologies.push_back(new std::string(shill::kTypeVPN));
989 CHECK_GT(technologies.size(), 0ul);
990 return technologies.Pass();
993 } // namespace chromeos