OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 "chrome/browser/chromeos/dbus/bluetooth_adapter_client.h" | |
6 | |
7 #include <map> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/logging.h" | |
11 #include "base/stl_util.h" | |
12 #include "chrome/browser/chromeos/system/runtime_environment.h" | |
13 #include "dbus/bus.h" | |
14 #include "dbus/message.h" | |
15 #include "dbus/object_proxy.h" | |
16 #include "third_party/cros_system_api/dbus/service_constants.h" | |
17 | |
18 namespace { | |
19 | |
20 // Utility function to convert an array of dbus dict_entry objects into a | |
21 // DictionaryValue object. | |
22 // | |
23 // The dict_entry objects must have keys that are strings and values that are | |
24 // simple variants. | |
25 // | |
26 // When converting integral types, we use Integer Value objects to represent | |
27 // uint8, int16, uint16, int32, and uint32 values and Double Value objects to | |
28 // represent int64 and uint64 values. | |
29 // | |
30 // We intend to move this to the chrome dbus library's MessageReader class when | |
31 // it's more fully baked. | |
32 // | |
33 // TODO(vlaviano): | |
34 // - Can we handle integral types better? | |
35 // - Add support for nested complex types. | |
36 // - Write an equivalent function to convert in the opposite direction. | |
37 // - Write unit tests. | |
38 bool PopArrayOfDictEntries(dbus::MessageReader* reader, | |
39 dbus::Message* message, | |
40 DictionaryValue* dictionary) { | |
41 DCHECK(reader != NULL); | |
42 DCHECK(message != NULL); | |
43 DCHECK(dictionary != NULL); | |
44 dbus::MessageReader array_reader(message); | |
45 if (!reader->PopArray(&array_reader)) { | |
46 return false; | |
47 } | |
48 while (array_reader.HasMoreData()) { | |
49 dbus::MessageReader dict_entry_reader(message); | |
50 if (!array_reader.PopDictEntry(&dict_entry_reader)) { | |
51 return false; | |
52 } | |
53 std::string key; | |
54 if (!dict_entry_reader.PopString(&key)) { | |
55 return false; | |
56 } | |
57 dbus::MessageReader variant_reader(message); | |
58 if (!dict_entry_reader.PopVariant(&variant_reader)) { | |
59 return false; | |
60 } | |
61 const dbus::Message::DataType type = variant_reader.GetDataType(); | |
62 switch (type) { | |
63 case dbus::Message::BYTE: { | |
64 uint8 value = 0; | |
65 if (!variant_reader.PopByte(&value)) { | |
66 return false; | |
67 } | |
68 dictionary->SetInteger(key, value); | |
69 break; | |
70 } | |
71 case dbus::Message::BOOL: { | |
72 bool value = false; | |
73 if (!variant_reader.PopBool(&value)) { | |
74 return false; | |
75 } | |
76 dictionary->SetBoolean(key, value); | |
77 break; | |
78 } | |
79 case dbus::Message::INT16: { | |
80 int16 value = 0; | |
81 if (!variant_reader.PopInt16(&value)) { | |
82 return false; | |
83 } | |
84 dictionary->SetInteger(key, value); | |
85 break; | |
86 } | |
87 case dbus::Message::UINT16: { | |
88 uint16 value = 0; | |
89 if (!variant_reader.PopUint16(&value)) { | |
90 return false; | |
91 } | |
92 dictionary->SetInteger(key, value); | |
93 break; | |
94 } | |
95 case dbus::Message::INT32: { | |
96 int32 value = 0; | |
97 if (!variant_reader.PopInt32(&value)) { | |
98 return false; | |
99 } | |
100 dictionary->SetInteger(key, value); | |
101 break; | |
102 } | |
103 case dbus::Message::UINT32: { | |
104 uint32 value = 0; | |
105 if (!variant_reader.PopUint32(&value)) { | |
106 return false; | |
107 } | |
108 dictionary->SetInteger(key, value); | |
109 break; | |
110 } | |
111 case dbus::Message::INT64: { | |
112 int64 value = 0; | |
113 if (!variant_reader.PopInt64(&value)) { | |
114 return false; | |
115 } | |
116 dictionary->SetDouble(key, value); | |
117 break; | |
118 } | |
119 case dbus::Message::UINT64: { | |
120 uint64 value = 0; | |
121 if (!variant_reader.PopUint64(&value)) { | |
122 return false; | |
123 } | |
124 dictionary->SetDouble(key, value); | |
125 break; | |
126 } | |
127 case dbus::Message::DOUBLE: { | |
128 double value = 0; | |
129 if (!variant_reader.PopDouble(&value)) { | |
130 return false; | |
131 } | |
132 dictionary->SetDouble(key, value); | |
133 break; | |
134 } | |
135 case dbus::Message::STRING: { | |
136 std::string value; | |
137 if (!variant_reader.PopString(&value)) { | |
138 return false; | |
139 } | |
140 dictionary->SetString(key, value); | |
141 break; | |
142 } | |
143 case dbus::Message::OBJECT_PATH: { | |
144 std::string value; | |
145 if (!variant_reader.PopObjectPath(&value)) { | |
146 return false; | |
147 } | |
148 dictionary->SetString(key, value); | |
149 break; | |
150 } | |
151 case dbus::Message::ARRAY: { | |
152 // Not yet supported. | |
153 return false; | |
154 } | |
155 case dbus::Message::STRUCT: { | |
156 // Not yet supported. | |
157 return false; | |
158 } | |
159 case dbus::Message::DICT_ENTRY: { | |
160 // Not yet supported. | |
161 return false; | |
162 } | |
163 case dbus::Message::VARIANT: { | |
164 // Not yet supported. | |
165 return false; | |
166 } | |
167 default: | |
168 LOG(FATAL) << "Unknown type: " << type; | |
169 } | |
170 } | |
171 return true; | |
172 } | |
173 | |
174 } // namespace | |
175 | |
176 namespace chromeos { | |
177 | |
178 // The BluetoothAdapterClient implementation used in production. | |
179 class BluetoothAdapterClientImpl: public BluetoothAdapterClient { | |
180 public: | |
181 explicit BluetoothAdapterClientImpl(dbus::Bus* bus) | |
182 : weak_ptr_factory_(this), | |
183 bus_(bus) { | |
184 VLOG(1) << "Creating BluetoothAdapterClientImpl"; | |
185 } | |
186 | |
187 virtual ~BluetoothAdapterClientImpl() { | |
188 } | |
189 | |
190 // BluetoothAdapterClient override. | |
191 virtual void AddObserver(Observer* observer, const std::string& object_path) { | |
192 VLOG(1) << "AddObserver: " << object_path; | |
193 DCHECK(observer != NULL); | |
satorux1
2011/10/25 19:55:17
I think DCHECK(observer) is more common in Chrome
Vince Laviano
2011/10/25 20:31:42
Done.
| |
194 observers_.AddObserver(observer); | |
195 AddObjectProxyForPath(object_path); | |
196 } | |
197 | |
198 // BluetoothAdapterClient override. | |
199 virtual void RemoveObserver(Observer* observer, | |
200 const std::string& object_path) { | |
201 VLOG(1) << "RemoveObserver: " << object_path; | |
202 CHECK(observer != NULL); | |
203 observers_.RemoveObserver(observer); | |
204 RemoveObjectProxyForPath(object_path); | |
205 } | |
206 | |
207 // BluetoothAdapterClient override. | |
208 virtual void StartDiscovery(const std::string& object_path) { | |
209 VLOG(1) << "StartDiscovery: " << object_path; | |
210 | |
211 dbus::MethodCall method_call( | |
212 bluetooth_adapter::kBluetoothAdapterInterface, | |
213 bluetooth_adapter::kStartDiscovery); | |
214 | |
215 ProxyMap::iterator it = proxy_map_.find(object_path); | |
216 if (it == proxy_map_.end()) { | |
217 LOG(ERROR) << "Couldn't find proxy for object path " << object_path; | |
218 return; | |
219 } | |
220 dbus::ObjectProxy* adapter_proxy = | |
221 static_cast<dbus::ObjectProxy*>(it->second); | |
satorux1
2011/10/25 19:55:17
I think the static cast is unnecessary here.
Vince Laviano
2011/10/25 20:31:42
Done.
| |
222 DCHECK(adapter_proxy != NULL); | |
satorux1
2011/10/25 19:55:17
This may sound like an overuse of DCHECK(), but it
Vince Laviano
2011/10/25 20:31:42
Done.
| |
223 | |
224 adapter_proxy->CallMethod( | |
225 &method_call, | |
226 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, | |
227 base::Bind(&BluetoothAdapterClientImpl::OnStartDiscovery, | |
228 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
229 } | |
230 | |
231 // BluetoothAdapterClient override. | |
232 virtual void StopDiscovery(const std::string& object_path) { | |
233 VLOG(1) << "StopDiscovery: " << object_path; | |
234 | |
235 dbus::MethodCall method_call( | |
236 bluetooth_adapter::kBluetoothAdapterInterface, | |
237 bluetooth_adapter::kStopDiscovery); | |
238 | |
239 ProxyMap::iterator it = proxy_map_.find(object_path); | |
240 if (it == proxy_map_.end()) { | |
241 LOG(ERROR) << "Couldn't find proxy for object path " << object_path; | |
242 return; | |
243 } | |
244 dbus::ObjectProxy* adapter_proxy = | |
245 static_cast<dbus::ObjectProxy*>(it->second); | |
satorux1
2011/10/25 19:55:17
ditto.
Vince Laviano
2011/10/25 20:31:42
Done.
| |
246 DCHECK(adapter_proxy != NULL); | |
247 | |
248 adapter_proxy->CallMethod( | |
249 &method_call, | |
250 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, | |
251 base::Bind(&BluetoothAdapterClientImpl::OnStopDiscovery, | |
252 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
253 } | |
254 | |
255 private: | |
256 // Gets a dbus object proxy for an adapter with dbus object path |object_path| | |
257 // and stores it in our |proxy_map_| map. | |
258 void AddObjectProxyForPath(const std::string& object_path) { | |
259 VLOG(1) << "AddObjectProxyForPath: " << object_path; | |
260 | |
261 DCHECK(bus_ != NULL); | |
262 dbus::ObjectProxy* adapter_proxy = bus_->GetObjectProxy( | |
263 bluetooth_adapter::kBluetoothAdapterServiceName, object_path); | |
264 DCHECK(adapter_proxy != NULL); | |
satorux1
2011/10/25 19:55:17
we don't need this. GetObjectProxy guarantees not
Vince Laviano
2011/10/25 20:31:42
Done.
| |
265 | |
266 proxy_map_[object_path] = adapter_proxy; | |
267 | |
268 adapter_proxy->ConnectToSignal( | |
269 bluetooth_adapter::kBluetoothAdapterInterface, | |
270 bluetooth_adapter::kPropertyChangedSignal, | |
271 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedReceived, | |
272 weak_ptr_factory_.GetWeakPtr(), object_path), | |
273 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedConnected, | |
274 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
275 | |
276 adapter_proxy->ConnectToSignal( | |
277 bluetooth_adapter::kBluetoothAdapterInterface, | |
278 bluetooth_adapter::kDeviceFoundSignal, | |
279 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundReceived, | |
280 weak_ptr_factory_.GetWeakPtr(), object_path), | |
281 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundConnected, | |
282 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
283 | |
284 adapter_proxy->ConnectToSignal( | |
285 bluetooth_adapter::kBluetoothAdapterInterface, | |
286 bluetooth_adapter::kDeviceDisappearedSignal, | |
287 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedReceived, | |
288 weak_ptr_factory_.GetWeakPtr(), object_path), | |
289 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedConnected, | |
290 weak_ptr_factory_.GetWeakPtr(), object_path)); | |
291 } | |
292 | |
293 // Removes the dbus object proxy for the adapter with dbus object path | |
294 // |object_path| from our |proxy_map_| map. | |
295 void RemoveObjectProxyForPath(const std::string& object_path) { | |
296 VLOG(1) << "RemoveObjectProxyForPath: " << object_path; | |
297 proxy_map_.erase(object_path); | |
298 } | |
299 | |
300 // Called by dbus:: when a PropertyChanged signal is received. | |
301 void PropertyChangedReceived(const std::string& object_path, | |
302 dbus::Signal* signal) { | |
303 DCHECK(signal != NULL); | |
304 dbus::MessageReader reader(signal); | |
305 std::string property_name; | |
306 if (!reader.PopString(&property_name)) { | |
307 LOG(ERROR) << object_path | |
308 << ": PropertyChanged signal has incorrect parameters: " | |
309 << signal->ToString(); | |
310 return; | |
311 } | |
312 | |
313 if (property_name != bluetooth_adapter::kDiscoveringProperty) { | |
314 VLOG(1) << object_path << ": PropertyChanged: " << property_name; | |
315 // We don't care. | |
316 return; | |
317 } | |
318 | |
319 bool discovering = false; | |
320 if (!reader.PopVariantOfBool(&discovering)) { | |
321 LOG(ERROR) << object_path | |
322 << ": PropertyChanged signal has incorrect parameters: " | |
323 << signal->ToString(); | |
324 return; | |
325 } | |
326 VLOG(1) << object_path << ": PropertyChanged: Discovering = " | |
327 << discovering; | |
328 | |
329 FOR_EACH_OBSERVER(Observer, observers_, | |
330 DiscoveringPropertyChanged(object_path, discovering)); | |
331 } | |
332 | |
333 // Called by dbus:: when the PropertyChanged signal is initially connected. | |
334 void PropertyChangedConnected(const std::string& object_path, | |
335 const std::string& interface_name, | |
336 const std::string& signal_name, | |
337 bool success) { | |
338 LOG_IF(WARNING, !success) << object_path | |
339 << ": Failed to connect to PropertyChanged signal."; | |
340 } | |
341 | |
342 // Called by dbus:: when a DeviceFound signal is received. | |
343 void DeviceFoundReceived(const std::string& object_path, | |
344 dbus::Signal* signal) { | |
345 DCHECK(signal != NULL); | |
346 dbus::MessageReader reader(signal); | |
347 std::string address; | |
348 if (!reader.PopString(&address)) { | |
349 LOG(ERROR) << object_path | |
350 << ": DeviceFound signal has incorrect parameters: " | |
351 << signal->ToString(); | |
352 return; | |
353 } | |
354 VLOG(1) << object_path << ": Device found: " << address; | |
355 | |
356 DictionaryValue device_properties; | |
357 if (!PopArrayOfDictEntries(&reader, signal, &device_properties)) { | |
358 LOG(ERROR) << object_path | |
359 << ": DeviceFound signal has incorrect parameters: " | |
360 << signal->ToString(); | |
361 return; | |
362 } | |
363 | |
364 FOR_EACH_OBSERVER(Observer, observers_, DeviceFound(object_path, address, | |
365 device_properties)); | |
366 } | |
367 | |
368 // Called by dbus:: when the DeviceFound signal is initially connected. | |
369 void DeviceFoundConnected(const std::string& object_path, | |
370 const std::string& interface_name, | |
371 const std::string& signal_name, | |
372 bool success) { | |
373 LOG_IF(WARNING, !success) << object_path | |
374 << ": Failed to connect to DeviceFound signal."; | |
375 } | |
376 | |
377 // Called by dbus:: when a DeviceDisappeared signal is received. | |
378 void DeviceDisappearedReceived(const std::string& object_path, | |
379 dbus::Signal* signal) { | |
380 DCHECK(signal != NULL); | |
381 dbus::MessageReader reader(signal); | |
382 std::string address; | |
383 if (!reader.PopString(&address)) { | |
384 LOG(ERROR) << object_path | |
385 << ": DeviceDisappeared signal has incorrect parameters: " | |
386 << signal->ToString(); | |
387 return; | |
388 } | |
389 VLOG(1) << object_path << ": Device disappeared: " << address; | |
390 FOR_EACH_OBSERVER(Observer, observers_, DeviceDisappeared(object_path, | |
391 address)); | |
392 } | |
393 | |
394 // Called by dbus:: when the DeviceDisappeared signal is initially connected. | |
395 void DeviceDisappearedConnected(const std::string& object_path, | |
396 const std::string& interface_name, | |
397 const std::string& signal_name, | |
398 bool success) { | |
399 LOG_IF(WARNING, !success) << object_path | |
400 << ": Failed to connect to DeviceDisappeared signal."; | |
401 } | |
402 | |
403 // Called when a response for StartDiscovery() is received. | |
404 void OnStartDiscovery(const std::string& object_path, | |
405 dbus::Response* response) { | |
406 VLOG(1) << "OnStartDiscovery: " << object_path; | |
407 DCHECK(response != NULL); | |
satorux1
2011/10/25 19:55:17
LOG_IF(WARNING, response) << ...
would be nicer.
Vince Laviano
2011/10/25 20:31:42
Done.
| |
408 } | |
409 | |
410 // Called when a response for StopDiscovery() is received. | |
411 void OnStopDiscovery(const std::string& object_path, | |
412 dbus::Response* response) { | |
413 VLOG(1) << "OnStopDiscovery: " << object_path; | |
414 DCHECK(response != NULL); | |
satorux1
2011/10/25 19:55:17
ditto.
Vince Laviano
2011/10/25 20:31:42
Done.
| |
415 } | |
416 | |
417 // Weak pointer factory for generating 'this' pointers that might live longer | |
418 // than we do. | |
419 base::WeakPtrFactory<BluetoothAdapterClientImpl> weak_ptr_factory_; | |
420 | |
421 dbus::Bus* bus_; | |
422 | |
423 // We maintain a collection of dbus object proxies, one for each adapter. | |
424 typedef std::map<const std::string, dbus::ObjectProxy*> ProxyMap; | |
425 ProxyMap proxy_map_; | |
426 | |
427 // List of observers interested in event notifications from us. | |
428 ObserverList<Observer> observers_; | |
429 | |
430 DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterClientImpl); | |
431 }; | |
432 | |
433 // The BluetoothAdapterClient implementation used on Linux desktop, which does | |
434 // nothing. | |
435 class BluetoothAdapterClientStubImpl : public BluetoothAdapterClient { | |
436 public: | |
437 // BluetoothAdapterClient override. | |
438 virtual void AddObserver(Observer* observer, const std::string& object_path) { | |
439 VLOG(1) << "AddObserver: " << object_path; | |
440 } | |
441 | |
442 // BluetoothAdapterClient override. | |
443 virtual void RemoveObserver(Observer* observer, | |
444 const std::string& object_path) { | |
445 VLOG(1) << "RemoveObserver: " << object_path; | |
446 } | |
447 | |
448 // BluetoothAdapterClient override. | |
449 virtual void StartDiscovery(const std::string& object_path) { | |
450 VLOG(1) << "StartDiscovery: " << object_path; | |
451 } | |
452 | |
453 // BluetoothAdapterClient override. | |
454 virtual void StopDiscovery(const std::string& object_path) { | |
455 VLOG(1) << "StopDiscovery: " << object_path; | |
456 } | |
457 }; | |
458 | |
459 BluetoothAdapterClient::BluetoothAdapterClient() { | |
460 } | |
461 | |
462 BluetoothAdapterClient::~BluetoothAdapterClient() { | |
463 } | |
464 | |
465 BluetoothAdapterClient* BluetoothAdapterClient::Create(dbus::Bus* bus) { | |
466 if (system::runtime_environment::IsRunningOnChromeOS()) { | |
467 return new BluetoothAdapterClientImpl(bus); | |
468 } else { | |
469 return new BluetoothAdapterClientStubImpl(); | |
470 } | |
471 } | |
472 | |
473 } // namespace chromeos | |
OLD | NEW |