Add default implementations for AppWindowRegistry::Observer notifications.
[chromium-blink-merge.git] / chromeos / network / shill_property_handler.cc
blob8ae24fbb83c1fccca81a2ca9b653b3f2d13e0bad
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/shill_property_handler.h"
7 #include "base/bind.h"
8 #include "base/format_macros.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_ipconfig_client.h"
16 #include "chromeos/dbus/shill_manager_client.h"
17 #include "chromeos/dbus/shill_profile_client.h"
18 #include "chromeos/dbus/shill_service_client.h"
19 #include "chromeos/network/network_event_log.h"
20 #include "chromeos/network/network_state.h"
21 #include "dbus/object_path.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 namespace {
26 // Limit the number of services or devices we observe. Since they are listed in
27 // priority order, it should be reasonable to ignore services past this.
28 const size_t kMaxObserved = 100;
30 const base::ListValue* GetListValue(const std::string& key,
31 const base::Value& value) {
32 const base::ListValue* vlist = NULL;
33 if (!value.GetAsList(&vlist)) {
34 LOG(ERROR) << "Error parsing key as list: " << key;
35 return NULL;
37 return vlist;
40 } // namespace
42 namespace chromeos {
43 namespace internal {
45 // Class to manage Shill service property changed observers. Observers are
46 // added on construction and removed on destruction. Runs the handler when
47 // OnPropertyChanged is called.
48 class ShillPropertyObserver : public ShillPropertyChangedObserver {
49 public:
50 typedef base::Callback<void(ManagedState::ManagedType type,
51 const std::string& service,
52 const std::string& name,
53 const base::Value& value)> Handler;
55 ShillPropertyObserver(ManagedState::ManagedType type,
56 const std::string& path,
57 const Handler& handler)
58 : type_(type),
59 path_(path),
60 handler_(handler) {
61 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
62 DBusThreadManager::Get()->GetShillServiceClient()->
63 AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
64 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
65 DBusThreadManager::Get()->GetShillDeviceClient()->
66 AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
67 } else {
68 NOTREACHED();
72 virtual ~ShillPropertyObserver() {
73 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
74 DBusThreadManager::Get()->GetShillServiceClient()->
75 RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
76 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
77 DBusThreadManager::Get()->GetShillDeviceClient()->
78 RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
79 } else {
80 NOTREACHED();
84 // ShillPropertyChangedObserver overrides.
85 virtual void OnPropertyChanged(const std::string& key,
86 const base::Value& value) OVERRIDE {
87 handler_.Run(type_, path_, key, value);
90 private:
91 ManagedState::ManagedType type_;
92 std::string path_;
93 Handler handler_;
95 DISALLOW_COPY_AND_ASSIGN(ShillPropertyObserver);
98 //------------------------------------------------------------------------------
99 // ShillPropertyHandler
101 ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
102 : listener_(listener),
103 shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {
106 ShillPropertyHandler::~ShillPropertyHandler() {
107 // Delete network service observers.
108 STLDeleteContainerPairSecondPointers(
109 observed_networks_.begin(), observed_networks_.end());
110 STLDeleteContainerPairSecondPointers(
111 observed_devices_.begin(), observed_devices_.end());
112 CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
113 shill_manager_->RemovePropertyChangedObserver(this);
116 void ShillPropertyHandler::Init() {
117 UpdateManagerProperties();
118 shill_manager_->AddPropertyChangedObserver(this);
121 void ShillPropertyHandler::UpdateManagerProperties() {
122 NET_LOG_EVENT("UpdateManagerProperties", "");
123 shill_manager_->GetProperties(
124 base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback,
125 AsWeakPtr()));
128 bool ShillPropertyHandler::IsTechnologyAvailable(
129 const std::string& technology) const {
130 return available_technologies_.count(technology) != 0;
133 bool ShillPropertyHandler::IsTechnologyEnabled(
134 const std::string& technology) const {
135 return enabled_technologies_.count(technology) != 0;
138 bool ShillPropertyHandler::IsTechnologyEnabling(
139 const std::string& technology) const {
140 return enabling_technologies_.count(technology) != 0;
143 bool ShillPropertyHandler::IsTechnologyUninitialized(
144 const std::string& technology) const {
145 return uninitialized_technologies_.count(technology) != 0;
148 void ShillPropertyHandler::SetTechnologyEnabled(
149 const std::string& technology,
150 bool enabled,
151 const network_handler::ErrorCallback& error_callback) {
152 if (enabled) {
153 enabling_technologies_.insert(technology);
154 shill_manager_->EnableTechnology(
155 technology,
156 base::Bind(&base::DoNothing),
157 base::Bind(&ShillPropertyHandler::EnableTechnologyFailed,
158 AsWeakPtr(), technology, error_callback));
159 } else {
160 // Immediately clear locally from enabled and enabling lists.
161 enabled_technologies_.erase(technology);
162 enabling_technologies_.erase(technology);
163 shill_manager_->DisableTechnology(
164 technology,
165 base::Bind(&base::DoNothing),
166 base::Bind(&network_handler::ShillErrorCallbackFunction,
167 "SetTechnologyEnabled Failed",
168 technology, error_callback));
172 void ShillPropertyHandler::SetCheckPortalList(
173 const std::string& check_portal_list) {
174 base::StringValue value(check_portal_list);
175 shill_manager_->SetProperty(
176 shill::kCheckPortalListProperty,
177 value,
178 base::Bind(&base::DoNothing),
179 base::Bind(&network_handler::ShillErrorCallbackFunction,
180 "SetCheckPortalList Failed",
181 "", network_handler::ErrorCallback()));
184 void ShillPropertyHandler::RequestScan() const {
185 shill_manager_->RequestScan(
187 base::Bind(&base::DoNothing),
188 base::Bind(&network_handler::ShillErrorCallbackFunction,
189 "RequestScan Failed",
190 "", network_handler::ErrorCallback()));
193 void ShillPropertyHandler::ConnectToBestServices() const {
194 NET_LOG_EVENT("ConnectToBestServices", "");
195 shill_manager_->ConnectToBestServices(
196 base::Bind(&base::DoNothing),
197 base::Bind(&network_handler::ShillErrorCallbackFunction,
198 "ConnectToBestServices Failed",
199 "", network_handler::ErrorCallback()));
202 void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
203 const std::string& path) {
204 if (pending_updates_[type].find(path) != pending_updates_[type].end())
205 return; // Update already requested.
207 NET_LOG_DEBUG("Request Properties", path);
208 pending_updates_[type].insert(path);
209 if (type == ManagedState::MANAGED_TYPE_NETWORK ||
210 type == ManagedState::MANAGED_TYPE_FAVORITE) {
211 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
212 dbus::ObjectPath(path),
213 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
214 AsWeakPtr(), type, path));
215 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
216 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
217 dbus::ObjectPath(path),
218 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
219 AsWeakPtr(), type, path));
220 } else {
221 NOTREACHED();
225 void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
226 const base::Value& value) {
227 ManagerPropertyChanged(key, value);
228 CheckPendingStateListUpdates(key);
231 //------------------------------------------------------------------------------
232 // Private methods
234 void ShillPropertyHandler::ManagerPropertiesCallback(
235 DBusMethodCallStatus call_status,
236 const base::DictionaryValue& properties) {
237 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
238 NET_LOG_ERROR("ManagerPropertiesCallback",
239 base::StringPrintf("Failed: %d", call_status));
240 return;
242 NET_LOG_EVENT("ManagerPropertiesCallback", "Success");
243 const base::Value* update_service_value = NULL;
244 const base::Value* update_service_complete_value = NULL;
245 for (base::DictionaryValue::Iterator iter(properties);
246 !iter.IsAtEnd(); iter.Advance()) {
247 // Defer updating Services until all other properties have been updated.
248 if (iter.key() == shill::kServicesProperty)
249 update_service_value = &iter.value();
250 else if (iter.key() == shill::kServiceCompleteListProperty)
251 update_service_complete_value = &iter.value();
252 else
253 ManagerPropertyChanged(iter.key(), iter.value());
255 // Update Services which can safely assume other properties have been set.
256 if (update_service_value)
257 ManagerPropertyChanged(shill::kServicesProperty, *update_service_value);
258 // Update ServiceCompleteList which skips entries that have already been
259 // requested for Services.
260 if (update_service_complete_value) {
261 ManagerPropertyChanged(shill::kServiceCompleteListProperty,
262 *update_service_complete_value);
265 CheckPendingStateListUpdates("");
268 void ShillPropertyHandler::CheckPendingStateListUpdates(
269 const std::string& key) {
270 // Once there are no pending updates, signal the state list changed callbacks.
271 if ((key.empty() || key == shill::kServicesProperty) &&
272 pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
273 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
275 // Both Network update requests and Favorite update requests will affect
276 // the list of favorites, so wait for both to complete.
277 if ((key.empty() || key == shill::kServiceCompleteListProperty) &&
278 pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0 &&
279 pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
280 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
282 if ((key.empty() || key == shill::kDevicesProperty) &&
283 pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
284 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
288 void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
289 const base::Value& value) {
290 if (key == shill::kDefaultServiceProperty) {
291 std::string service_path;
292 value.GetAsString(&service_path);
293 listener_->DefaultNetworkServiceChanged(service_path);
294 } else if (key == shill::kServicesProperty) {
295 const base::ListValue* vlist = GetListValue(key, value);
296 if (vlist) {
297 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
298 UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
299 // UpdateObserved used to use kServiceWatchListProperty for TYPE_NETWORK,
300 // however that prevents us from receiving Strength updates from inactive
301 // networks. The overhead for observing all services is not unreasonable
302 // (and we limit the max number of observed services to kMaxObserved).
303 UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
305 } else if (key == shill::kServiceCompleteListProperty) {
306 const base::ListValue* vlist = GetListValue(key, value);
307 if (vlist) {
308 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
309 UpdateProperties(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
311 } else if (key == shill::kDevicesProperty) {
312 const base::ListValue* vlist = GetListValue(key, value);
313 if (vlist) {
314 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
315 UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
316 UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
318 } else if (key == shill::kAvailableTechnologiesProperty) {
319 const base::ListValue* vlist = GetListValue(key, value);
320 if (vlist)
321 UpdateAvailableTechnologies(*vlist);
322 } else if (key == shill::kEnabledTechnologiesProperty) {
323 const base::ListValue* vlist = GetListValue(key, value);
324 if (vlist)
325 UpdateEnabledTechnologies(*vlist);
326 } else if (key == shill::kUninitializedTechnologiesProperty) {
327 const base::ListValue* vlist = GetListValue(key, value);
328 if (vlist)
329 UpdateUninitializedTechnologies(*vlist);
330 } else if (key == shill::kProfilesProperty) {
331 listener_->ProfileListChanged();
332 } else if (key == shill::kCheckPortalListProperty) {
333 std::string check_portal_list;
334 if (value.GetAsString(&check_portal_list))
335 listener_->CheckPortalListChanged(check_portal_list);
336 } else {
337 VLOG(2) << "Ignored Manager Property: " << key;
341 void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
342 const base::ListValue& entries) {
343 std::set<std::string>& requested_updates = requested_updates_[type];
344 std::set<std::string>& requested_service_updates =
345 requested_updates_[ManagedState::MANAGED_TYPE_NETWORK]; // For favorites
346 std::set<std::string> new_requested_updates;
347 NET_LOG_DEBUG(
348 base::StringPrintf("UpdateProperties: %" PRIuS, entries.GetSize()),
349 ManagedState::TypeToString(type));
350 for (base::ListValue::const_iterator iter = entries.begin();
351 iter != entries.end(); ++iter) {
352 std::string path;
353 (*iter)->GetAsString(&path);
354 if (path.empty())
355 continue;
356 if (type == ManagedState::MANAGED_TYPE_FAVORITE &&
357 requested_service_updates.count(path) > 0)
358 continue; // Update already requested
360 // We add a special case for devices here to work around an issue in shill
361 // that prevents it from sending property changed signals for cellular
362 // devices (see crbug.com/321854).
363 if (type == ManagedState::MANAGED_TYPE_DEVICE ||
364 requested_updates.find(path) == requested_updates.end())
365 RequestProperties(type, path);
366 new_requested_updates.insert(path);
368 requested_updates.swap(new_requested_updates);
371 void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
372 const base::ListValue& entries) {
373 DCHECK(type == ManagedState::MANAGED_TYPE_NETWORK ||
374 type == ManagedState::MANAGED_TYPE_DEVICE);
375 ShillPropertyObserverMap& observer_map =
376 (type == ManagedState::MANAGED_TYPE_NETWORK)
377 ? observed_networks_ : observed_devices_;
378 ShillPropertyObserverMap new_observed;
379 for (base::ListValue::const_iterator iter1 = entries.begin();
380 iter1 != entries.end(); ++iter1) {
381 std::string path;
382 (*iter1)->GetAsString(&path);
383 if (path.empty())
384 continue;
385 ShillPropertyObserverMap::iterator iter2 = observer_map.find(path);
386 if (iter2 != observer_map.end()) {
387 new_observed[path] = iter2->second;
388 } else {
389 // Create an observer for future updates.
390 new_observed[path] = new ShillPropertyObserver(
391 type, path, base::Bind(
392 &ShillPropertyHandler::PropertyChangedCallback, AsWeakPtr()));
394 observer_map.erase(path);
395 // Limit the number of observed services.
396 if (new_observed.size() >= kMaxObserved)
397 break;
399 // Delete network service observers still in observer_map.
400 for (ShillPropertyObserverMap::iterator iter = observer_map.begin();
401 iter != observer_map.end(); ++iter) {
402 delete iter->second;
404 observer_map.swap(new_observed);
407 void ShillPropertyHandler::UpdateAvailableTechnologies(
408 const base::ListValue& technologies) {
409 available_technologies_.clear();
410 NET_LOG_EVENT("AvailableTechnologiesChanged",
411 base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
412 for (base::ListValue::const_iterator iter = technologies.begin();
413 iter != technologies.end(); ++iter) {
414 std::string technology;
415 (*iter)->GetAsString(&technology);
416 DCHECK(!technology.empty());
417 available_technologies_.insert(technology);
419 listener_->TechnologyListChanged();
422 void ShillPropertyHandler::UpdateEnabledTechnologies(
423 const base::ListValue& technologies) {
424 enabled_technologies_.clear();
425 NET_LOG_EVENT("EnabledTechnologiesChanged",
426 base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
427 for (base::ListValue::const_iterator iter = technologies.begin();
428 iter != technologies.end(); ++iter) {
429 std::string technology;
430 (*iter)->GetAsString(&technology);
431 DCHECK(!technology.empty());
432 enabled_technologies_.insert(technology);
433 enabling_technologies_.erase(technology);
435 listener_->TechnologyListChanged();
438 void ShillPropertyHandler::UpdateUninitializedTechnologies(
439 const base::ListValue& technologies) {
440 uninitialized_technologies_.clear();
441 NET_LOG_EVENT("UninitializedTechnologiesChanged",
442 base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
443 for (base::ListValue::const_iterator iter = technologies.begin();
444 iter != technologies.end(); ++iter) {
445 std::string technology;
446 (*iter)->GetAsString(&technology);
447 DCHECK(!technology.empty());
448 uninitialized_technologies_.insert(technology);
450 listener_->TechnologyListChanged();
453 void ShillPropertyHandler::EnableTechnologyFailed(
454 const std::string& technology,
455 const network_handler::ErrorCallback& error_callback,
456 const std::string& dbus_error_name,
457 const std::string& dbus_error_message) {
458 enabling_technologies_.erase(technology);
459 network_handler::ShillErrorCallbackFunction(
460 "EnableTechnology Failed",
461 technology, error_callback,
462 dbus_error_name, dbus_error_message);
465 void ShillPropertyHandler::GetPropertiesCallback(
466 ManagedState::ManagedType type,
467 const std::string& path,
468 DBusMethodCallStatus call_status,
469 const base::DictionaryValue& properties) {
470 NET_LOG_DEBUG("GetPropertiesCallback: " + ManagedState::TypeToString(type),
471 path);
472 pending_updates_[type].erase(path);
473 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
474 // The shill service no longer exists. This can happen when a network
475 // has been removed.
476 NET_LOG_DEBUG("Failed to get properties",
477 base::StringPrintf("%s: %d", path.c_str(), call_status));
478 return;
480 // Update Favorite properties for networks in the Services list.
481 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
482 // Only networks with a ProfilePath set are Favorites.
483 std::string profile_path;
484 properties.GetStringWithoutPathExpansion(
485 shill::kProfileProperty, &profile_path);
486 if (!profile_path.empty()) {
487 listener_->UpdateManagedStateProperties(
488 ManagedState::MANAGED_TYPE_FAVORITE, path, properties);
491 listener_->UpdateManagedStateProperties(type, path, properties);
492 // Request IPConfig parameters for networks.
493 if (type == ManagedState::MANAGED_TYPE_NETWORK &&
494 properties.HasKey(shill::kIPConfigProperty)) {
495 std::string ip_config_path;
496 if (properties.GetString(shill::kIPConfigProperty, &ip_config_path)) {
497 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
498 dbus::ObjectPath(ip_config_path),
499 base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
500 AsWeakPtr(), path));
504 // Notify the listener only when all updates for that type have completed.
505 if (pending_updates_[type].size() == 0) {
506 listener_->ManagedStateListChanged(type);
507 // Notify that Favorites have changed when notifying for Networks if there
508 // are no additional Favorite updates pending.
509 if (type == ManagedState::MANAGED_TYPE_NETWORK &&
510 pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
511 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
516 void ShillPropertyHandler::PropertyChangedCallback(
517 ManagedState::ManagedType type,
518 const std::string& path,
519 const std::string& key,
520 const base::Value& value) {
521 if (type == ManagedState::MANAGED_TYPE_NETWORK)
522 NetworkServicePropertyChangedCallback(path, key, value);
523 else if (type == ManagedState::MANAGED_TYPE_DEVICE)
524 NetworkDevicePropertyChangedCallback(path, key, value);
525 else
526 NOTREACHED();
529 void ShillPropertyHandler::NetworkServicePropertyChangedCallback(
530 const std::string& path,
531 const std::string& key,
532 const base::Value& value) {
533 if (key == shill::kIPConfigProperty) {
534 // Request the IPConfig for the network and update network properties
535 // when the request completes.
536 std::string ip_config_path;
537 value.GetAsString(&ip_config_path);
538 DCHECK(!ip_config_path.empty());
539 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
540 dbus::ObjectPath(ip_config_path),
541 base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
542 AsWeakPtr(), path));
543 } else {
544 listener_->UpdateNetworkServiceProperty(path, key, value);
548 void ShillPropertyHandler::GetIPConfigCallback(
549 const std::string& service_path,
550 DBusMethodCallStatus call_status,
551 const base::DictionaryValue& properties) {
552 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
553 NET_LOG_ERROR("Failed to get IP Config properties",
554 base::StringPrintf("%s: %d",
555 service_path.c_str(), call_status));
556 return;
558 UpdateIPConfigProperty(service_path, properties, shill::kAddressProperty);
559 UpdateIPConfigProperty(service_path, properties, shill::kNameServersProperty);
560 UpdateIPConfigProperty(service_path, properties, shill::kPrefixlenProperty);
561 UpdateIPConfigProperty(service_path, properties, shill::kGatewayProperty);
562 UpdateIPConfigProperty(service_path, properties,
563 shill::kWebProxyAutoDiscoveryUrlProperty);
566 void ShillPropertyHandler::UpdateIPConfigProperty(
567 const std::string& service_path,
568 const base::DictionaryValue& properties,
569 const char* property) {
570 const base::Value* value;
571 if (!properties.GetWithoutPathExpansion(property, &value)) {
572 LOG(ERROR) << "Failed to get IPConfig property: " << property
573 << ", for: " << service_path;
574 return;
576 listener_->UpdateNetworkServiceProperty(
577 service_path, NetworkState::IPConfigProperty(property), *value);
580 void ShillPropertyHandler::NetworkDevicePropertyChangedCallback(
581 const std::string& path,
582 const std::string& key,
583 const base::Value& value) {
584 listener_->UpdateDeviceProperty(path, key, value);
587 } // namespace internal
588 } // namespace chromeos