1// Copyright 2013 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/dbus/fake_shill_device_client.h" 6 7#include "base/bind.h" 8#include "base/message_loop/message_loop.h" 9#include "base/stl_util.h" 10#include "base/values.h" 11#include "chromeos/dbus/dbus_thread_manager.h" 12#include "chromeos/dbus/shill_manager_client.h" 13#include "chromeos/dbus/shill_property_changed_observer.h" 14#include "dbus/bus.h" 15#include "dbus/message.h" 16#include "dbus/object_path.h" 17#include "dbus/object_proxy.h" 18#include "dbus/values_util.h" 19#include "third_party/cros_system_api/dbus/service_constants.h" 20 21namespace chromeos { 22 23namespace { 24 25std::string kSimPin = "1111"; 26 27void ErrorFunction(const std::string& device_path, 28 const std::string& error_name, 29 const std::string& error_message) { 30 LOG(ERROR) << "Shill Error for: " << device_path 31 << ": " << error_name << " : " << error_message; 32} 33 34void PostDeviceNotFoundError( 35 const ShillDeviceClient::ErrorCallback& error_callback) { 36 std::string error_message("Failed"); 37 base::MessageLoop::current()->PostTask( 38 FROM_HERE, 39 base::Bind(error_callback, shill::kErrorResultNotFound, error_message)); 40} 41 42} // namespace 43 44FakeShillDeviceClient::FakeShillDeviceClient() 45 : tdls_busy_count_(0), 46 weak_ptr_factory_(this) { 47} 48 49FakeShillDeviceClient::~FakeShillDeviceClient() { 50 STLDeleteContainerPairSecondPointers( 51 observer_list_.begin(), observer_list_.end()); 52} 53 54// ShillDeviceClient overrides. 55 56void FakeShillDeviceClient::Init(dbus::Bus* bus) {} 57 58void FakeShillDeviceClient::AddPropertyChangedObserver( 59 const dbus::ObjectPath& device_path, 60 ShillPropertyChangedObserver* observer) { 61 GetObserverList(device_path).AddObserver(observer); 62} 63 64void FakeShillDeviceClient::RemovePropertyChangedObserver( 65 const dbus::ObjectPath& device_path, 66 ShillPropertyChangedObserver* observer) { 67 GetObserverList(device_path).RemoveObserver(observer); 68} 69 70void FakeShillDeviceClient::GetProperties( 71 const dbus::ObjectPath& device_path, 72 const DictionaryValueCallback& callback) { 73 base::MessageLoop::current()->PostTask( 74 FROM_HERE, 75 base::Bind(&FakeShillDeviceClient::PassStubDeviceProperties, 76 weak_ptr_factory_.GetWeakPtr(), 77 device_path, callback)); 78} 79 80void FakeShillDeviceClient::ProposeScan( 81 const dbus::ObjectPath& device_path, 82 const VoidDBusMethodCallback& callback) { 83 PostVoidCallback(callback, DBUS_METHOD_CALL_SUCCESS); 84} 85 86void FakeShillDeviceClient::SetProperty(const dbus::ObjectPath& device_path, 87 const std::string& name, 88 const base::Value& value, 89 const base::Closure& callback, 90 const ErrorCallback& error_callback) { 91 base::DictionaryValue* device_properties = NULL; 92 if (!stub_devices_.GetDictionaryWithoutPathExpansion(device_path.value(), 93 &device_properties)) { 94 PostDeviceNotFoundError(error_callback); 95 return; 96 } 97 device_properties->SetWithoutPathExpansion(name, value.DeepCopy()); 98 base::MessageLoop::current()->PostTask( 99 FROM_HERE, 100 base::Bind(&FakeShillDeviceClient::NotifyObserversPropertyChanged, 101 weak_ptr_factory_.GetWeakPtr(), device_path, name)); 102 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 103} 104 105void FakeShillDeviceClient::ClearProperty( 106 const dbus::ObjectPath& device_path, 107 const std::string& name, 108 const VoidDBusMethodCallback& callback) { 109 base::DictionaryValue* device_properties = NULL; 110 if (!stub_devices_.GetDictionaryWithoutPathExpansion(device_path.value(), 111 &device_properties)) { 112 PostVoidCallback(callback, DBUS_METHOD_CALL_FAILURE); 113 return; 114 } 115 device_properties->RemoveWithoutPathExpansion(name, NULL); 116 PostVoidCallback(callback, DBUS_METHOD_CALL_SUCCESS); 117} 118 119void FakeShillDeviceClient::AddIPConfig( 120 const dbus::ObjectPath& device_path, 121 const std::string& method, 122 const ObjectPathDBusMethodCallback& callback) { 123 base::MessageLoop::current()->PostTask(FROM_HERE, 124 base::Bind(callback, 125 DBUS_METHOD_CALL_SUCCESS, 126 dbus::ObjectPath())); 127} 128 129void FakeShillDeviceClient::RequirePin(const dbus::ObjectPath& device_path, 130 const std::string& pin, 131 bool require, 132 const base::Closure& callback, 133 const ErrorCallback& error_callback) { 134 VLOG(1) << "RequirePin: " << device_path.value(); 135 if (pin != kSimPin) { 136 base::MessageLoop::current()->PostTask( 137 FROM_HERE, 138 base::Bind(error_callback, shill::kErrorResultIncorrectPin, "")); 139 return; 140 } 141 base::DictionaryValue* device_properties = NULL; 142 if (!stub_devices_.GetDictionaryWithoutPathExpansion(device_path.value(), 143 &device_properties)) { 144 PostDeviceNotFoundError(error_callback); 145 return; 146 } 147 base::DictionaryValue* simlock_dict = NULL; 148 if (!device_properties->GetDictionaryWithoutPathExpansion( 149 shill::kSIMLockStatusProperty, &simlock_dict)) { 150 simlock_dict = new base::DictionaryValue; 151 device_properties->SetWithoutPathExpansion( 152 shill::kSIMLockStatusProperty, simlock_dict); 153 } 154 simlock_dict->Clear(); 155 simlock_dict->SetBoolean(shill::kSIMLockEnabledProperty, require); 156 // TODO(stevenjb): Investigate why non-empty value breaks UI. 157 std::string lock_type = ""; // shill::kSIMLockPin 158 simlock_dict->SetString(shill::kSIMLockTypeProperty, lock_type); 159 simlock_dict->SetInteger(shill::kSIMLockRetriesLeftProperty, 5); 160 161 NotifyObserversPropertyChanged(device_path, shill::kSIMLockStatusProperty); 162 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 163} 164 165void FakeShillDeviceClient::EnterPin(const dbus::ObjectPath& device_path, 166 const std::string& pin, 167 const base::Closure& callback, 168 const ErrorCallback& error_callback) { 169 VLOG(1) << "EnterPin: " << device_path.value(); 170 if (pin != kSimPin) { 171 base::MessageLoop::current()->PostTask( 172 FROM_HERE, 173 base::Bind(error_callback, shill::kErrorResultIncorrectPin, "")); 174 return; 175 } 176 if (!stub_devices_.HasKey(device_path.value())) { 177 PostDeviceNotFoundError(error_callback); 178 return; 179 } 180 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 181} 182 183void FakeShillDeviceClient::UnblockPin(const dbus::ObjectPath& device_path, 184 const std::string& puk, 185 const std::string& pin, 186 const base::Closure& callback, 187 const ErrorCallback& error_callback) { 188 VLOG(1) << "UnblockPin: " << device_path.value(); 189 if (!stub_devices_.HasKey(device_path.value())) { 190 PostDeviceNotFoundError(error_callback); 191 return; 192 } 193 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 194} 195 196void FakeShillDeviceClient::ChangePin(const dbus::ObjectPath& device_path, 197 const std::string& old_pin, 198 const std::string& new_pin, 199 const base::Closure& callback, 200 const ErrorCallback& error_callback) { 201 VLOG(1) << "ChangePin: " << device_path.value(); 202 if (!stub_devices_.HasKey(device_path.value())) { 203 PostDeviceNotFoundError(error_callback); 204 return; 205 } 206 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 207} 208 209void FakeShillDeviceClient::Register(const dbus::ObjectPath& device_path, 210 const std::string& network_id, 211 const base::Closure& callback, 212 const ErrorCallback& error_callback) { 213 if (!stub_devices_.HasKey(device_path.value())) { 214 PostDeviceNotFoundError(error_callback); 215 return; 216 } 217 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 218} 219 220void FakeShillDeviceClient::SetCarrier(const dbus::ObjectPath& device_path, 221 const std::string& carrier, 222 const base::Closure& callback, 223 const ErrorCallback& error_callback) { 224 if (!stub_devices_.HasKey(device_path.value())) { 225 PostDeviceNotFoundError(error_callback); 226 return; 227 } 228 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 229} 230 231void FakeShillDeviceClient::Reset(const dbus::ObjectPath& device_path, 232 const base::Closure& callback, 233 const ErrorCallback& error_callback) { 234 if (!stub_devices_.HasKey(device_path.value())) { 235 PostDeviceNotFoundError(error_callback); 236 return; 237 } 238 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 239} 240 241void FakeShillDeviceClient::PerformTDLSOperation( 242 const dbus::ObjectPath& device_path, 243 const std::string& operation, 244 const std::string& peer, 245 const StringCallback& callback, 246 const ErrorCallback& error_callback) { 247 if (!stub_devices_.HasKey(device_path.value())) { 248 PostDeviceNotFoundError(error_callback); 249 return; 250 } 251 if (tdls_busy_count_) { 252 --tdls_busy_count_; 253 std::string error_message("In-Progress"); 254 base::MessageLoop::current()->PostTask( 255 FROM_HERE, 256 base::Bind(error_callback, 257 shill::kErrorResultInProgress, error_message)); 258 return; 259 } 260 std::string result; 261 if (operation == shill::kTDLSStatusOperation) 262 result = shill::kTDLSConnectedState; 263 base::MessageLoop::current()->PostTask(FROM_HERE, 264 base::Bind(callback, result)); 265} 266 267ShillDeviceClient::TestInterface* FakeShillDeviceClient::GetTestInterface() { 268 return this; 269} 270 271// ShillDeviceClient::TestInterface overrides. 272 273void FakeShillDeviceClient::AddDevice(const std::string& device_path, 274 const std::string& type, 275 const std::string& name) { 276 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()-> 277 AddDevice(device_path); 278 279 base::DictionaryValue* properties = GetDeviceProperties(device_path); 280 properties->SetStringWithoutPathExpansion(shill::kTypeProperty, type); 281 properties->SetStringWithoutPathExpansion(shill::kNameProperty, name); 282 properties->SetStringWithoutPathExpansion(shill::kDBusObjectProperty, 283 device_path); 284 properties->SetStringWithoutPathExpansion( 285 shill::kDBusServiceProperty, modemmanager::kModemManager1ServiceName); 286 if (type == shill::kTypeCellular) { 287 properties->SetBooleanWithoutPathExpansion( 288 shill::kCellularAllowRoamingProperty, false); 289 } 290} 291 292void FakeShillDeviceClient::RemoveDevice(const std::string& device_path) { 293 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()-> 294 RemoveDevice(device_path); 295 296 stub_devices_.RemoveWithoutPathExpansion(device_path, NULL); 297} 298 299void FakeShillDeviceClient::ClearDevices() { 300 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()-> 301 ClearDevices(); 302 303 stub_devices_.Clear(); 304} 305 306void FakeShillDeviceClient::SetDeviceProperty(const std::string& device_path, 307 const std::string& name, 308 const base::Value& value) { 309 VLOG(1) << "SetDeviceProperty: " << device_path 310 << ": " << name << " = " << value; 311 SetProperty(dbus::ObjectPath(device_path), name, value, 312 base::Bind(&base::DoNothing), 313 base::Bind(&ErrorFunction, device_path)); 314} 315 316std::string FakeShillDeviceClient::GetDevicePathForType( 317 const std::string& type) { 318 for (base::DictionaryValue::Iterator iter(stub_devices_); 319 !iter.IsAtEnd(); iter.Advance()) { 320 const base::DictionaryValue* properties = NULL; 321 if (!iter.value().GetAsDictionary(&properties)) 322 continue; 323 std::string prop_type; 324 if (!properties->GetStringWithoutPathExpansion( 325 shill::kTypeProperty, &prop_type) || 326 prop_type != type) 327 continue; 328 return iter.key(); 329 } 330 return std::string(); 331} 332 333void FakeShillDeviceClient::PassStubDeviceProperties( 334 const dbus::ObjectPath& device_path, 335 const DictionaryValueCallback& callback) const { 336 const base::DictionaryValue* device_properties = NULL; 337 if (!stub_devices_.GetDictionaryWithoutPathExpansion( 338 device_path.value(), &device_properties)) { 339 base::DictionaryValue empty_dictionary; 340 callback.Run(DBUS_METHOD_CALL_FAILURE, empty_dictionary); 341 return; 342 } 343 callback.Run(DBUS_METHOD_CALL_SUCCESS, *device_properties); 344} 345 346// Posts a task to run a void callback with status code |status|. 347void FakeShillDeviceClient::PostVoidCallback( 348 const VoidDBusMethodCallback& callback, 349 DBusMethodCallStatus status) { 350 base::MessageLoop::current()->PostTask(FROM_HERE, 351 base::Bind(callback, status)); 352} 353 354void FakeShillDeviceClient::NotifyObserversPropertyChanged( 355 const dbus::ObjectPath& device_path, 356 const std::string& property) { 357 base::DictionaryValue* dict = NULL; 358 std::string path = device_path.value(); 359 if (!stub_devices_.GetDictionaryWithoutPathExpansion(path, &dict)) { 360 LOG(ERROR) << "Notify for unknown service: " << path; 361 return; 362 } 363 base::Value* value = NULL; 364 if (!dict->GetWithoutPathExpansion(property, &value)) { 365 LOG(ERROR) << "Notify for unknown property: " 366 << path << " : " << property; 367 return; 368 } 369 FOR_EACH_OBSERVER(ShillPropertyChangedObserver, 370 GetObserverList(device_path), 371 OnPropertyChanged(property, *value)); 372} 373 374base::DictionaryValue* FakeShillDeviceClient::GetDeviceProperties( 375 const std::string& device_path) { 376 base::DictionaryValue* properties = NULL; 377 if (!stub_devices_.GetDictionaryWithoutPathExpansion( 378 device_path, &properties)) { 379 properties = new base::DictionaryValue; 380 stub_devices_.SetWithoutPathExpansion(device_path, properties); 381 } 382 return properties; 383} 384 385FakeShillDeviceClient::PropertyObserverList& 386FakeShillDeviceClient::GetObserverList(const dbus::ObjectPath& device_path) { 387 std::map<dbus::ObjectPath, PropertyObserverList*>::iterator iter = 388 observer_list_.find(device_path); 389 if (iter != observer_list_.end()) 390 return *(iter->second); 391 PropertyObserverList* observer_list = new PropertyObserverList(); 392 observer_list_[device_path] = observer_list; 393 return *observer_list; 394} 395 396} // namespace chromeos 397