shill_property_handler.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/shill_property_handler.h" 6 7#include "base/bind.h" 8#include "base/stl_util.h" 9#include "base/string_util.h" 10#include "base/values.h" 11#include "chromeos/dbus/dbus_thread_manager.h" 12#include "chromeos/dbus/shill_device_client.h" 13#include "chromeos/dbus/shill_ipconfig_client.h" 14#include "chromeos/dbus/shill_manager_client.h" 15#include "chromeos/dbus/shill_service_client.h" 16#include "chromeos/network/shill_service_observer.h" 17#include "dbus/object_path.h" 18#include "third_party/cros_system_api/dbus/service_constants.h" 19 20namespace { 21 22// Limit the number of services we observe. Since they are listed in priority 23// order, it should be reasonable to ignore services past this. 24const size_t kMaxObservedServices = 100; 25 26void ErrorCallbackFunction(const std::string& error_name, 27 const std::string& error_message) { 28 // TODO(stevenjb): Add error logging. 29 LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message; 30} 31 32const base::ListValue* GetListValue(const std::string& key, 33 const base::Value& value) { 34 const base::ListValue* vlist = NULL; 35 if (!value.GetAsList(&vlist)) { 36 LOG(ERROR) << "Error parsing key as list: " << key; 37 return NULL; 38 } 39 return vlist; 40} 41 42} // namespace 43 44namespace chromeos { 45namespace internal { 46 47ShillPropertyHandler::ShillPropertyHandler(Listener* listener) 48 : listener_(listener), 49 shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()), 50 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { 51} 52 53ShillPropertyHandler::~ShillPropertyHandler() { 54 // Delete network service observers. 55 STLDeleteContainerPairSecondPointers( 56 observed_networks_.begin(), observed_networks_.end()); 57 CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient()); 58 shill_manager_->RemovePropertyChangedObserver(this); 59} 60 61void ShillPropertyHandler::Init() { 62 shill_manager_->GetProperties( 63 base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback, 64 weak_ptr_factory_.GetWeakPtr())); 65 shill_manager_->AddPropertyChangedObserver(this); 66} 67 68void ShillPropertyHandler::SetTechnologyEnabled( 69 const std::string& technology, 70 bool enabled) { 71 if (enabled) { 72 shill_manager_->EnableTechnology(technology, 73 base::Bind(&base::DoNothing), 74 base::Bind(&ErrorCallbackFunction)); 75 } else { 76 shill_manager_->DisableTechnology(technology, 77 base::Bind(&base::DoNothing), 78 base::Bind(&ErrorCallbackFunction)); 79 } 80} 81 82void ShillPropertyHandler::RequestScan() const { 83 shill_manager_->RequestScan("", 84 base::Bind(&base::DoNothing), 85 base::Bind(&ErrorCallbackFunction)); 86} 87 88void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type, 89 const std::string& path) { 90 ++pending_updates_[type]; 91 if (type == ManagedState::MANAGED_TYPE_NETWORK) { 92 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( 93 dbus::ObjectPath(path), 94 base::Bind(&ShillPropertyHandler::GetPropertiesCallback, 95 weak_ptr_factory_.GetWeakPtr(), type, path)); 96 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) { 97 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties( 98 dbus::ObjectPath(path), 99 base::Bind(&ShillPropertyHandler::GetPropertiesCallback, 100 weak_ptr_factory_.GetWeakPtr(), type, path)); 101 } else { 102 NOTREACHED(); 103 } 104} 105 106void ShillPropertyHandler::RequestIPConfig( 107 const std::string& service_path, 108 const std::string& ip_config_path) { 109 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties( 110 dbus::ObjectPath(ip_config_path), 111 base::Bind(&ShillPropertyHandler::GetIPConfigCallback, 112 weak_ptr_factory_.GetWeakPtr(), 113 service_path)); 114} 115 116void ShillPropertyHandler::OnPropertyChanged(const std::string& key, 117 const base::Value& value) { 118 if (ManagerPropertyChanged(key, value)) 119 listener_->ManagerPropertyChanged(); 120} 121 122//------------------------------------------------------------------------------ 123// Private methods 124 125void ShillPropertyHandler::ManagerPropertiesCallback( 126 DBusMethodCallStatus call_status, 127 const base::DictionaryValue& properties) { 128 if (call_status != DBUS_METHOD_CALL_SUCCESS) { 129 LOG(ERROR) << "Failed to get Manager properties:" << call_status; 130 return; 131 } 132 bool notify = false; 133 bool update_service_list = false; 134 for (base::DictionaryValue::Iterator iter(properties); 135 iter.HasNext(); iter.Advance()) { 136 // Defer updating Services until all other properties have been updated. 137 if (iter.key() == flimflam::kServicesProperty) 138 update_service_list = true; 139 else 140 notify |= ManagerPropertyChanged(iter.key(), iter.value()); 141 } 142 // Now update the service list which can safely assume other properties have 143 // been initially set. 144 if (update_service_list) { 145 const base::Value* value = NULL; 146 if (properties.GetWithoutPathExpansion(flimflam::kServicesProperty, &value)) 147 notify |= ManagerPropertyChanged(flimflam::kServicesProperty, *value); 148 } 149 if (notify) 150 listener_->ManagerPropertyChanged(); 151} 152 153bool ShillPropertyHandler::ManagerPropertyChanged(const std::string& key, 154 const base::Value& value) { 155 bool notify_manager_changed = false; 156 if (key == flimflam::kServicesProperty) { 157 const base::ListValue* vlist = GetListValue(key, value); 158 if (vlist) 159 UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist); 160 } else if (key == flimflam::kServiceWatchListProperty) { 161 const base::ListValue* vlist = GetListValue(key, value); 162 if (vlist) { 163 UpdateObservedNetworkServices(*vlist); 164 } 165 } else if (key == flimflam::kDevicesProperty) { 166 const ListValue* vlist = GetListValue(key, value); 167 if (vlist) 168 UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist); 169 } else if (key == flimflam::kAvailableTechnologiesProperty) { 170 const base::ListValue* vlist = GetListValue(key, value); 171 if (vlist ) { 172 listener_->UpdateAvailableTechnologies(*vlist); 173 notify_manager_changed = true; 174 } 175 } else if (key == flimflam::kEnabledTechnologiesProperty) { 176 const base::ListValue* vlist = GetListValue(key, value); 177 if (vlist) { 178 listener_->UpdateEnabledTechnologies(*vlist); 179 notify_manager_changed = true; 180 } 181 } 182 return notify_manager_changed; 183} 184 185void ShillPropertyHandler::UpdateManagedList(ManagedState::ManagedType type, 186 const base::ListValue& entries) { 187 listener_->UpdateManagedList(type, entries); 188 // Do not send a ManagerPropertyChanged notification to the Listener if 189 // RequestProperties has been called (ManagedStateListChanged will be 190 // called when the update requests have completed). If no requests 191 // have been made, call ManagedStateListChanged to indicate that the 192 // order of the list has changed. 193 if (pending_updates_[type] == 0) 194 listener_->ManagedStateListChanged(type); 195} 196 197void ShillPropertyHandler::UpdateObservedNetworkServices( 198 const base::ListValue& entries) { 199 // Watch all networks in the watch list. 200 ShillServiceObserverMap new_observed; 201 for (base::ListValue::const_iterator iter1 = entries.begin(); 202 iter1 != entries.end(); ++iter1) { 203 std::string path; 204 (*iter1)->GetAsString(&path); 205 if (path.empty()) 206 continue; 207 ShillServiceObserverMap::iterator iter2 = observed_networks_.find(path); 208 if (iter2 != observed_networks_.end()) { 209 new_observed[path] = observed_networks_[path]; 210 } else { 211 new_observed[path] = new ShillServiceObserver( 212 path, base::Bind( 213 &ShillPropertyHandler::NetworkServicePropertyChangedCallback, 214 weak_ptr_factory_.GetWeakPtr())); 215 } 216 observed_networks_.erase(path); 217 // Limit the number of observed services. 218 if (new_observed.size() >= kMaxObservedServices) 219 break; 220 } 221 VLOG(2) << "UpdateObservedNetworkServices, new observed: " 222 << new_observed.size(); 223 // Delete network service observers still in observed_networks_. 224 STLDeleteContainerPairSecondPointers( 225 observed_networks_.begin(), observed_networks_.end()); 226 observed_networks_.swap(new_observed); 227} 228 229void ShillPropertyHandler::GetPropertiesCallback( 230 ManagedState::ManagedType type, 231 const std::string& path, 232 DBusMethodCallStatus call_status, 233 const base::DictionaryValue& properties) { 234 VLOG(2) << "GetPropertiesCallback: " << type << " : " << path; 235 --pending_updates_[type]; 236 if (call_status != DBUS_METHOD_CALL_SUCCESS) { 237 LOG(ERROR) << "Failed to get properties for: " << path 238 << ": " << call_status; 239 return; 240 } 241 listener_->UpdateManagedStateProperties(type, path, properties); 242 // Notify the listener only when all updates for that type have completed. 243 if (pending_updates_[type] == 0) 244 listener_->ManagedStateListChanged(type); 245} 246 247void ShillPropertyHandler::NetworkServicePropertyChangedCallback( 248 const std::string& path, 249 const std::string& key, 250 const base::Value& value) { 251 listener_->UpdateNetworkServiceProperty(path, key, value); 252} 253 254void ShillPropertyHandler::GetIPConfigCallback( 255 const std::string& service_path, 256 DBusMethodCallStatus call_status, 257 const base::DictionaryValue& properties) { 258 if (call_status != DBUS_METHOD_CALL_SUCCESS) { 259 LOG(ERROR) << "Failed to get IP properties for: " << service_path; 260 return; 261 } 262 std::string ip_address; 263 if (!properties.GetStringWithoutPathExpansion(flimflam::kAddressProperty, 264 &ip_address)) { 265 LOG(ERROR) << "Failed to get IP Address property for: " << service_path; 266 return; 267 } 268 listener_->UpdateNetworkServiceIPAddress(service_path, ip_address); 269} 270 271} // namespace internal 272} // namespace chromeos 273