OLD | NEW |
| (Empty) |
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/dbus/bluetooth_device_client.h" | |
6 | |
7 #include <map> | |
8 #include <utility> | |
9 | |
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" | |
15 #include "chromeos/dbus/fake_old_bluetooth_device_client.h" | |
16 #include "dbus/bus.h" | |
17 #include "dbus/message.h" | |
18 #include "dbus/object_path.h" | |
19 #include "dbus/object_proxy.h" | |
20 #include "third_party/cros_system_api/dbus/service_constants.h" | |
21 | |
22 namespace chromeos { | |
23 | |
24 BluetoothDeviceClient::Properties::Properties( | |
25 dbus::ObjectProxy* object_proxy, | |
26 const PropertyChangedCallback& callback) | |
27 : BluetoothPropertySet(object_proxy, | |
28 bluetooth_device::kBluetoothDeviceInterface, | |
29 callback) { | |
30 RegisterProperty(bluetooth_device::kAddressProperty, &address); | |
31 RegisterProperty(bluetooth_device::kNameProperty, &name); | |
32 RegisterProperty(bluetooth_device::kVendorProperty, &vendor); | |
33 RegisterProperty(bluetooth_device::kProductProperty, &product); | |
34 RegisterProperty(bluetooth_device::kVersionProperty, &version); | |
35 RegisterProperty(bluetooth_device::kIconProperty, &icon); | |
36 RegisterProperty(bluetooth_device::kClassProperty, &bluetooth_class); | |
37 RegisterProperty(bluetooth_device::kUUIDsProperty, &uuids); | |
38 RegisterProperty(bluetooth_device::kServicesProperty, &services); | |
39 RegisterProperty(bluetooth_device::kPairedProperty, &paired); | |
40 RegisterProperty(bluetooth_device::kConnectedProperty, &connected); | |
41 RegisterProperty(bluetooth_device::kTrustedProperty, &trusted); | |
42 RegisterProperty(bluetooth_device::kBlockedProperty, &blocked); | |
43 RegisterProperty(bluetooth_device::kAliasProperty, &alias); | |
44 RegisterProperty(bluetooth_device::kNodesProperty, &nodes); | |
45 RegisterProperty(bluetooth_device::kAdapterProperty, &adapter); | |
46 RegisterProperty(bluetooth_device::kLegacyPairingProperty, &legacy_pairing); | |
47 } | |
48 | |
49 BluetoothDeviceClient::Properties::~Properties() { | |
50 } | |
51 | |
52 | |
53 // The BluetoothDeviceClient implementation used in production. | |
54 class BluetoothDeviceClientImpl: public BluetoothDeviceClient, | |
55 private BluetoothAdapterClient::Observer { | |
56 public: | |
57 BluetoothDeviceClientImpl(dbus::Bus* bus, | |
58 BluetoothAdapterClient* adapter_client) | |
59 : bus_(bus), | |
60 weak_ptr_factory_(this) { | |
61 VLOG(1) << "Creating BluetoothDeviceClientImpl"; | |
62 | |
63 DCHECK(adapter_client); | |
64 adapter_client->AddObserver(this); | |
65 } | |
66 | |
67 virtual ~BluetoothDeviceClientImpl() { | |
68 // Clean up Properties structures | |
69 for (ObjectMap::iterator iter = object_map_.begin(); | |
70 iter != object_map_.end(); ++iter) { | |
71 Object object = iter->second; | |
72 Properties* properties = object.second; | |
73 delete properties; | |
74 } | |
75 } | |
76 | |
77 // BluetoothDeviceClient override. | |
78 virtual void AddObserver(BluetoothDeviceClient::Observer* observer) | |
79 OVERRIDE { | |
80 DCHECK(observer); | |
81 observers_.AddObserver(observer); | |
82 } | |
83 | |
84 // BluetoothDeviceClient override. | |
85 virtual void RemoveObserver(BluetoothDeviceClient::Observer* observer) | |
86 OVERRIDE { | |
87 DCHECK(observer); | |
88 observers_.RemoveObserver(observer); | |
89 } | |
90 | |
91 // BluetoothDeviceClient override. | |
92 virtual Properties* GetProperties(const dbus::ObjectPath& object_path) | |
93 OVERRIDE { | |
94 return GetObject(object_path).second; | |
95 } | |
96 | |
97 // BluetoothDeviceClient override. | |
98 virtual void DiscoverServices(const dbus::ObjectPath& object_path, | |
99 const std::string& pattern, | |
100 const ServicesCallback& callback) OVERRIDE { | |
101 dbus::MethodCall method_call( | |
102 bluetooth_device::kBluetoothDeviceInterface, | |
103 bluetooth_device::kDiscoverServices); | |
104 | |
105 dbus::MessageWriter writer(&method_call); | |
106 writer.AppendString(pattern); | |
107 | |
108 dbus::ObjectProxy* object_proxy = GetObjectProxy(object_path); | |
109 | |
110 object_proxy->CallMethod( | |
111 &method_call, | |
112 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, | |
113 base::Bind(&BluetoothDeviceClientImpl::OnDiscoverServices, | |
114 weak_ptr_factory_.GetWeakPtr(), object_path, callback)); | |
115 } | |
116 | |
117 // BluetoothDeviceClient override. | |
118 virtual void CancelDiscovery(const dbus::ObjectPath& object_path, | |
119 const DeviceCallback& callback) OVERRIDE { | |
120 dbus::MethodCall method_call( | |
121 bluetooth_device::kBluetoothDeviceInterface, | |
122 bluetooth_device::kCancelDiscovery); | |
123 | |
124 dbus::ObjectProxy* object_proxy = GetObjectProxy(object_path); | |
125 | |
126 object_proxy->CallMethod( | |
127 &method_call, | |
128 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, | |
129 base::Bind(&BluetoothDeviceClientImpl::OnCancelDiscovery, | |
130 weak_ptr_factory_.GetWeakPtr(), object_path, callback)); | |
131 } | |
132 | |
133 // BluetoothDeviceClient override. | |
134 virtual void Disconnect(const dbus::ObjectPath& object_path, | |
135 const DeviceCallback& callback) OVERRIDE { | |
136 dbus::MethodCall method_call( | |
137 bluetooth_device::kBluetoothDeviceInterface, | |
138 bluetooth_device::kDisconnect); | |
139 | |
140 dbus::ObjectProxy* object_proxy = GetObjectProxy(object_path); | |
141 | |
142 object_proxy->CallMethod( | |
143 &method_call, | |
144 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, | |
145 base::Bind(&BluetoothDeviceClientImpl::OnDisconnect, | |
146 weak_ptr_factory_.GetWeakPtr(), object_path, callback)); | |
147 } | |
148 | |
149 // BluetoothDeviceClient override. | |
150 virtual void CreateNode(const dbus::ObjectPath& object_path, | |
151 const std::string& uuid, | |
152 const NodeCallback& callback) OVERRIDE { | |
153 dbus::MethodCall method_call( | |
154 bluetooth_device::kBluetoothDeviceInterface, | |
155 bluetooth_device::kCreateNode); | |
156 | |
157 dbus::MessageWriter writer(&method_call); | |
158 writer.AppendString(uuid); | |
159 | |
160 dbus::ObjectProxy* object_proxy = GetObjectProxy(object_path); | |
161 | |
162 object_proxy->CallMethod( | |
163 &method_call, | |
164 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, | |
165 base::Bind(&BluetoothDeviceClientImpl::OnCreateNode, | |
166 weak_ptr_factory_.GetWeakPtr(), object_path, callback)); | |
167 } | |
168 | |
169 // BluetoothDeviceClient override. | |
170 virtual void RemoveNode(const dbus::ObjectPath& object_path, | |
171 const dbus::ObjectPath& node_path, | |
172 const DeviceCallback& callback) OVERRIDE { | |
173 dbus::MethodCall method_call( | |
174 bluetooth_device::kBluetoothDeviceInterface, | |
175 bluetooth_device::kRemoveNode); | |
176 | |
177 dbus::MessageWriter writer(&method_call); | |
178 writer.AppendObjectPath(node_path); | |
179 | |
180 dbus::ObjectProxy* object_proxy = GetObjectProxy(object_path); | |
181 | |
182 object_proxy->CallMethod( | |
183 &method_call, | |
184 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, | |
185 base::Bind(&BluetoothDeviceClientImpl::OnRemoveNode, | |
186 weak_ptr_factory_.GetWeakPtr(), object_path, callback)); | |
187 } | |
188 | |
189 private: | |
190 // We maintain a collection of dbus object proxies and properties structures | |
191 // for each device. | |
192 typedef std::pair<dbus::ObjectProxy*, Properties*> Object; | |
193 typedef std::map<const dbus::ObjectPath, Object> ObjectMap; | |
194 ObjectMap object_map_; | |
195 | |
196 // BluetoothAdapterClient::Observer override. | |
197 virtual void DeviceCreated(const dbus::ObjectPath& adapter_path, | |
198 const dbus::ObjectPath& object_path) OVERRIDE { | |
199 } | |
200 | |
201 // BluetoothAdapterClient::Observer override. | |
202 virtual void DeviceRemoved(const dbus::ObjectPath& adapter_path, | |
203 const dbus::ObjectPath& object_path) OVERRIDE { | |
204 RemoveObject(object_path); | |
205 } | |
206 | |
207 // Ensures that we have an object proxy and properties structure for | |
208 // a device with object path |object_path|, creating it if not and | |
209 // storing it in our |object_map_| map. | |
210 Object GetObject(const dbus::ObjectPath& object_path) { | |
211 ObjectMap::iterator iter = object_map_.find(object_path); | |
212 if (iter != object_map_.end()) | |
213 return iter->second; | |
214 | |
215 // Create the object proxy. | |
216 DCHECK(bus_); | |
217 dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy( | |
218 bluetooth_device::kBluetoothDeviceServiceName, object_path); | |
219 | |
220 object_proxy->ConnectToSignal( | |
221 bluetooth_device::kBluetoothDeviceInterface, | |
222 bluetooth_device::kDisconnectRequestedSignal, | |
223 base::Bind(&BluetoothDeviceClientImpl::DisconnectRequestedReceived, | |
224 weak_ptr_factory_.GetWeakPtr(), object_path), | |
225 base::Bind(&BluetoothDeviceClientImpl::DisconnectRequestedConnected, | |
226 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
227 | |
228 object_proxy->ConnectToSignal( | |
229 bluetooth_device::kBluetoothDeviceInterface, | |
230 bluetooth_device::kNodeCreatedSignal, | |
231 base::Bind(&BluetoothDeviceClientImpl::NodeCreatedReceived, | |
232 weak_ptr_factory_.GetWeakPtr(), object_path), | |
233 base::Bind(&BluetoothDeviceClientImpl::NodeCreatedConnected, | |
234 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
235 | |
236 object_proxy->ConnectToSignal( | |
237 bluetooth_device::kBluetoothDeviceInterface, | |
238 bluetooth_device::kNodeRemovedSignal, | |
239 base::Bind(&BluetoothDeviceClientImpl::NodeRemovedReceived, | |
240 weak_ptr_factory_.GetWeakPtr(), object_path), | |
241 base::Bind(&BluetoothDeviceClientImpl::NodeRemovedConnected, | |
242 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
243 | |
244 // Create the properties structure. | |
245 Properties* properties = new Properties( | |
246 object_proxy, | |
247 base::Bind(&BluetoothDeviceClientImpl::OnPropertyChanged, | |
248 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
249 | |
250 properties->ConnectSignals(); | |
251 properties->GetAll(); | |
252 | |
253 Object object = std::make_pair(object_proxy, properties); | |
254 object_map_[object_path] = object; | |
255 return object; | |
256 } | |
257 | |
258 // Removes the dbus object proxy and properties for the device with | |
259 // dbus object path |object_path| from our |object_map_| map. | |
260 void RemoveObject(const dbus::ObjectPath& object_path) { | |
261 ObjectMap::iterator iter = object_map_.find(object_path); | |
262 if (iter != object_map_.end()) { | |
263 // Clean up the Properties structure. | |
264 Object object = iter->second; | |
265 Properties* properties = object.second; | |
266 delete properties; | |
267 | |
268 object_map_.erase(iter); | |
269 } | |
270 } | |
271 | |
272 // Returns a pointer to the object proxy for |object_path|, creating | |
273 // it if necessary. | |
274 dbus::ObjectProxy* GetObjectProxy(const dbus::ObjectPath& object_path) { | |
275 return GetObject(object_path).first; | |
276 } | |
277 | |
278 // Called by BluetoothPropertySet when a property value is changed, | |
279 // either by result of a signal or response to a GetAll() or Get() | |
280 // call. Informs observers. | |
281 void OnPropertyChanged(const dbus::ObjectPath& object_path, | |
282 const std::string& property_name) { | |
283 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_, | |
284 DevicePropertyChanged(object_path, property_name)); | |
285 } | |
286 | |
287 // Called by dbus:: when a DisconnectRequested signal is received. | |
288 void DisconnectRequestedReceived(const dbus::ObjectPath& object_path, | |
289 dbus::Signal* signal) { | |
290 DCHECK(signal); | |
291 | |
292 VLOG(1) << object_path.value() << ": Disconnect requested."; | |
293 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_, | |
294 DisconnectRequested(object_path)); | |
295 } | |
296 | |
297 // Called by dbus:: when the DisconnectRequested signal is initially | |
298 // connected. | |
299 void DisconnectRequestedConnected(const dbus::ObjectPath& object_path, | |
300 const std::string& interface_name, | |
301 const std::string& signal_name, | |
302 bool success) { | |
303 LOG_IF(WARNING, !success) << object_path.value() | |
304 << ": Failed to connect to " | |
305 "DisconnectRequested signal."; | |
306 } | |
307 | |
308 // Called by dbus:: when a NodeCreated signal is received. | |
309 void NodeCreatedReceived(const dbus::ObjectPath& object_path, | |
310 dbus::Signal* signal) { | |
311 DCHECK(signal); | |
312 dbus::MessageReader reader(signal); | |
313 dbus::ObjectPath node_path; | |
314 if (!reader.PopObjectPath(&node_path)) { | |
315 LOG(WARNING) << object_path.value() | |
316 << ": NodeCreated signal has incorrect parameters: " | |
317 << signal->ToString(); | |
318 return; | |
319 } | |
320 | |
321 VLOG(1) << object_path.value() << ": Node created: " | |
322 << node_path.value(); | |
323 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_, | |
324 NodeCreated(object_path, node_path)); | |
325 } | |
326 | |
327 // Called by dbus:: when the NodeCreated signal is initially connected. | |
328 void NodeCreatedConnected(const dbus::ObjectPath& object_path, | |
329 const std::string& interface_name, | |
330 const std::string& signal_name, | |
331 bool success) { | |
332 LOG_IF(WARNING, !success) << object_path.value() | |
333 << ": Failed to connect to NodeCreated signal."; | |
334 } | |
335 | |
336 // Called by dbus:: when a NodeRemoved signal is received. | |
337 void NodeRemovedReceived(const dbus::ObjectPath& object_path, | |
338 dbus::Signal* signal) { | |
339 DCHECK(signal); | |
340 dbus::MessageReader reader(signal); | |
341 dbus::ObjectPath node_path; | |
342 if (!reader.PopObjectPath(&node_path)) { | |
343 LOG(WARNING) << object_path.value() | |
344 << ": NodeRemoved signal has incorrect parameters: " | |
345 << signal->ToString(); | |
346 return; | |
347 } | |
348 | |
349 VLOG(1) << object_path.value() << ": Node removed: " | |
350 << node_path.value(); | |
351 FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_, | |
352 NodeRemoved(object_path, node_path)); | |
353 } | |
354 | |
355 // Called by dbus:: when the NodeRemoved signal is initially connected. | |
356 void NodeRemovedConnected(const dbus::ObjectPath& object_path, | |
357 const std::string& interface_name, | |
358 const std::string& signal_name, | |
359 bool success) { | |
360 LOG_IF(WARNING, !success) << object_path.value() | |
361 << ": Failed to connect to NodeRemoved signal."; | |
362 } | |
363 | |
364 // Called when a response for DiscoverServices() is received. | |
365 void OnDiscoverServices(const dbus::ObjectPath& object_path, | |
366 const ServicesCallback& callback, | |
367 dbus::Response* response) { | |
368 // Parse response. | |
369 bool success = false; | |
370 ServiceMap services; | |
371 if (response != NULL) { | |
372 dbus::MessageReader reader(response); | |
373 | |
374 dbus::MessageReader array_reader(NULL); | |
375 if (!reader.PopArray(&array_reader)) { | |
376 LOG(WARNING) << "DiscoverServices response has incorrect parameters: " | |
377 << response->ToString(); | |
378 } else { | |
379 while (array_reader.HasMoreData()) { | |
380 dbus::MessageReader dict_entry_reader(NULL); | |
381 uint32 key = 0; | |
382 std::string value; | |
383 if (!array_reader.PopDictEntry(&dict_entry_reader) | |
384 || !dict_entry_reader.PopUint32(&key) | |
385 || !dict_entry_reader.PopString(&value)) { | |
386 LOG(WARNING) << "DiscoverServices response has " | |
387 "incorrect parameters: " << response->ToString(); | |
388 } else { | |
389 services[key] = value; | |
390 } | |
391 } | |
392 | |
393 success = true; | |
394 } | |
395 } else { | |
396 LOG(WARNING) << "Failed to discover services."; | |
397 } | |
398 | |
399 // Notify client. | |
400 callback.Run(object_path, services, success); | |
401 } | |
402 | |
403 // Called when a response for CancelDiscovery() is received. | |
404 void OnCancelDiscovery(const dbus::ObjectPath& object_path, | |
405 const DeviceCallback& callback, | |
406 dbus::Response* response) { | |
407 LOG_IF(WARNING, !response) << object_path.value() | |
408 << ": OnCancelDiscovery: failed."; | |
409 callback.Run(object_path, response); | |
410 } | |
411 | |
412 // Called when a response for Disconnect() is received. | |
413 void OnDisconnect(const dbus::ObjectPath& object_path, | |
414 const DeviceCallback& callback, | |
415 dbus::Response* response) { | |
416 LOG_IF(WARNING, !response) << object_path.value() | |
417 << ": OnDisconnect: failed."; | |
418 callback.Run(object_path, response); | |
419 } | |
420 | |
421 // Called when a response for CreateNode() is received. | |
422 void OnCreateNode(const dbus::ObjectPath& object_path, | |
423 const NodeCallback& callback, | |
424 dbus::Response* response) { | |
425 // Parse response. | |
426 bool success = false; | |
427 dbus::ObjectPath node_path; | |
428 if (response != NULL) { | |
429 dbus::MessageReader reader(response); | |
430 if (!reader.PopObjectPath(&node_path)) { | |
431 LOG(WARNING) << "CreateNode response has incorrect parameters: " | |
432 << response->ToString(); | |
433 } else { | |
434 success = true; | |
435 } | |
436 } else { | |
437 LOG(WARNING) << "Failed to create node."; | |
438 } | |
439 | |
440 // Notify client. | |
441 callback.Run(node_path, success); | |
442 } | |
443 | |
444 // Called when a response for RemoveNode() is received. | |
445 void OnRemoveNode(const dbus::ObjectPath& object_path, | |
446 const DeviceCallback& callback, | |
447 dbus::Response* response) { | |
448 LOG_IF(WARNING, !response) << object_path.value() | |
449 << ": OnRemoveNode: failed."; | |
450 callback.Run(object_path, response); | |
451 } | |
452 | |
453 dbus::Bus* bus_; | |
454 | |
455 // List of observers interested in event notifications from us. | |
456 ObserverList<BluetoothDeviceClient::Observer> observers_; | |
457 | |
458 // Weak pointer factory for generating 'this' pointers that might live longer | |
459 // than we do. | |
460 // Note: This should remain the last member so it'll be destroyed and | |
461 // invalidate its weak pointers before any other members are destroyed. | |
462 base::WeakPtrFactory<BluetoothDeviceClientImpl> weak_ptr_factory_; | |
463 | |
464 DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceClientImpl); | |
465 }; | |
466 | |
467 BluetoothDeviceClient::BluetoothDeviceClient() { | |
468 } | |
469 | |
470 BluetoothDeviceClient::~BluetoothDeviceClient() { | |
471 } | |
472 | |
473 BluetoothDeviceClient* BluetoothDeviceClient::Create( | |
474 DBusClientImplementationType type, | |
475 dbus::Bus* bus, | |
476 BluetoothAdapterClient* adapter_client) { | |
477 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) | |
478 return new BluetoothDeviceClientImpl(bus, adapter_client); | |
479 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); | |
480 return new FakeOldBluetoothDeviceClient(); | |
481 } | |
482 | |
483 } // namespace chromeos | |
OLD | NEW |