Index: chromeos/network/shill_property_handler.cc |
diff --git a/chromeos/network/shill_property_handler.cc b/chromeos/network/shill_property_handler.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9fecfd6d5a09f92e9304d7023b24deabc68889bb |
--- /dev/null |
+++ b/chromeos/network/shill_property_handler.cc |
@@ -0,0 +1,272 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chromeos/network/shill_property_handler.h" |
+ |
+#include "base/bind.h" |
+#include "base/stl_util.h" |
+#include "base/string_util.h" |
+#include "base/values.h" |
+#include "chromeos/dbus/dbus_thread_manager.h" |
+#include "chromeos/dbus/shill_device_client.h" |
+#include "chromeos/dbus/shill_ipconfig_client.h" |
+#include "chromeos/dbus/shill_manager_client.h" |
+#include "chromeos/dbus/shill_service_client.h" |
+#include "chromeos/network/shill_service_observer.h" |
+#include "dbus/object_path.h" |
+#include "third_party/cros_system_api/dbus/service_constants.h" |
+ |
+namespace { |
+ |
+// Limit the number of services we observe. Since they are listed in priority |
+// order, it should be reasonable to ignore services past this. |
+const size_t kMaxObservedServices = 100; |
+ |
+void ErrorCallbackFunction(const std::string& error_name, |
+ const std::string& error_message) { |
+ // TODO(stevenjb): Add error logging. |
+ LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message; |
+} |
+ |
+const base::ListValue* GetListValue(const std::string& key, |
+ const base::Value& value) { |
+ const base::ListValue* vlist = NULL; |
+ if (!value.GetAsList(&vlist)) { |
+ LOG(ERROR) << "Error parsing key as list: " << key; |
+ return NULL; |
+ } |
+ return vlist; |
+} |
+ |
+} // namespace |
+ |
+namespace chromeos { |
+namespace internal { |
+ |
+ShillPropertyHandler::ShillPropertyHandler(Listener* listener) |
+ : listener_(listener), |
+ shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()), |
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
+} |
+ |
+ShillPropertyHandler::~ShillPropertyHandler() { |
+ // Delete network service observers. |
+ STLDeleteContainerPairSecondPointers( |
+ observed_networks_.begin(), observed_networks_.end()); |
+ CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient()); |
+ shill_manager_->RemovePropertyChangedObserver(this); |
+} |
+ |
+void ShillPropertyHandler::Init() { |
+ shill_manager_->GetProperties( |
+ base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ shill_manager_->AddPropertyChangedObserver(this); |
+} |
+ |
+void ShillPropertyHandler::SetTechnologyEnabled( |
+ const std::string& technology, |
+ bool enabled) { |
+ if (enabled) { |
+ shill_manager_->EnableTechnology(technology, |
+ base::Bind(&base::DoNothing), |
+ base::Bind(&ErrorCallbackFunction)); |
+ } else { |
+ shill_manager_->DisableTechnology(technology, |
+ base::Bind(&base::DoNothing), |
+ base::Bind(&ErrorCallbackFunction)); |
+ } |
+} |
+ |
+void ShillPropertyHandler::RequestScan() const { |
+ shill_manager_->RequestScan("", |
+ base::Bind(&base::DoNothing), |
+ base::Bind(&ErrorCallbackFunction)); |
+} |
+ |
+void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type, |
+ const std::string& path) { |
+ ++pending_updates_[type]; |
+ if (type == ManagedState::MANAGED_TYPE_NETWORK) { |
+ DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( |
+ dbus::ObjectPath(path), |
+ base::Bind(&ShillPropertyHandler::GetPropertiesCallback, |
+ weak_ptr_factory_.GetWeakPtr(), type, path)); |
+ } else if (type == ManagedState::MANAGED_TYPE_DEVICE) { |
+ DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties( |
+ dbus::ObjectPath(path), |
+ base::Bind(&ShillPropertyHandler::GetPropertiesCallback, |
+ weak_ptr_factory_.GetWeakPtr(), type, path)); |
+ } else { |
+ NOTREACHED(); |
+ } |
+} |
+ |
+void ShillPropertyHandler::RequestIPConfig( |
+ const std::string& service_path, |
+ const std::string& ip_config_path) { |
+ DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties( |
+ dbus::ObjectPath(ip_config_path), |
+ base::Bind(&ShillPropertyHandler::GetIPConfigCallback, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ service_path)); |
+} |
+ |
+void ShillPropertyHandler::OnPropertyChanged(const std::string& key, |
+ const base::Value& value) { |
+ if (ManagerPropertyChanged(key, value)) |
+ listener_->ManagerPropertyChanged(); |
+} |
+ |
+//------------------------------------------------------------------------------ |
+// Private methods |
+ |
+void ShillPropertyHandler::ManagerPropertiesCallback( |
+ DBusMethodCallStatus call_status, |
+ const base::DictionaryValue& properties) { |
+ if (call_status != DBUS_METHOD_CALL_SUCCESS) { |
+ LOG(ERROR) << "Failed to get Manager properties:" << call_status; |
+ return; |
+ } |
+ bool notify = false; |
+ bool update_service_list = false; |
+ for (base::DictionaryValue::Iterator iter(properties); |
+ iter.HasNext(); iter.Advance()) { |
+ // Defer updating Services until all other properties have been updated. |
+ if (iter.key() == flimflam::kServicesProperty) |
+ update_service_list = true; |
+ else |
+ notify |= ManagerPropertyChanged(iter.key(), iter.value()); |
+ } |
+ // Now update the service list which can safely assume other properties have |
+ // been initially set. |
+ if (update_service_list) { |
+ const base::Value* value = NULL; |
+ if (properties.GetWithoutPathExpansion(flimflam::kServicesProperty, &value)) |
+ notify |= ManagerPropertyChanged(flimflam::kServicesProperty, *value); |
+ } |
+ if (notify) |
+ listener_->ManagerPropertyChanged(); |
+} |
+ |
+bool ShillPropertyHandler::ManagerPropertyChanged(const std::string& key, |
+ const base::Value& value) { |
+ bool notify_manager_changed = false; |
+ if (key == flimflam::kServicesProperty) { |
+ const base::ListValue* vlist = GetListValue(key, value); |
+ if (vlist) |
+ UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist); |
+ } else if (key == flimflam::kServiceWatchListProperty) { |
+ const base::ListValue* vlist = GetListValue(key, value); |
+ if (vlist) { |
+ UpdateObservedNetworkServices(*vlist); |
+ } |
+ } else if (key == flimflam::kDevicesProperty) { |
+ const ListValue* vlist = GetListValue(key, value); |
+ if (vlist) |
+ UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist); |
+ } else if (key == flimflam::kAvailableTechnologiesProperty) { |
+ const base::ListValue* vlist = GetListValue(key, value); |
+ if (vlist ) { |
+ listener_->UpdateAvailableTechnologies(*vlist); |
+ notify_manager_changed = true; |
+ } |
+ } else if (key == flimflam::kEnabledTechnologiesProperty) { |
+ const base::ListValue* vlist = GetListValue(key, value); |
+ if (vlist) { |
+ listener_->UpdateEnabledTechnologies(*vlist); |
+ notify_manager_changed = true; |
+ } |
+ } |
+ return notify_manager_changed; |
+} |
+ |
+void ShillPropertyHandler::UpdateManagedList(ManagedState::ManagedType type, |
+ const base::ListValue& entries) { |
+ listener_->UpdateManagedList(type, entries); |
+ // Do not send a ManagerPropertyChanged notification to the Listener if |
+ // RequestProperties has been called (ManagedStateListChanged will be |
+ // called when the update requests have completed). If no requests |
+ // have been made, call ManagedStateListChanged to indicate that the |
+ // order of the list has changed. |
+ if (pending_updates_[type] == 0) |
+ listener_->ManagedStateListChanged(type); |
+} |
+ |
+void ShillPropertyHandler::UpdateObservedNetworkServices( |
+ const base::ListValue& entries) { |
+ // Watch all networks in the watch list. |
+ ShillServiceObserverMap new_observed; |
+ for (base::ListValue::const_iterator iter1 = entries.begin(); |
+ iter1 != entries.end(); ++iter1) { |
+ std::string path; |
+ (*iter1)->GetAsString(&path); |
+ if (path.empty()) |
+ continue; |
+ ShillServiceObserverMap::iterator iter2 = observed_networks_.find(path); |
+ if (iter2 != observed_networks_.end()) { |
+ new_observed[path] = observed_networks_[path]; |
+ } else { |
+ new_observed[path] = new ShillServiceObserver( |
+ path, base::Bind( |
+ &ShillPropertyHandler::NetworkServicePropertyChangedCallback, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ } |
+ observed_networks_.erase(path); |
+ // Limit the number of observed services. |
+ if (new_observed.size() >= kMaxObservedServices) |
+ break; |
+ } |
+ VLOG(2) << "UpdateObservedNetworkServices, new observed: " |
+ << new_observed.size(); |
+ // Delete network service observers still in observed_networks_. |
+ STLDeleteContainerPairSecondPointers( |
+ observed_networks_.begin(), observed_networks_.end()); |
+ observed_networks_.swap(new_observed); |
+} |
+ |
+void ShillPropertyHandler::GetPropertiesCallback( |
+ ManagedState::ManagedType type, |
+ const std::string& path, |
+ DBusMethodCallStatus call_status, |
+ const base::DictionaryValue& properties) { |
+ VLOG(2) << "GetPropertiesCallback: " << type << " : " << path; |
+ --pending_updates_[type]; |
+ if (call_status != DBUS_METHOD_CALL_SUCCESS) { |
+ LOG(ERROR) << "Failed to get properties for: " << path |
+ << ": " << call_status; |
+ return; |
+ } |
+ listener_->UpdateManagedStateProperties(type, path, properties); |
+ // Notify the listener only when all updates for that type have completed. |
+ if (pending_updates_[type] == 0) |
+ listener_->ManagedStateListChanged(type); |
+} |
+ |
+void ShillPropertyHandler::NetworkServicePropertyChangedCallback( |
+ const std::string& path, |
+ const std::string& key, |
+ const base::Value& value) { |
+ listener_->UpdateNetworkServiceProperty(path, key, value); |
+} |
+ |
+void ShillPropertyHandler::GetIPConfigCallback( |
+ const std::string& service_path, |
+ DBusMethodCallStatus call_status, |
+ const base::DictionaryValue& properties) { |
+ if (call_status != DBUS_METHOD_CALL_SUCCESS) { |
+ LOG(ERROR) << "Failed to get IP properties for: " << service_path; |
+ return; |
+ } |
+ std::string ip_address; |
+ if (!properties.GetStringWithoutPathExpansion(flimflam::kAddressProperty, |
+ &ip_address)) { |
+ LOG(ERROR) << "Failed to get IP Address property for: " << service_path; |
+ return; |
+ } |
+ listener_->UpdateNetworkServiceIPAddress(service_path, ip_address); |
+} |
+ |
+} // namespace internal |
+} // namespace chromeos |