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/dbus/shill_device_client.h"
8 #include "base/message_loop.h"
9 #include "base/stl_util.h"
10 #include "base/values.h"
11 #include "chromeos/dbus/shill_property_changed_observer.h"
13 #include "dbus/message.h"
14 #include "dbus/object_path.h"
15 #include "dbus/object_proxy.h"
16 #include "dbus/values_util.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
23 // The ShillDeviceClient implementation.
24 class ShillDeviceClientImpl
: public ShillDeviceClient
{
26 explicit ShillDeviceClientImpl(dbus::Bus
* bus
)
28 helpers_deleter_(&helpers_
) {
31 ///////////////////////////////////////
32 // ShillDeviceClient overrides.
33 virtual void AddPropertyChangedObserver(
34 const dbus::ObjectPath
& device_path
,
35 ShillPropertyChangedObserver
* observer
) OVERRIDE
{
36 GetHelper(device_path
)->AddPropertyChangedObserver(observer
);
39 virtual void RemovePropertyChangedObserver(
40 const dbus::ObjectPath
& device_path
,
41 ShillPropertyChangedObserver
* observer
) OVERRIDE
{
42 GetHelper(device_path
)->RemovePropertyChangedObserver(observer
);
45 virtual void GetProperties(const dbus::ObjectPath
& device_path
,
46 const DictionaryValueCallback
& callback
) OVERRIDE
{
47 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
48 flimflam::kGetPropertiesFunction
);
49 GetHelper(device_path
)->CallDictionaryValueMethod(&method_call
, callback
);
52 virtual base::DictionaryValue
* CallGetPropertiesAndBlock(
53 const dbus::ObjectPath
& device_path
) OVERRIDE
{
54 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
55 flimflam::kGetPropertiesFunction
);
56 return GetHelper(device_path
)->CallDictionaryValueMethodAndBlock(
60 virtual void ProposeScan(const dbus::ObjectPath
& device_path
,
61 const VoidDBusMethodCallback
& callback
) OVERRIDE
{
62 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
63 flimflam::kProposeScanFunction
);
64 GetHelper(device_path
)->CallVoidMethod(&method_call
, callback
);
67 virtual void SetProperty(const dbus::ObjectPath
& device_path
,
68 const std::string
& name
,
69 const base::Value
& value
,
70 const base::Closure
& callback
,
71 const ErrorCallback
& error_callback
) OVERRIDE
{
72 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
73 flimflam::kSetPropertyFunction
);
74 dbus::MessageWriter
writer(&method_call
);
75 writer
.AppendString(name
);
76 ShillClientHelper::AppendValueDataAsVariant(&writer
, value
);
77 GetHelper(device_path
)->CallVoidMethodWithErrorCallback(&method_call
,
82 virtual void ClearProperty(const dbus::ObjectPath
& device_path
,
83 const std::string
& name
,
84 const VoidDBusMethodCallback
& callback
) OVERRIDE
{
85 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
86 flimflam::kClearPropertyFunction
);
87 dbus::MessageWriter
writer(&method_call
);
88 writer
.AppendString(name
);
89 GetHelper(device_path
)->CallVoidMethod(&method_call
, callback
);
92 virtual void AddIPConfig(
93 const dbus::ObjectPath
& device_path
,
94 const std::string
& method
,
95 const ObjectPathDBusMethodCallback
& callback
) OVERRIDE
{
96 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
97 flimflam::kAddIPConfigFunction
);
98 dbus::MessageWriter
writer(&method_call
);
99 writer
.AppendString(method
);
100 GetHelper(device_path
)->CallObjectPathMethod(&method_call
, callback
);
103 virtual void RequirePin(const dbus::ObjectPath
& device_path
,
104 const std::string
& pin
,
106 const base::Closure
& callback
,
107 const ErrorCallback
& error_callback
) OVERRIDE
{
108 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
109 flimflam::kRequirePinFunction
);
110 dbus::MessageWriter
writer(&method_call
);
111 writer
.AppendString(pin
);
112 writer
.AppendBool(require
);
113 GetHelper(device_path
)->CallVoidMethodWithErrorCallback(
114 &method_call
, callback
, error_callback
);
117 virtual void EnterPin(const dbus::ObjectPath
& device_path
,
118 const std::string
& pin
,
119 const base::Closure
& callback
,
120 const ErrorCallback
& error_callback
) OVERRIDE
{
121 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
122 flimflam::kEnterPinFunction
);
123 dbus::MessageWriter
writer(&method_call
);
124 writer
.AppendString(pin
);
125 GetHelper(device_path
)->CallVoidMethodWithErrorCallback(
126 &method_call
, callback
, error_callback
);
129 virtual void UnblockPin(const dbus::ObjectPath
& device_path
,
130 const std::string
& puk
,
131 const std::string
& pin
,
132 const base::Closure
& callback
,
133 const ErrorCallback
& error_callback
) OVERRIDE
{
134 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
135 flimflam::kUnblockPinFunction
);
136 dbus::MessageWriter
writer(&method_call
);
137 writer
.AppendString(puk
);
138 writer
.AppendString(pin
);
139 GetHelper(device_path
)->CallVoidMethodWithErrorCallback(
140 &method_call
, callback
, error_callback
);
143 virtual void ChangePin(const dbus::ObjectPath
& device_path
,
144 const std::string
& old_pin
,
145 const std::string
& new_pin
,
146 const base::Closure
& callback
,
147 const ErrorCallback
& error_callback
) OVERRIDE
{
148 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
149 flimflam::kChangePinFunction
);
150 dbus::MessageWriter
writer(&method_call
);
151 writer
.AppendString(old_pin
);
152 writer
.AppendString(new_pin
);
153 GetHelper(device_path
)->CallVoidMethodWithErrorCallback(
154 &method_call
, callback
, error_callback
);
157 virtual void Register(const dbus::ObjectPath
& device_path
,
158 const std::string
& network_id
,
159 const base::Closure
& callback
,
160 const ErrorCallback
& error_callback
) OVERRIDE
{
161 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
162 flimflam::kRegisterFunction
);
163 dbus::MessageWriter
writer(&method_call
);
164 writer
.AppendString(network_id
);
165 GetHelper(device_path
)->CallVoidMethodWithErrorCallback(
166 &method_call
, callback
, error_callback
);
169 virtual void SetCarrier(const dbus::ObjectPath
& device_path
,
170 const std::string
& carrier
,
171 const base::Closure
& callback
,
172 const ErrorCallback
& error_callback
) OVERRIDE
{
173 dbus::MethodCall
method_call(flimflam::kFlimflamDeviceInterface
,
174 shill::kSetCarrierFunction
);
175 dbus::MessageWriter
writer(&method_call
);
176 writer
.AppendString(carrier
);
177 GetHelper(device_path
)->CallVoidMethodWithErrorCallback(
178 &method_call
, callback
, error_callback
);
181 virtual TestInterface
* GetTestInterface() OVERRIDE
{
186 typedef std::map
<std::string
, ShillClientHelper
*> HelperMap
;
188 // Returns the corresponding ShillClientHelper for the profile.
189 ShillClientHelper
* GetHelper(const dbus::ObjectPath
& device_path
) {
190 HelperMap::iterator it
= helpers_
.find(device_path
.value());
191 if (it
!= helpers_
.end())
194 // There is no helper for the profile, create it.
195 dbus::ObjectProxy
* object_proxy
=
196 bus_
->GetObjectProxy(flimflam::kFlimflamServiceName
, device_path
);
197 ShillClientHelper
* helper
= new ShillClientHelper(bus_
, object_proxy
);
198 helper
->MonitorPropertyChanged(flimflam::kFlimflamDeviceInterface
);
199 helpers_
.insert(HelperMap::value_type(device_path
.value(), helper
));
205 STLValueDeleter
<HelperMap
> helpers_deleter_
;
207 DISALLOW_COPY_AND_ASSIGN(ShillDeviceClientImpl
);
210 // A stub implementation of ShillDeviceClient.
211 // Implemented: Stub cellular device for SMS testing.
212 class ShillDeviceClientStubImpl
: public ShillDeviceClient
,
213 public ShillDeviceClient::TestInterface
{
215 ShillDeviceClientStubImpl() : weak_ptr_factory_(this) {
216 SetDefaultProperties();
219 virtual ~ShillDeviceClientStubImpl() {
220 STLDeleteContainerPairSecondPointers(
221 observer_list_
.begin(), observer_list_
.end());
224 // ShillDeviceClient overrides.
226 virtual void AddPropertyChangedObserver(
227 const dbus::ObjectPath
& device_path
,
228 ShillPropertyChangedObserver
* observer
) OVERRIDE
{
229 GetObserverList(device_path
).AddObserver(observer
);
232 virtual void RemovePropertyChangedObserver(
233 const dbus::ObjectPath
& device_path
,
234 ShillPropertyChangedObserver
* observer
) OVERRIDE
{
235 GetObserverList(device_path
).RemoveObserver(observer
);
238 virtual void GetProperties(const dbus::ObjectPath
& device_path
,
239 const DictionaryValueCallback
& callback
) OVERRIDE
{
240 MessageLoop::current()->PostTask(
242 base::Bind(&ShillDeviceClientStubImpl::PassStubDeviceProperties
,
243 weak_ptr_factory_
.GetWeakPtr(),
244 device_path
, callback
));
247 virtual base::DictionaryValue
* CallGetPropertiesAndBlock(
248 const dbus::ObjectPath
& device_path
) OVERRIDE
{
249 base::DictionaryValue
* device_properties
= NULL
;
250 stub_devices_
.GetDictionaryWithoutPathExpansion(
251 device_path
.value(), &device_properties
);
252 return device_properties
;
255 virtual void ProposeScan(const dbus::ObjectPath
& device_path
,
256 const VoidDBusMethodCallback
& callback
) OVERRIDE
{
257 PostVoidCallback(callback
, DBUS_METHOD_CALL_SUCCESS
);
260 virtual void SetProperty(const dbus::ObjectPath
& device_path
,
261 const std::string
& name
,
262 const base::Value
& value
,
263 const base::Closure
& callback
,
264 const ErrorCallback
& error_callback
) OVERRIDE
{
265 base::DictionaryValue
* device_properties
= NULL
;
266 if (!stub_devices_
.GetDictionary(device_path
.value(), &device_properties
)) {
267 std::string
error_name("org.chromium.flimflam.Error.Failure");
268 std::string
error_message("Failed");
269 MessageLoop::current()->PostTask(FROM_HERE
,
270 base::Bind(error_callback
,
275 device_properties
->Set(name
, value
.DeepCopy());
276 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
277 MessageLoop::current()->PostTask(
279 base::Bind(&ShillDeviceClientStubImpl::NotifyObserversPropertyChanged
,
280 weak_ptr_factory_
.GetWeakPtr(), device_path
, name
));
283 virtual void ClearProperty(const dbus::ObjectPath
& device_path
,
284 const std::string
& name
,
285 const VoidDBusMethodCallback
& callback
) OVERRIDE
{
286 base::DictionaryValue
* device_properties
= NULL
;
287 if (!stub_devices_
.GetDictionary(device_path
.value(), &device_properties
)) {
288 PostVoidCallback(callback
, DBUS_METHOD_CALL_FAILURE
);
291 device_properties
->Remove(name
, NULL
);
292 PostVoidCallback(callback
, DBUS_METHOD_CALL_SUCCESS
);
295 virtual void AddIPConfig(
296 const dbus::ObjectPath
& device_path
,
297 const std::string
& method
,
298 const ObjectPathDBusMethodCallback
& callback
) OVERRIDE
{
299 MessageLoop::current()->PostTask(FROM_HERE
,
301 DBUS_METHOD_CALL_SUCCESS
,
302 dbus::ObjectPath()));
305 virtual void RequirePin(const dbus::ObjectPath
& device_path
,
306 const std::string
& pin
,
308 const base::Closure
& callback
,
309 const ErrorCallback
& error_callback
) OVERRIDE
{
310 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
313 virtual void EnterPin(const dbus::ObjectPath
& device_path
,
314 const std::string
& pin
,
315 const base::Closure
& callback
,
316 const ErrorCallback
& error_callback
) OVERRIDE
{
317 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
320 virtual void UnblockPin(const dbus::ObjectPath
& device_path
,
321 const std::string
& puk
,
322 const std::string
& pin
,
323 const base::Closure
& callback
,
324 const ErrorCallback
& error_callback
) OVERRIDE
{
325 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
328 virtual void ChangePin(const dbus::ObjectPath
& device_path
,
329 const std::string
& old_pin
,
330 const std::string
& new_pin
,
331 const base::Closure
& callback
,
332 const ErrorCallback
& error_callback
) OVERRIDE
{
333 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
336 virtual void Register(const dbus::ObjectPath
& device_path
,
337 const std::string
& network_id
,
338 const base::Closure
& callback
,
339 const ErrorCallback
& error_callback
) OVERRIDE
{
340 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
343 virtual void SetCarrier(const dbus::ObjectPath
& device_path
,
344 const std::string
& carrier
,
345 const base::Closure
& callback
,
346 const ErrorCallback
& error_callback
) OVERRIDE
{
347 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
350 virtual ShillDeviceClient::TestInterface
* GetTestInterface() OVERRIDE
{
354 // ShillDeviceClient::TestInterface overrides.
356 virtual void AddDevice(const std::string
& device_path
,
357 const std::string
& type
,
358 const std::string
& object_path
,
359 const std::string
& connection_path
) OVERRIDE
{
360 base::DictionaryValue
* properties
= GetDeviceProperties(device_path
);
361 properties
->SetWithoutPathExpansion(
362 flimflam::kTypeProperty
,
363 base::Value::CreateStringValue(type
));
364 properties
->SetWithoutPathExpansion(
365 flimflam::kDBusObjectProperty
,
366 base::Value::CreateStringValue(object_path
));
367 properties
->SetWithoutPathExpansion(
368 flimflam::kDBusConnectionProperty
,
369 base::Value::CreateStringValue(connection_path
));
372 virtual void RemoveDevice(const std::string
& device_path
) OVERRIDE
{
373 stub_devices_
.RemoveWithoutPathExpansion(device_path
, NULL
);
376 virtual void ClearDevices() OVERRIDE
{
377 stub_devices_
.Clear();
381 typedef ObserverList
<ShillPropertyChangedObserver
> PropertyObserverList
;
383 void SetDefaultProperties() {
384 // Add a wifi device. Note: path matches Manager entry.
385 AddDevice("stub_wifi_device1", flimflam::kTypeWifi
,
386 "/device/wifi1", "/stub");
388 // Add a cellular device. Used in SMS stub. Note: path matches
390 AddDevice("stub_cellular_device1", flimflam::kTypeCellular
,
391 "/device/cellular1", "/stub");
394 void PassStubDeviceProperties(const dbus::ObjectPath
& device_path
,
395 const DictionaryValueCallback
& callback
) const {
396 const base::DictionaryValue
* device_properties
= NULL
;
397 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(
398 device_path
.value(), &device_properties
)) {
399 base::DictionaryValue empty_dictionary
;
400 callback
.Run(DBUS_METHOD_CALL_FAILURE
, empty_dictionary
);
403 callback
.Run(DBUS_METHOD_CALL_SUCCESS
, *device_properties
);
406 // Posts a task to run a void callback with status code |status|.
407 void PostVoidCallback(const VoidDBusMethodCallback
& callback
,
408 DBusMethodCallStatus status
) {
409 MessageLoop::current()->PostTask(FROM_HERE
,
410 base::Bind(callback
, status
));
413 void NotifyObserversPropertyChanged(const dbus::ObjectPath
& device_path
,
414 const std::string
& property
) {
415 base::DictionaryValue
* dict
= NULL
;
416 std::string path
= device_path
.value();
417 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(path
, &dict
)) {
418 LOG(ERROR
) << "Notify for unknown service: " << path
;
421 base::Value
* value
= NULL
;
422 if (!dict
->GetWithoutPathExpansion(property
, &value
)) {
423 LOG(ERROR
) << "Notify for unknown property: "
424 << path
<< " : " << property
;
427 FOR_EACH_OBSERVER(ShillPropertyChangedObserver
,
428 GetObserverList(device_path
),
429 OnPropertyChanged(property
, *value
));
432 base::DictionaryValue
* GetDeviceProperties(const std::string
& device_path
) {
433 base::DictionaryValue
* properties
= NULL
;
434 if (!stub_devices_
.GetDictionaryWithoutPathExpansion(
435 device_path
, &properties
)) {
436 properties
= new base::DictionaryValue
;
437 stub_devices_
.Set(device_path
, properties
);
442 PropertyObserverList
& GetObserverList(const dbus::ObjectPath
& device_path
) {
443 std::map
<dbus::ObjectPath
, PropertyObserverList
*>::iterator iter
=
444 observer_list_
.find(device_path
);
445 if (iter
!= observer_list_
.end())
446 return *(iter
->second
);
447 PropertyObserverList
* observer_list
= new PropertyObserverList();
448 observer_list_
[device_path
] = observer_list
;
449 return *observer_list
;
452 // Dictionary of <device_name, Dictionary>.
453 base::DictionaryValue stub_devices_
;
454 // Observer list for each device.
455 std::map
<dbus::ObjectPath
, PropertyObserverList
*> observer_list_
;
457 // Note: This should remain the last member so it'll be destroyed and
458 // invalidate its weak pointers before any other members are destroyed.
459 base::WeakPtrFactory
<ShillDeviceClientStubImpl
> weak_ptr_factory_
;
461 DISALLOW_COPY_AND_ASSIGN(ShillDeviceClientStubImpl
);
466 ShillDeviceClient::ShillDeviceClient() {}
468 ShillDeviceClient::~ShillDeviceClient() {}
471 ShillDeviceClient
* ShillDeviceClient::Create(
472 DBusClientImplementationType type
,
474 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
475 return new ShillDeviceClientImpl(bus
);
476 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
477 return new ShillDeviceClientStubImpl();
480 } // namespace chromeos