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.
5 #include "chromeos/dbus/fake_shill_device_client.h"
10 #include "base/location.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/values.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "chromeos/dbus/shill_manager_client.h"
17 #include "chromeos/dbus/shill_property_changed_observer.h"
19 #include "dbus/message.h"
20 #include "dbus/object_path.h"
21 #include "dbus/object_proxy.h"
22 #include "dbus/values_util.h"
23 #include "net/base/ip_endpoint.h"
24 #include "third_party/cros_system_api/dbus/service_constants.h"
30 std::string kSimPin
= "1111";
31 std::string kFailedMessage
= "Failed";
33 void ErrorFunction(const std::string
& device_path
,
34 const std::string
& error_name
,
35 const std::string
& error_message
) {
36 LOG(ERROR
) << "Shill Error for: " << device_path
37 << ": " << error_name
<< " : " << error_message
;
40 void PostError(const std::string
& error
,
41 const ShillDeviceClient::ErrorCallback
& error_callback
) {
42 base::ThreadTaskRunnerHandle::Get()->PostTask(
43 FROM_HERE
, base::Bind(error_callback
, error
, kFailedMessage
));
46 void PostNotFoundError(const ShillDeviceClient::ErrorCallback
& error_callback
) {
47 PostError(shill::kErrorResultNotFound
, error_callback
);
50 bool IsReadOnlyProperty(const std::string
& name
) {
51 if (name
== shill::kCarrierProperty
)
58 FakeShillDeviceClient::FakeShillDeviceClient()
59 : initial_tdls_busy_count_(0),
61 weak_ptr_factory_(this) {
64 FakeShillDeviceClient::~FakeShillDeviceClient() {
65 STLDeleteContainerPairSecondPointers(
66 observer_list_
.begin(), observer_list_
.end());
69 // ShillDeviceClient overrides.
71 void FakeShillDeviceClient::Init(dbus::Bus
* bus
) {}
73 void FakeShillDeviceClient::AddPropertyChangedObserver(
74 const dbus::ObjectPath
& device_path
,
75 ShillPropertyChangedObserver
* observer
) {
76 GetObserverList(device_path
).AddObserver(observer
);
79 void FakeShillDeviceClient::RemovePropertyChangedObserver(
80 const dbus::ObjectPath
& device_path
,
81 ShillPropertyChangedObserver
* observer
) {
82 GetObserverList(device_path
).RemoveObserver(observer
);
85 void FakeShillDeviceClient::GetProperties(
86 const dbus::ObjectPath
& device_path
,
87 const DictionaryValueCallback
& callback
) {
88 base::ThreadTaskRunnerHandle::Get()->PostTask(
90 base::Bind(&FakeShillDeviceClient::PassStubDeviceProperties
,
91 weak_ptr_factory_
.GetWeakPtr(), device_path
, callback
));
94 void FakeShillDeviceClient::ProposeScan(
95 const dbus::ObjectPath
& device_path
,
96 const VoidDBusMethodCallback
& callback
) {
97 PostVoidCallback(callback
, DBUS_METHOD_CALL_SUCCESS
);
100 void FakeShillDeviceClient::SetProperty(const dbus::ObjectPath
& device_path
,
101 const std::string
& name
,
102 const base::Value
& value
,
103 const base::Closure
& callback
,
104 const ErrorCallback
& error_callback
) {
105 if (IsReadOnlyProperty(name
))
106 PostError(shill::kErrorResultInvalidArguments
, error_callback
);
107 SetPropertyInternal(device_path
, name
, value
, callback
, error_callback
);
110 void FakeShillDeviceClient::SetPropertyInternal(
111 const dbus::ObjectPath
& device_path
,
112 const std::string
& name
,
113 const base::Value
& value
,
114 const base::Closure
& callback
,
115 const ErrorCallback
& error_callback
) {
116 base::DictionaryValue
* device_properties
= NULL
;
117 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(device_path
.value(),
118 &device_properties
)) {
119 PostNotFoundError(error_callback
);
122 device_properties
->SetWithoutPathExpansion(name
, value
.DeepCopy());
123 base::ThreadTaskRunnerHandle::Get()->PostTask(
125 base::Bind(&FakeShillDeviceClient::NotifyObserversPropertyChanged
,
126 weak_ptr_factory_
.GetWeakPtr(), device_path
, name
));
127 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
130 void FakeShillDeviceClient::ClearProperty(
131 const dbus::ObjectPath
& device_path
,
132 const std::string
& name
,
133 const VoidDBusMethodCallback
& callback
) {
134 base::DictionaryValue
* device_properties
= NULL
;
135 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(device_path
.value(),
136 &device_properties
)) {
137 PostVoidCallback(callback
, DBUS_METHOD_CALL_FAILURE
);
140 device_properties
->RemoveWithoutPathExpansion(name
, NULL
);
141 PostVoidCallback(callback
, DBUS_METHOD_CALL_SUCCESS
);
144 void FakeShillDeviceClient::AddIPConfig(
145 const dbus::ObjectPath
& device_path
,
146 const std::string
& method
,
147 const ObjectPathDBusMethodCallback
& callback
) {
148 base::ThreadTaskRunnerHandle::Get()->PostTask(
150 base::Bind(callback
, DBUS_METHOD_CALL_SUCCESS
, dbus::ObjectPath()));
153 void FakeShillDeviceClient::RequirePin(const dbus::ObjectPath
& device_path
,
154 const std::string
& pin
,
156 const base::Closure
& callback
,
157 const ErrorCallback
& error_callback
) {
158 VLOG(1) << "RequirePin: " << device_path
.value();
159 if (pin
!= kSimPin
) {
160 base::ThreadTaskRunnerHandle::Get()->PostTask(
162 base::Bind(error_callback
, shill::kErrorResultIncorrectPin
, ""));
165 base::DictionaryValue
* device_properties
= NULL
;
166 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(device_path
.value(),
167 &device_properties
)) {
168 PostNotFoundError(error_callback
);
171 base::DictionaryValue
* simlock_dict
= NULL
;
172 if (!device_properties
->GetDictionaryWithoutPathExpansion(
173 shill::kSIMLockStatusProperty
, &simlock_dict
)) {
174 simlock_dict
= new base::DictionaryValue
;
175 device_properties
->SetWithoutPathExpansion(
176 shill::kSIMLockStatusProperty
, simlock_dict
);
178 simlock_dict
->Clear();
179 simlock_dict
->SetBoolean(shill::kSIMLockEnabledProperty
, require
);
180 // TODO(stevenjb): Investigate why non-empty value breaks UI.
181 std::string lock_type
= ""; // shill::kSIMLockPin
182 simlock_dict
->SetString(shill::kSIMLockTypeProperty
, lock_type
);
183 simlock_dict
->SetInteger(shill::kSIMLockRetriesLeftProperty
, 5);
185 NotifyObserversPropertyChanged(device_path
, shill::kSIMLockStatusProperty
);
186 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
189 void FakeShillDeviceClient::EnterPin(const dbus::ObjectPath
& device_path
,
190 const std::string
& pin
,
191 const base::Closure
& callback
,
192 const ErrorCallback
& error_callback
) {
193 VLOG(1) << "EnterPin: " << device_path
.value();
194 if (pin
!= kSimPin
) {
195 base::ThreadTaskRunnerHandle::Get()->PostTask(
197 base::Bind(error_callback
, shill::kErrorResultIncorrectPin
, ""));
200 if (!stub_devices_
.HasKey(device_path
.value())) {
201 PostNotFoundError(error_callback
);
204 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
207 void FakeShillDeviceClient::UnblockPin(const dbus::ObjectPath
& device_path
,
208 const std::string
& puk
,
209 const std::string
& pin
,
210 const base::Closure
& callback
,
211 const ErrorCallback
& error_callback
) {
212 VLOG(1) << "UnblockPin: " << device_path
.value();
213 if (!stub_devices_
.HasKey(device_path
.value())) {
214 PostNotFoundError(error_callback
);
217 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
220 void FakeShillDeviceClient::ChangePin(const dbus::ObjectPath
& device_path
,
221 const std::string
& old_pin
,
222 const std::string
& new_pin
,
223 const base::Closure
& callback
,
224 const ErrorCallback
& error_callback
) {
225 VLOG(1) << "ChangePin: " << device_path
.value();
226 if (!stub_devices_
.HasKey(device_path
.value())) {
227 PostNotFoundError(error_callback
);
230 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
233 void FakeShillDeviceClient::Register(const dbus::ObjectPath
& device_path
,
234 const std::string
& network_id
,
235 const base::Closure
& callback
,
236 const ErrorCallback
& error_callback
) {
237 if (!stub_devices_
.HasKey(device_path
.value())) {
238 PostNotFoundError(error_callback
);
241 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
244 void FakeShillDeviceClient::SetCarrier(const dbus::ObjectPath
& device_path
,
245 const std::string
& carrier
,
246 const base::Closure
& callback
,
247 const ErrorCallback
& error_callback
) {
248 SetPropertyInternal(device_path
, shill::kCarrierProperty
,
249 base::StringValue(carrier
), callback
, error_callback
);
252 void FakeShillDeviceClient::Reset(const dbus::ObjectPath
& device_path
,
253 const base::Closure
& callback
,
254 const ErrorCallback
& error_callback
) {
255 if (!stub_devices_
.HasKey(device_path
.value())) {
256 PostNotFoundError(error_callback
);
259 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
262 void FakeShillDeviceClient::PerformTDLSOperation(
263 const dbus::ObjectPath
& device_path
,
264 const std::string
& operation
,
265 const std::string
& peer
,
266 const StringCallback
& callback
,
267 const ErrorCallback
& error_callback
) {
268 if (!stub_devices_
.HasKey(device_path
.value())) {
269 PostNotFoundError(error_callback
);
272 // Use -1 to emulate a TDLS failure.
273 if (tdls_busy_count_
== -1) {
274 base::ThreadTaskRunnerHandle::Get()->PostTask(
276 base::Bind(error_callback
, shill::kErrorDhcpFailed
, "Failed"));
279 if (operation
!= shill::kTDLSStatusOperation
&& tdls_busy_count_
> 0) {
281 base::ThreadTaskRunnerHandle::Get()->PostTask(
282 FROM_HERE
, base::Bind(error_callback
, shill::kErrorResultInProgress
,
287 tdls_busy_count_
= initial_tdls_busy_count_
;
290 if (operation
== shill::kTDLSDiscoverOperation
) {
291 if (tdls_state_
.empty())
292 tdls_state_
= shill::kTDLSDisconnectedState
;
293 } else if (operation
== shill::kTDLSSetupOperation
) {
294 if (tdls_state_
.empty())
295 tdls_state_
= shill::kTDLSConnectedState
;
296 } else if (operation
== shill::kTDLSTeardownOperation
) {
297 if (tdls_state_
.empty())
298 tdls_state_
= shill::kTDLSDisconnectedState
;
299 } else if (operation
== shill::kTDLSStatusOperation
) {
300 result
= tdls_state_
;
303 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
304 base::Bind(callback
, result
));
307 void FakeShillDeviceClient::AddWakeOnPacketConnection(
308 const dbus::ObjectPath
& device_path
,
309 const net::IPEndPoint
& ip_endpoint
,
310 const base::Closure
& callback
,
311 const ErrorCallback
& error_callback
) {
312 if (!stub_devices_
.HasKey(device_path
.value())) {
313 PostNotFoundError(error_callback
);
317 wake_on_packet_connections_
[device_path
].insert(ip_endpoint
);
319 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
322 void FakeShillDeviceClient::RemoveWakeOnPacketConnection(
323 const dbus::ObjectPath
& device_path
,
324 const net::IPEndPoint
& ip_endpoint
,
325 const base::Closure
& callback
,
326 const ErrorCallback
& error_callback
) {
327 const auto device_iter
= wake_on_packet_connections_
.find(device_path
);
328 if (!stub_devices_
.HasKey(device_path
.value()) ||
329 device_iter
== wake_on_packet_connections_
.end()) {
330 PostNotFoundError(error_callback
);
334 const auto endpoint_iter
= device_iter
->second
.find(ip_endpoint
);
335 if (endpoint_iter
== device_iter
->second
.end()) {
336 PostNotFoundError(error_callback
);
340 device_iter
->second
.erase(endpoint_iter
);
342 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
345 void FakeShillDeviceClient::RemoveAllWakeOnPacketConnections(
346 const dbus::ObjectPath
& device_path
,
347 const base::Closure
& callback
,
348 const ErrorCallback
& error_callback
) {
349 const auto iter
= wake_on_packet_connections_
.find(device_path
);
350 if (!stub_devices_
.HasKey(device_path
.value()) ||
351 iter
== wake_on_packet_connections_
.end()) {
352 PostNotFoundError(error_callback
);
356 wake_on_packet_connections_
.erase(iter
);
358 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
361 ShillDeviceClient::TestInterface
* FakeShillDeviceClient::GetTestInterface() {
365 // ShillDeviceClient::TestInterface overrides.
367 void FakeShillDeviceClient::AddDevice(const std::string
& device_path
,
368 const std::string
& type
,
369 const std::string
& name
) {
370 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
371 AddDevice(device_path
);
373 base::DictionaryValue
* properties
= GetDeviceProperties(device_path
);
374 properties
->SetStringWithoutPathExpansion(shill::kTypeProperty
, type
);
375 properties
->SetStringWithoutPathExpansion(shill::kNameProperty
, name
);
376 properties
->SetStringWithoutPathExpansion(shill::kDBusObjectProperty
,
378 properties
->SetStringWithoutPathExpansion(
379 shill::kDBusServiceProperty
, modemmanager::kModemManager1ServiceName
);
380 if (type
== shill::kTypeCellular
) {
381 properties
->SetBooleanWithoutPathExpansion(
382 shill::kCellularAllowRoamingProperty
, false);
386 void FakeShillDeviceClient::RemoveDevice(const std::string
& device_path
) {
387 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
388 RemoveDevice(device_path
);
390 stub_devices_
.RemoveWithoutPathExpansion(device_path
, NULL
);
393 void FakeShillDeviceClient::ClearDevices() {
394 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
397 stub_devices_
.Clear();
400 void FakeShillDeviceClient::SetDeviceProperty(const std::string
& device_path
,
401 const std::string
& name
,
402 const base::Value
& value
) {
403 VLOG(1) << "SetDeviceProperty: " << device_path
404 << ": " << name
<< " = " << value
;
405 SetPropertyInternal(dbus::ObjectPath(device_path
), name
, value
,
406 base::Bind(&base::DoNothing
),
407 base::Bind(&ErrorFunction
, device_path
));
410 std::string
FakeShillDeviceClient::GetDevicePathForType(
411 const std::string
& type
) {
412 for (base::DictionaryValue::Iterator
iter(stub_devices_
);
413 !iter
.IsAtEnd(); iter
.Advance()) {
414 const base::DictionaryValue
* properties
= NULL
;
415 if (!iter
.value().GetAsDictionary(&properties
))
417 std::string prop_type
;
418 if (!properties
->GetStringWithoutPathExpansion(
419 shill::kTypeProperty
, &prop_type
) ||
424 return std::string();
427 void FakeShillDeviceClient::SetTDLSBusyCount(int count
) {
428 tdls_busy_count_
= std::max(count
, -1);
431 void FakeShillDeviceClient::SetTDLSState(const std::string
& state
) {
435 void FakeShillDeviceClient::PassStubDeviceProperties(
436 const dbus::ObjectPath
& device_path
,
437 const DictionaryValueCallback
& callback
) const {
438 const base::DictionaryValue
* device_properties
= NULL
;
439 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(
440 device_path
.value(), &device_properties
)) {
441 base::DictionaryValue empty_dictionary
;
442 callback
.Run(DBUS_METHOD_CALL_FAILURE
, empty_dictionary
);
445 callback
.Run(DBUS_METHOD_CALL_SUCCESS
, *device_properties
);
448 // Posts a task to run a void callback with status code |status|.
449 void FakeShillDeviceClient::PostVoidCallback(
450 const VoidDBusMethodCallback
& callback
,
451 DBusMethodCallStatus status
) {
452 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
453 base::Bind(callback
, status
));
456 void FakeShillDeviceClient::NotifyObserversPropertyChanged(
457 const dbus::ObjectPath
& device_path
,
458 const std::string
& property
) {
459 base::DictionaryValue
* dict
= NULL
;
460 std::string path
= device_path
.value();
461 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(path
, &dict
)) {
462 LOG(ERROR
) << "Notify for unknown service: " << path
;
465 base::Value
* value
= NULL
;
466 if (!dict
->GetWithoutPathExpansion(property
, &value
)) {
467 LOG(ERROR
) << "Notify for unknown property: "
468 << path
<< " : " << property
;
471 FOR_EACH_OBSERVER(ShillPropertyChangedObserver
,
472 GetObserverList(device_path
),
473 OnPropertyChanged(property
, *value
));
476 base::DictionaryValue
* FakeShillDeviceClient::GetDeviceProperties(
477 const std::string
& device_path
) {
478 base::DictionaryValue
* properties
= NULL
;
479 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(
480 device_path
, &properties
)) {
481 properties
= new base::DictionaryValue
;
482 stub_devices_
.SetWithoutPathExpansion(device_path
, properties
);
487 FakeShillDeviceClient::PropertyObserverList
&
488 FakeShillDeviceClient::GetObserverList(const dbus::ObjectPath
& device_path
) {
489 std::map
<dbus::ObjectPath
, PropertyObserverList
*>::iterator iter
=
490 observer_list_
.find(device_path
);
491 if (iter
!= observer_list_
.end())
492 return *(iter
->second
);
493 PropertyObserverList
* observer_list
= new PropertyObserverList();
494 observer_list_
[device_path
] = observer_list
;
495 return *observer_list
;
498 } // namespace chromeos