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/bluetooth_device_client.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/stl_util.h"
13 #include "chromeos/dbus/bluetooth_adapter_client.h"
14 #include "chromeos/dbus/bluetooth_property.h"
16 #include "dbus/message.h"
17 #include "dbus/object_path.h"
18 #include "dbus/object_proxy.h"
19 #include "third_party/cros_system_api/dbus/service_constants.h"
23 BluetoothDeviceClient::Properties::Properties(
24 dbus::ObjectProxy
* object_proxy
,
25 const PropertyChangedCallback
& callback
)
26 : BluetoothPropertySet(object_proxy
,
27 bluetooth_device::kBluetoothDeviceInterface
,
29 RegisterProperty(bluetooth_device::kAddressProperty
, &address
);
30 RegisterProperty(bluetooth_device::kNameProperty
, &name
);
31 RegisterProperty(bluetooth_device::kVendorProperty
, &vendor
);
32 RegisterProperty(bluetooth_device::kProductProperty
, &product
);
33 RegisterProperty(bluetooth_device::kVersionProperty
, &version
);
34 RegisterProperty(bluetooth_device::kIconProperty
, &icon
);
35 RegisterProperty(bluetooth_device::kClassProperty
, &bluetooth_class
);
36 RegisterProperty(bluetooth_device::kUUIDsProperty
, &uuids
);
37 RegisterProperty(bluetooth_device::kServicesProperty
, &services
);
38 RegisterProperty(bluetooth_device::kPairedProperty
, &paired
);
39 RegisterProperty(bluetooth_device::kConnectedProperty
, &connected
);
40 RegisterProperty(bluetooth_device::kTrustedProperty
, &trusted
);
41 RegisterProperty(bluetooth_device::kBlockedProperty
, &blocked
);
42 RegisterProperty(bluetooth_device::kAliasProperty
, &alias
);
43 RegisterProperty(bluetooth_device::kNodesProperty
, &nodes
);
44 RegisterProperty(bluetooth_device::kAdapterProperty
, &adapter
);
45 RegisterProperty(bluetooth_device::kLegacyPairingProperty
, &legacy_pairing
);
48 BluetoothDeviceClient::Properties::~Properties() {
52 // The BluetoothDeviceClient implementation used in production.
53 class BluetoothDeviceClientImpl
: public BluetoothDeviceClient
,
54 private BluetoothAdapterClient::Observer
{
56 BluetoothDeviceClientImpl(dbus::Bus
* bus
,
57 BluetoothAdapterClient
* adapter_client
)
59 weak_ptr_factory_(this) {
60 VLOG(1) << "Creating BluetoothDeviceClientImpl";
62 DCHECK(adapter_client
);
63 adapter_client
->AddObserver(this);
66 virtual ~BluetoothDeviceClientImpl() {
67 // Clean up Properties structures
68 for (ObjectMap::iterator iter
= object_map_
.begin();
69 iter
!= object_map_
.end(); ++iter
) {
70 Object object
= iter
->second
;
71 Properties
* properties
= object
.second
;
76 // BluetoothDeviceClient override.
77 virtual void AddObserver(BluetoothDeviceClient::Observer
* observer
)
80 observers_
.AddObserver(observer
);
83 // BluetoothDeviceClient override.
84 virtual void RemoveObserver(BluetoothDeviceClient::Observer
* observer
)
87 observers_
.RemoveObserver(observer
);
90 // BluetoothDeviceClient override.
91 virtual Properties
* GetProperties(const dbus::ObjectPath
& object_path
)
93 return GetObject(object_path
).second
;
96 // BluetoothDeviceClient override.
97 virtual void DiscoverServices(const dbus::ObjectPath
& object_path
,
98 const std::string
& pattern
,
99 const ServicesCallback
& callback
) OVERRIDE
{
100 dbus::MethodCall
method_call(
101 bluetooth_device::kBluetoothDeviceInterface
,
102 bluetooth_device::kDiscoverServices
);
104 dbus::MessageWriter
writer(&method_call
);
105 writer
.AppendString(pattern
);
107 dbus::ObjectProxy
* object_proxy
= GetObjectProxy(object_path
);
109 object_proxy
->CallMethod(
111 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
112 base::Bind(&BluetoothDeviceClientImpl::OnDiscoverServices
,
113 weak_ptr_factory_
.GetWeakPtr(), object_path
, callback
));
116 // BluetoothDeviceClient override.
117 virtual void CancelDiscovery(const dbus::ObjectPath
& object_path
,
118 const DeviceCallback
& callback
) OVERRIDE
{
119 dbus::MethodCall
method_call(
120 bluetooth_device::kBluetoothDeviceInterface
,
121 bluetooth_device::kCancelDiscovery
);
123 dbus::ObjectProxy
* object_proxy
= GetObjectProxy(object_path
);
125 object_proxy
->CallMethod(
127 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
128 base::Bind(&BluetoothDeviceClientImpl::OnCancelDiscovery
,
129 weak_ptr_factory_
.GetWeakPtr(), object_path
, callback
));
132 // BluetoothDeviceClient override.
133 virtual void Disconnect(const dbus::ObjectPath
& object_path
,
134 const DeviceCallback
& callback
) OVERRIDE
{
135 dbus::MethodCall
method_call(
136 bluetooth_device::kBluetoothDeviceInterface
,
137 bluetooth_device::kDisconnect
);
139 dbus::ObjectProxy
* object_proxy
= GetObjectProxy(object_path
);
141 object_proxy
->CallMethod(
143 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
144 base::Bind(&BluetoothDeviceClientImpl::OnDisconnect
,
145 weak_ptr_factory_
.GetWeakPtr(), object_path
, callback
));
148 // BluetoothDeviceClient override.
149 virtual void CreateNode(const dbus::ObjectPath
& object_path
,
150 const std::string
& uuid
,
151 const NodeCallback
& callback
) OVERRIDE
{
152 dbus::MethodCall
method_call(
153 bluetooth_device::kBluetoothDeviceInterface
,
154 bluetooth_device::kCreateNode
);
156 dbus::MessageWriter
writer(&method_call
);
157 writer
.AppendString(uuid
);
159 dbus::ObjectProxy
* object_proxy
= GetObjectProxy(object_path
);
161 object_proxy
->CallMethod(
163 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
164 base::Bind(&BluetoothDeviceClientImpl::OnCreateNode
,
165 weak_ptr_factory_
.GetWeakPtr(), object_path
, callback
));
168 // BluetoothDeviceClient override.
169 virtual void RemoveNode(const dbus::ObjectPath
& object_path
,
170 const dbus::ObjectPath
& node_path
,
171 const DeviceCallback
& callback
) OVERRIDE
{
172 dbus::MethodCall
method_call(
173 bluetooth_device::kBluetoothDeviceInterface
,
174 bluetooth_device::kRemoveNode
);
176 dbus::MessageWriter
writer(&method_call
);
177 writer
.AppendObjectPath(node_path
);
179 dbus::ObjectProxy
* object_proxy
= GetObjectProxy(object_path
);
181 object_proxy
->CallMethod(
183 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
184 base::Bind(&BluetoothDeviceClientImpl::OnRemoveNode
,
185 weak_ptr_factory_
.GetWeakPtr(), object_path
, callback
));
189 // We maintain a collection of dbus object proxies and properties structures
191 typedef std::pair
<dbus::ObjectProxy
*, Properties
*> Object
;
192 typedef std::map
<const dbus::ObjectPath
, Object
> ObjectMap
;
193 ObjectMap object_map_
;
195 // BluetoothAdapterClient::Observer override.
196 virtual void DeviceCreated(const dbus::ObjectPath
& adapter_path
,
197 const dbus::ObjectPath
& object_path
) OVERRIDE
{
200 // BluetoothAdapterClient::Observer override.
201 virtual void DeviceRemoved(const dbus::ObjectPath
& adapter_path
,
202 const dbus::ObjectPath
& object_path
) OVERRIDE
{
203 RemoveObject(object_path
);
206 // Ensures that we have an object proxy and properties structure for
207 // a device with object path |object_path|, creating it if not and
208 // storing it in our |object_map_| map.
209 Object
GetObject(const dbus::ObjectPath
& object_path
) {
210 ObjectMap::iterator iter
= object_map_
.find(object_path
);
211 if (iter
!= object_map_
.end())
214 // Create the object proxy.
216 dbus::ObjectProxy
* object_proxy
= bus_
->GetObjectProxy(
217 bluetooth_device::kBluetoothDeviceServiceName
, object_path
);
219 object_proxy
->ConnectToSignal(
220 bluetooth_device::kBluetoothDeviceInterface
,
221 bluetooth_device::kDisconnectRequestedSignal
,
222 base::Bind(&BluetoothDeviceClientImpl::DisconnectRequestedReceived
,
223 weak_ptr_factory_
.GetWeakPtr(), object_path
),
224 base::Bind(&BluetoothDeviceClientImpl::DisconnectRequestedConnected
,
225 weak_ptr_factory_
.GetWeakPtr(), object_path
));
227 object_proxy
->ConnectToSignal(
228 bluetooth_device::kBluetoothDeviceInterface
,
229 bluetooth_device::kNodeCreatedSignal
,
230 base::Bind(&BluetoothDeviceClientImpl::NodeCreatedReceived
,
231 weak_ptr_factory_
.GetWeakPtr(), object_path
),
232 base::Bind(&BluetoothDeviceClientImpl::NodeCreatedConnected
,
233 weak_ptr_factory_
.GetWeakPtr(), object_path
));
235 object_proxy
->ConnectToSignal(
236 bluetooth_device::kBluetoothDeviceInterface
,
237 bluetooth_device::kNodeRemovedSignal
,
238 base::Bind(&BluetoothDeviceClientImpl::NodeRemovedReceived
,
239 weak_ptr_factory_
.GetWeakPtr(), object_path
),
240 base::Bind(&BluetoothDeviceClientImpl::NodeRemovedConnected
,
241 weak_ptr_factory_
.GetWeakPtr(), object_path
));
243 // Create the properties structure.
244 Properties
* properties
= new Properties(
246 base::Bind(&BluetoothDeviceClientImpl::OnPropertyChanged
,
247 weak_ptr_factory_
.GetWeakPtr(), object_path
));
249 properties
->ConnectSignals();
250 properties
->GetAll();
252 Object object
= std::make_pair(object_proxy
, properties
);
253 object_map_
[object_path
] = object
;
257 // Removes the dbus object proxy and properties for the device with
258 // dbus object path |object_path| from our |object_map_| map.
259 void RemoveObject(const dbus::ObjectPath
& object_path
) {
260 ObjectMap::iterator iter
= object_map_
.find(object_path
);
261 if (iter
!= object_map_
.end()) {
262 // Clean up the Properties structure.
263 Object object
= iter
->second
;
264 Properties
* properties
= object
.second
;
267 object_map_
.erase(iter
);
271 // Returns a pointer to the object proxy for |object_path|, creating
273 dbus::ObjectProxy
* GetObjectProxy(const dbus::ObjectPath
& object_path
) {
274 return GetObject(object_path
).first
;
277 // Called by BluetoothPropertySet when a property value is changed,
278 // either by result of a signal or response to a GetAll() or Get()
279 // call. Informs observers.
280 void OnPropertyChanged(const dbus::ObjectPath
& object_path
,
281 const std::string
& property_name
) {
282 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer
, observers_
,
283 DevicePropertyChanged(object_path
, property_name
));
286 // Called by dbus:: when a DisconnectRequested signal is received.
287 void DisconnectRequestedReceived(const dbus::ObjectPath
& object_path
,
288 dbus::Signal
* signal
) {
291 VLOG(1) << object_path
.value() << ": Disconnect requested.";
292 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer
, observers_
,
293 DisconnectRequested(object_path
));
296 // Called by dbus:: when the DisconnectRequested signal is initially
298 void DisconnectRequestedConnected(const dbus::ObjectPath
& object_path
,
299 const std::string
& interface_name
,
300 const std::string
& signal_name
,
302 LOG_IF(WARNING
, !success
) << object_path
.value()
303 << ": Failed to connect to "
304 "DisconnectRequested signal.";
307 // Called by dbus:: when a NodeCreated signal is received.
308 void NodeCreatedReceived(const dbus::ObjectPath
& object_path
,
309 dbus::Signal
* signal
) {
311 dbus::MessageReader
reader(signal
);
312 dbus::ObjectPath node_path
;
313 if (!reader
.PopObjectPath(&node_path
)) {
314 LOG(WARNING
) << object_path
.value()
315 << ": NodeCreated signal has incorrect parameters: "
316 << signal
->ToString();
320 VLOG(1) << object_path
.value() << ": Node created: "
321 << node_path
.value();
322 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer
, observers_
,
323 NodeCreated(object_path
, node_path
));
326 // Called by dbus:: when the NodeCreated signal is initially connected.
327 void NodeCreatedConnected(const dbus::ObjectPath
& object_path
,
328 const std::string
& interface_name
,
329 const std::string
& signal_name
,
331 LOG_IF(WARNING
, !success
) << object_path
.value()
332 << ": Failed to connect to NodeCreated signal.";
335 // Called by dbus:: when a NodeRemoved signal is received.
336 void NodeRemovedReceived(const dbus::ObjectPath
& object_path
,
337 dbus::Signal
* signal
) {
339 dbus::MessageReader
reader(signal
);
340 dbus::ObjectPath node_path
;
341 if (!reader
.PopObjectPath(&node_path
)) {
342 LOG(WARNING
) << object_path
.value()
343 << ": NodeRemoved signal has incorrect parameters: "
344 << signal
->ToString();
348 VLOG(1) << object_path
.value() << ": Node removed: "
349 << node_path
.value();
350 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer
, observers_
,
351 NodeRemoved(object_path
, node_path
));
354 // Called by dbus:: when the NodeRemoved signal is initially connected.
355 void NodeRemovedConnected(const dbus::ObjectPath
& object_path
,
356 const std::string
& interface_name
,
357 const std::string
& signal_name
,
359 LOG_IF(WARNING
, !success
) << object_path
.value()
360 << ": Failed to connect to NodeRemoved signal.";
363 // Called when a response for DiscoverServices() is received.
364 void OnDiscoverServices(const dbus::ObjectPath
& object_path
,
365 const ServicesCallback
& callback
,
366 dbus::Response
* response
) {
368 bool success
= false;
370 if (response
!= NULL
) {
371 dbus::MessageReader
reader(response
);
373 dbus::MessageReader
array_reader(NULL
);
374 if (!reader
.PopArray(&array_reader
)) {
375 LOG(WARNING
) << "DiscoverServices response has incorrect parameters: "
376 << response
->ToString();
378 while (array_reader
.HasMoreData()) {
379 dbus::MessageReader
dict_entry_reader(NULL
);
382 if (!array_reader
.PopDictEntry(&dict_entry_reader
)
383 || !dict_entry_reader
.PopUint32(&key
)
384 || !dict_entry_reader
.PopString(&value
)) {
385 LOG(WARNING
) << "DiscoverServices response has "
386 "incorrect parameters: " << response
->ToString();
388 services
[key
] = value
;
395 LOG(WARNING
) << "Failed to discover services.";
399 callback
.Run(object_path
, services
, success
);
402 // Called when a response for CancelDiscovery() is received.
403 void OnCancelDiscovery(const dbus::ObjectPath
& object_path
,
404 const DeviceCallback
& callback
,
405 dbus::Response
* response
) {
406 LOG_IF(WARNING
, !response
) << object_path
.value()
407 << ": OnCancelDiscovery: failed.";
408 callback
.Run(object_path
, response
);
411 // Called when a response for Disconnect() is received.
412 void OnDisconnect(const dbus::ObjectPath
& object_path
,
413 const DeviceCallback
& callback
,
414 dbus::Response
* response
) {
415 LOG_IF(WARNING
, !response
) << object_path
.value()
416 << ": OnDisconnect: failed.";
417 callback
.Run(object_path
, response
);
420 // Called when a response for CreateNode() is received.
421 void OnCreateNode(const dbus::ObjectPath
& object_path
,
422 const NodeCallback
& callback
,
423 dbus::Response
* response
) {
425 bool success
= false;
426 dbus::ObjectPath node_path
;
427 if (response
!= NULL
) {
428 dbus::MessageReader
reader(response
);
429 if (!reader
.PopObjectPath(&node_path
)) {
430 LOG(WARNING
) << "CreateNode response has incorrect parameters: "
431 << response
->ToString();
436 LOG(WARNING
) << "Failed to create node.";
440 callback
.Run(node_path
, success
);
443 // Called when a response for RemoveNode() is received.
444 void OnRemoveNode(const dbus::ObjectPath
& object_path
,
445 const DeviceCallback
& callback
,
446 dbus::Response
* response
) {
447 LOG_IF(WARNING
, !response
) << object_path
.value()
448 << ": OnRemoveNode: failed.";
449 callback
.Run(object_path
, response
);
454 // List of observers interested in event notifications from us.
455 ObserverList
<BluetoothDeviceClient::Observer
> observers_
;
457 // Weak pointer factory for generating 'this' pointers that might live longer
459 // Note: This should remain the last member so it'll be destroyed and
460 // invalidate its weak pointers before any other members are destroyed.
461 base::WeakPtrFactory
<BluetoothDeviceClientImpl
> weak_ptr_factory_
;
463 DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceClientImpl
);
466 // The BluetoothDeviceClient implementation used on Linux desktop, which does
468 class BluetoothDeviceClientStubImpl
: public BluetoothDeviceClient
{
470 struct Properties
: public BluetoothDeviceClient::Properties
{
471 explicit Properties(const PropertyChangedCallback
& callback
)
472 : BluetoothDeviceClient::Properties(NULL
, callback
) {
475 virtual ~Properties() {
478 virtual void Get(dbus::PropertyBase
* property
,
479 dbus::PropertySet::GetCallback callback
) OVERRIDE
{
480 VLOG(1) << "Get " << property
->name();
484 virtual void GetAll() OVERRIDE
{
488 virtual void Set(dbus::PropertyBase
*property
,
489 dbus::PropertySet::SetCallback callback
) OVERRIDE
{
490 VLOG(1) << "Set " << property
->name();
495 BluetoothDeviceClientStubImpl() {
496 dbus::ObjectPath
dev0("/fake/hci0/dev0");
498 Properties
* properties
= new Properties(base::Bind(
499 &BluetoothDeviceClientStubImpl::OnPropertyChanged
,
500 base::Unretained(this),
502 properties
->address
.ReplaceValue("00:11:22:33:44:55");
503 properties
->name
.ReplaceValue("Fake Device");
504 properties
->paired
.ReplaceValue(true);
505 properties
->trusted
.ReplaceValue(true);
507 properties_map_
[dev0
] = properties
;
510 virtual ~BluetoothDeviceClientStubImpl() {
511 // Clean up Properties structures
512 STLDeleteValues(&properties_map_
);
515 // BluetoothDeviceClient override.
516 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
517 observers_
.AddObserver(observer
);
520 // BluetoothDeviceClient override.
521 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
522 observers_
.RemoveObserver(observer
);
525 // BluetoothDeviceClient override.
526 virtual Properties
* GetProperties(const dbus::ObjectPath
& object_path
)
528 VLOG(1) << "GetProperties: " << object_path
.value();
529 PropertiesMap::iterator iter
= properties_map_
.find(object_path
);
530 if (iter
!= properties_map_
.end())
535 // BluetoothDeviceClient override.
536 virtual void DiscoverServices(const dbus::ObjectPath
& object_path
,
537 const std::string
& pattern
,
538 const ServicesCallback
& callback
) OVERRIDE
{
539 VLOG(1) << "DiscoverServices: " << object_path
.value() << " " << pattern
;
542 callback
.Run(object_path
, services
, false);
545 // BluetoothDeviceClient override.
546 virtual void CancelDiscovery(const dbus::ObjectPath
& object_path
,
547 const DeviceCallback
& callback
) OVERRIDE
{
548 VLOG(1) << "CancelDiscovery: " << object_path
.value();
549 callback
.Run(object_path
, false);
552 // BluetoothDeviceClient override.
553 virtual void Disconnect(const dbus::ObjectPath
& object_path
,
554 const DeviceCallback
& callback
) OVERRIDE
{
555 VLOG(1) << "Disconnect: " << object_path
.value();
556 callback
.Run(object_path
, false);
559 // BluetoothDeviceClient override.
560 virtual void CreateNode(const dbus::ObjectPath
& object_path
,
561 const std::string
& uuid
,
562 const NodeCallback
& callback
) OVERRIDE
{
563 VLOG(1) << "CreateNode: " << object_path
.value() << " " << uuid
;
564 callback
.Run(dbus::ObjectPath(), false);
567 // BluetoothDeviceClient override.
568 virtual void RemoveNode(const dbus::ObjectPath
& object_path
,
569 const dbus::ObjectPath
& node_path
,
570 const DeviceCallback
& callback
) OVERRIDE
{
571 VLOG(1) << "RemoveNode: " << object_path
.value()
572 << " " << node_path
.value();
573 callback
.Run(object_path
, false);
577 void OnPropertyChanged(dbus::ObjectPath object_path
,
578 const std::string
& property_name
) {
579 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer
, observers_
,
580 DevicePropertyChanged(object_path
, property_name
));
583 // List of observers interested in event notifications from us.
584 ObserverList
<Observer
> observers_
;
586 // Static properties we typedef.
587 typedef std::map
<const dbus::ObjectPath
, Properties
*> PropertiesMap
;
588 PropertiesMap properties_map_
;
591 BluetoothDeviceClient::BluetoothDeviceClient() {
594 BluetoothDeviceClient::~BluetoothDeviceClient() {
597 BluetoothDeviceClient
* BluetoothDeviceClient::Create(
598 DBusClientImplementationType type
,
600 BluetoothAdapterClient
* adapter_client
) {
601 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
602 return new BluetoothDeviceClientImpl(bus
, adapter_client
);
603 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
604 return new BluetoothDeviceClientStubImpl();
607 } // namespace chromeos