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); |
| 42 DCHECK(message); |
| 43 DCHECK(dictionary); |
| 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); |
| 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 DCHECK(observer); |
| 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 = it->second; |
| 221 |
| 222 adapter_proxy->CallMethod( |
| 223 &method_call, |
| 224 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| 225 base::Bind(&BluetoothAdapterClientImpl::OnStartDiscovery, |
| 226 weak_ptr_factory_.GetWeakPtr(), object_path)); |
| 227 } |
| 228 |
| 229 // BluetoothAdapterClient override. |
| 230 virtual void StopDiscovery(const std::string& object_path) { |
| 231 VLOG(1) << "StopDiscovery: " << object_path; |
| 232 |
| 233 dbus::MethodCall method_call( |
| 234 bluetooth_adapter::kBluetoothAdapterInterface, |
| 235 bluetooth_adapter::kStopDiscovery); |
| 236 |
| 237 ProxyMap::iterator it = proxy_map_.find(object_path); |
| 238 if (it == proxy_map_.end()) { |
| 239 LOG(ERROR) << "Couldn't find proxy for object path " << object_path; |
| 240 return; |
| 241 } |
| 242 dbus::ObjectProxy* adapter_proxy = it->second; |
| 243 |
| 244 adapter_proxy->CallMethod( |
| 245 &method_call, |
| 246 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| 247 base::Bind(&BluetoothAdapterClientImpl::OnStopDiscovery, |
| 248 weak_ptr_factory_.GetWeakPtr(), object_path)); |
| 249 } |
| 250 |
| 251 private: |
| 252 // Gets a dbus object proxy for an adapter with dbus object path |object_path| |
| 253 // and stores it in our |proxy_map_| map. |
| 254 void AddObjectProxyForPath(const std::string& object_path) { |
| 255 VLOG(1) << "AddObjectProxyForPath: " << object_path; |
| 256 |
| 257 DCHECK(bus_); |
| 258 dbus::ObjectProxy* adapter_proxy = bus_->GetObjectProxy( |
| 259 bluetooth_adapter::kBluetoothAdapterServiceName, object_path); |
| 260 |
| 261 proxy_map_[object_path] = adapter_proxy; |
| 262 |
| 263 adapter_proxy->ConnectToSignal( |
| 264 bluetooth_adapter::kBluetoothAdapterInterface, |
| 265 bluetooth_adapter::kPropertyChangedSignal, |
| 266 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedReceived, |
| 267 weak_ptr_factory_.GetWeakPtr(), object_path), |
| 268 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedConnected, |
| 269 weak_ptr_factory_.GetWeakPtr(), object_path)); |
| 270 |
| 271 adapter_proxy->ConnectToSignal( |
| 272 bluetooth_adapter::kBluetoothAdapterInterface, |
| 273 bluetooth_adapter::kDeviceFoundSignal, |
| 274 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundReceived, |
| 275 weak_ptr_factory_.GetWeakPtr(), object_path), |
| 276 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundConnected, |
| 277 weak_ptr_factory_.GetWeakPtr(), object_path)); |
| 278 |
| 279 adapter_proxy->ConnectToSignal( |
| 280 bluetooth_adapter::kBluetoothAdapterInterface, |
| 281 bluetooth_adapter::kDeviceDisappearedSignal, |
| 282 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedReceived, |
| 283 weak_ptr_factory_.GetWeakPtr(), object_path), |
| 284 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedConnected, |
| 285 weak_ptr_factory_.GetWeakPtr(), object_path)); |
| 286 } |
| 287 |
| 288 // Removes the dbus object proxy for the adapter with dbus object path |
| 289 // |object_path| from our |proxy_map_| map. |
| 290 void RemoveObjectProxyForPath(const std::string& object_path) { |
| 291 VLOG(1) << "RemoveObjectProxyForPath: " << object_path; |
| 292 proxy_map_.erase(object_path); |
| 293 } |
| 294 |
| 295 // Called by dbus:: when a PropertyChanged signal is received. |
| 296 void PropertyChangedReceived(const std::string& object_path, |
| 297 dbus::Signal* signal) { |
| 298 DCHECK(signal); |
| 299 dbus::MessageReader reader(signal); |
| 300 std::string property_name; |
| 301 if (!reader.PopString(&property_name)) { |
| 302 LOG(ERROR) << object_path |
| 303 << ": PropertyChanged signal has incorrect parameters: " |
| 304 << signal->ToString(); |
| 305 return; |
| 306 } |
| 307 |
| 308 if (property_name != bluetooth_adapter::kDiscoveringProperty) { |
| 309 VLOG(1) << object_path << ": PropertyChanged: " << property_name; |
| 310 // We don't care. |
| 311 return; |
| 312 } |
| 313 |
| 314 bool discovering = false; |
| 315 if (!reader.PopVariantOfBool(&discovering)) { |
| 316 LOG(ERROR) << object_path |
| 317 << ": PropertyChanged signal has incorrect parameters: " |
| 318 << signal->ToString(); |
| 319 return; |
| 320 } |
| 321 VLOG(1) << object_path << ": PropertyChanged: Discovering = " |
| 322 << discovering; |
| 323 |
| 324 FOR_EACH_OBSERVER(Observer, observers_, |
| 325 DiscoveringPropertyChanged(object_path, discovering)); |
| 326 } |
| 327 |
| 328 // Called by dbus:: when the PropertyChanged signal is initially connected. |
| 329 void PropertyChangedConnected(const std::string& object_path, |
| 330 const std::string& interface_name, |
| 331 const std::string& signal_name, |
| 332 bool success) { |
| 333 LOG_IF(WARNING, !success) << object_path |
| 334 << ": Failed to connect to PropertyChanged signal."; |
| 335 } |
| 336 |
| 337 // Called by dbus:: when a DeviceFound signal is received. |
| 338 void DeviceFoundReceived(const std::string& object_path, |
| 339 dbus::Signal* signal) { |
| 340 DCHECK(signal); |
| 341 dbus::MessageReader reader(signal); |
| 342 std::string address; |
| 343 if (!reader.PopString(&address)) { |
| 344 LOG(ERROR) << object_path |
| 345 << ": DeviceFound signal has incorrect parameters: " |
| 346 << signal->ToString(); |
| 347 return; |
| 348 } |
| 349 VLOG(1) << object_path << ": Device found: " << address; |
| 350 |
| 351 DictionaryValue device_properties; |
| 352 if (!PopArrayOfDictEntries(&reader, signal, &device_properties)) { |
| 353 LOG(ERROR) << object_path |
| 354 << ": DeviceFound signal has incorrect parameters: " |
| 355 << signal->ToString(); |
| 356 return; |
| 357 } |
| 358 |
| 359 FOR_EACH_OBSERVER(Observer, observers_, DeviceFound(object_path, address, |
| 360 device_properties)); |
| 361 } |
| 362 |
| 363 // Called by dbus:: when the DeviceFound signal is initially connected. |
| 364 void DeviceFoundConnected(const std::string& object_path, |
| 365 const std::string& interface_name, |
| 366 const std::string& signal_name, |
| 367 bool success) { |
| 368 LOG_IF(WARNING, !success) << object_path |
| 369 << ": Failed to connect to DeviceFound signal."; |
| 370 } |
| 371 |
| 372 // Called by dbus:: when a DeviceDisappeared signal is received. |
| 373 void DeviceDisappearedReceived(const std::string& object_path, |
| 374 dbus::Signal* signal) { |
| 375 DCHECK(signal); |
| 376 dbus::MessageReader reader(signal); |
| 377 std::string address; |
| 378 if (!reader.PopString(&address)) { |
| 379 LOG(ERROR) << object_path |
| 380 << ": DeviceDisappeared signal has incorrect parameters: " |
| 381 << signal->ToString(); |
| 382 return; |
| 383 } |
| 384 VLOG(1) << object_path << ": Device disappeared: " << address; |
| 385 FOR_EACH_OBSERVER(Observer, observers_, DeviceDisappeared(object_path, |
| 386 address)); |
| 387 } |
| 388 |
| 389 // Called by dbus:: when the DeviceDisappeared signal is initially connected. |
| 390 void DeviceDisappearedConnected(const std::string& object_path, |
| 391 const std::string& interface_name, |
| 392 const std::string& signal_name, |
| 393 bool success) { |
| 394 LOG_IF(WARNING, !success) << object_path |
| 395 << ": Failed to connect to DeviceDisappeared signal."; |
| 396 } |
| 397 |
| 398 // Called when a response for StartDiscovery() is received. |
| 399 void OnStartDiscovery(const std::string& object_path, |
| 400 dbus::Response* response) { |
| 401 VLOG(1) << "OnStartDiscovery: " << object_path; |
| 402 LOG_IF(WARNING, !response) << object_path << ": OnStartDiscovery: failed."; |
| 403 } |
| 404 |
| 405 // Called when a response for StopDiscovery() is received. |
| 406 void OnStopDiscovery(const std::string& object_path, |
| 407 dbus::Response* response) { |
| 408 VLOG(1) << "OnStopDiscovery: " << object_path; |
| 409 LOG_IF(WARNING, !response) << object_path << ": OnStopDiscovery: failed."; |
| 410 } |
| 411 |
| 412 // Weak pointer factory for generating 'this' pointers that might live longer |
| 413 // than we do. |
| 414 base::WeakPtrFactory<BluetoothAdapterClientImpl> weak_ptr_factory_; |
| 415 |
| 416 dbus::Bus* bus_; |
| 417 |
| 418 // We maintain a collection of dbus object proxies, one for each adapter. |
| 419 typedef std::map<const std::string, dbus::ObjectProxy*> ProxyMap; |
| 420 ProxyMap proxy_map_; |
| 421 |
| 422 // List of observers interested in event notifications from us. |
| 423 ObserverList<Observer> observers_; |
| 424 |
| 425 DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterClientImpl); |
| 426 }; |
| 427 |
| 428 // The BluetoothAdapterClient implementation used on Linux desktop, which does |
| 429 // nothing. |
| 430 class BluetoothAdapterClientStubImpl : public BluetoothAdapterClient { |
| 431 public: |
| 432 // BluetoothAdapterClient override. |
| 433 virtual void AddObserver(Observer* observer, const std::string& object_path) { |
| 434 VLOG(1) << "AddObserver: " << object_path; |
| 435 } |
| 436 |
| 437 // BluetoothAdapterClient override. |
| 438 virtual void RemoveObserver(Observer* observer, |
| 439 const std::string& object_path) { |
| 440 VLOG(1) << "RemoveObserver: " << object_path; |
| 441 } |
| 442 |
| 443 // BluetoothAdapterClient override. |
| 444 virtual void StartDiscovery(const std::string& object_path) { |
| 445 VLOG(1) << "StartDiscovery: " << object_path; |
| 446 } |
| 447 |
| 448 // BluetoothAdapterClient override. |
| 449 virtual void StopDiscovery(const std::string& object_path) { |
| 450 VLOG(1) << "StopDiscovery: " << object_path; |
| 451 } |
| 452 }; |
| 453 |
| 454 BluetoothAdapterClient::BluetoothAdapterClient() { |
| 455 } |
| 456 |
| 457 BluetoothAdapterClient::~BluetoothAdapterClient() { |
| 458 } |
| 459 |
| 460 BluetoothAdapterClient* BluetoothAdapterClient::Create(dbus::Bus* bus) { |
| 461 if (system::runtime_environment::IsRunningOnChromeOS()) { |
| 462 return new BluetoothAdapterClientImpl(bus); |
| 463 } else { |
| 464 return new BluetoothAdapterClientStubImpl(); |
| 465 } |
| 466 } |
| 467 |
| 468 } // namespace chromeos |
OLD | NEW |