1 // Copyright 2014 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 "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h" 6 7 #include <limits> 8 9 #include "base/logging.h" 10 #include "base/strings/stringprintf.h" 11 #include "chromeos/dbus/dbus_thread_manager.h" 12 #include "device/bluetooth/bluetooth_adapter.h" 13 #include "device/bluetooth/bluetooth_device.h" 14 #include "device/bluetooth/bluetooth_gatt_notify_session_chromeos.h" 15 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h" 16 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h" 17 #include "third_party/cros_system_api/dbus/service_constants.h" 18 19 namespace chromeos { 20 21 namespace { 22 23 // Stream operator for logging vector<uint8>. 24 std::ostream& operator<<(std::ostream& out, const std::vector<uint8> bytes) { 25 out << "["; 26 for (std::vector<uint8>::const_iterator iter = bytes.begin(); 27 iter != bytes.end(); ++iter) { 28 out << base::StringPrintf("%02X", *iter); 29 } 30 return out << "]"; 31 } 32 33 } // namespace 34 35 BluetoothRemoteGattCharacteristicChromeOS:: 36 BluetoothRemoteGattCharacteristicChromeOS( 37 BluetoothRemoteGattServiceChromeOS* service, 38 const dbus::ObjectPath& object_path) 39 : object_path_(object_path), 40 service_(service), 41 num_notify_sessions_(0), 42 notify_call_pending_(false), 43 weak_ptr_factory_(this) { 44 VLOG(1) << "Creating remote GATT characteristic with identifier: " 45 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); 46 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()-> 47 AddObserver(this); 48 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()-> 49 AddObserver(this); 50 51 // Add all known GATT characteristic descriptors. 52 const std::vector<dbus::ObjectPath>& gatt_descs = 53 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()-> 54 GetDescriptors(); 55 for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_descs.begin(); 56 iter != gatt_descs.end(); ++iter) 57 GattDescriptorAdded(*iter); 58 } 59 60 BluetoothRemoteGattCharacteristicChromeOS:: 61 ~BluetoothRemoteGattCharacteristicChromeOS() { 62 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()-> 63 RemoveObserver(this); 64 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()-> 65 RemoveObserver(this); 66 67 // Clean up all the descriptors. There isn't much point in notifying service 68 // observers for each descriptor that gets removed, so just delete them. 69 for (DescriptorMap::iterator iter = descriptors_.begin(); 70 iter != descriptors_.end(); ++iter) 71 delete iter->second; 72 73 // Report an error for all pending calls to StartNotifySession. 74 while (!pending_start_notify_calls_.empty()) { 75 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front(); 76 pending_start_notify_calls_.pop(); 77 callbacks.second.Run(); 78 } 79 } 80 81 std::string BluetoothRemoteGattCharacteristicChromeOS::GetIdentifier() const { 82 return object_path_.value(); 83 } 84 85 device::BluetoothUUID 86 BluetoothRemoteGattCharacteristicChromeOS::GetUUID() const { 87 BluetoothGattCharacteristicClient::Properties* properties = 88 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()-> 89 GetProperties(object_path_); 90 DCHECK(properties); 91 return device::BluetoothUUID(properties->uuid.value()); 92 } 93 94 bool BluetoothRemoteGattCharacteristicChromeOS::IsLocal() const { 95 return false; 96 } 97 98 const std::vector<uint8>& 99 BluetoothRemoteGattCharacteristicChromeOS::GetValue() const { 100 return cached_value_; 101 } 102 103 device::BluetoothGattService* 104 BluetoothRemoteGattCharacteristicChromeOS::GetService() const { 105 return service_; 106 } 107 108 device::BluetoothGattCharacteristic::Properties 109 BluetoothRemoteGattCharacteristicChromeOS::GetProperties() const { 110 BluetoothGattCharacteristicClient::Properties* properties = 111 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()-> 112 GetProperties(object_path_); 113 DCHECK(properties); 114 115 Properties props = kPropertyNone; 116 const std::vector<std::string>& flags = properties->flags.value(); 117 for (std::vector<std::string>::const_iterator iter = flags.begin(); 118 iter != flags.end(); 119 ++iter) { 120 if (*iter == bluetooth_gatt_characteristic::kFlagBroadcast) 121 props |= kPropertyBroadcast; 122 if (*iter == bluetooth_gatt_characteristic::kFlagRead) 123 props |= kPropertyRead; 124 if (*iter == bluetooth_gatt_characteristic::kFlagWriteWithoutResponse) 125 props |= kPropertyWriteWithoutResponse; 126 if (*iter == bluetooth_gatt_characteristic::kFlagWrite) 127 props |= kPropertyWrite; 128 if (*iter == bluetooth_gatt_characteristic::kFlagNotify) 129 props |= kPropertyNotify; 130 if (*iter == bluetooth_gatt_characteristic::kFlagIndicate) 131 props |= kPropertyIndicate; 132 if (*iter == bluetooth_gatt_characteristic::kFlagAuthenticatedSignedWrites) 133 props |= kPropertyAuthenticatedSignedWrites; 134 if (*iter == bluetooth_gatt_characteristic::kFlagExtendedProperties) 135 props |= kPropertyExtendedProperties; 136 if (*iter == bluetooth_gatt_characteristic::kFlagReliableWrite) 137 props |= kPropertyReliableWrite; 138 if (*iter == bluetooth_gatt_characteristic::kFlagWritableAuxiliaries) 139 props |= kPropertyWritableAuxiliaries; 140 } 141 142 return props; 143 } 144 145 device::BluetoothGattCharacteristic::Permissions 146 BluetoothRemoteGattCharacteristicChromeOS::GetPermissions() const { 147 // TODO(armansito): Once BlueZ defines the permissions, return the correct 148 // values here. 149 return kPermissionNone; 150 } 151 152 bool BluetoothRemoteGattCharacteristicChromeOS::IsNotifying() const { 153 BluetoothGattCharacteristicClient::Properties* properties = 154 DBusThreadManager::Get() 155 ->GetBluetoothGattCharacteristicClient() 156 ->GetProperties(object_path_); 157 DCHECK(properties); 158 159 return properties->notifying.value(); 160 } 161 162 std::vector<device::BluetoothGattDescriptor*> 163 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptors() const { 164 std::vector<device::BluetoothGattDescriptor*> descriptors; 165 for (DescriptorMap::const_iterator iter = descriptors_.begin(); 166 iter != descriptors_.end(); ++iter) 167 descriptors.push_back(iter->second); 168 return descriptors; 169 } 170 171 device::BluetoothGattDescriptor* 172 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptor( 173 const std::string& identifier) const { 174 DescriptorMap::const_iterator iter = 175 descriptors_.find(dbus::ObjectPath(identifier)); 176 if (iter == descriptors_.end()) 177 return NULL; 178 return iter->second; 179 } 180 181 bool BluetoothRemoteGattCharacteristicChromeOS::AddDescriptor( 182 device::BluetoothGattDescriptor* descriptor) { 183 VLOG(1) << "Descriptors cannot be added to a remote GATT characteristic."; 184 return false; 185 } 186 187 bool BluetoothRemoteGattCharacteristicChromeOS::UpdateValue( 188 const std::vector<uint8>& value) { 189 VLOG(1) << "Cannot update the value of a remote GATT characteristic."; 190 return false; 191 } 192 193 void BluetoothRemoteGattCharacteristicChromeOS::ReadRemoteCharacteristic( 194 const ValueCallback& callback, 195 const ErrorCallback& error_callback) { 196 VLOG(1) << "Sending GATT characteristic read request to characteristic: " 197 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value() 198 << "."; 199 200 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->ReadValue( 201 object_path_, 202 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnValueSuccess, 203 weak_ptr_factory_.GetWeakPtr(), 204 callback), 205 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError, 206 weak_ptr_factory_.GetWeakPtr(), 207 error_callback)); 208 } 209 210 void BluetoothRemoteGattCharacteristicChromeOS::WriteRemoteCharacteristic( 211 const std::vector<uint8>& new_value, 212 const base::Closure& callback, 213 const ErrorCallback& error_callback) { 214 VLOG(1) << "Sending GATT characteristic write request to characteristic: " 215 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value() 216 << ", with value: " << new_value << "."; 217 218 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->WriteValue( 219 object_path_, 220 new_value, 221 callback, 222 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError, 223 weak_ptr_factory_.GetWeakPtr(), 224 error_callback)); 225 } 226 227 void BluetoothRemoteGattCharacteristicChromeOS::StartNotifySession( 228 const NotifySessionCallback& callback, 229 const ErrorCallback& error_callback) { 230 VLOG(1) << __func__; 231 232 if (num_notify_sessions_ > 0) { 233 // The characteristic might have stopped notifying even though the session 234 // count is nonzero. This means that notifications stopped outside of our 235 // control and we should reset the count. If the characteristic is still 236 // notifying, then return success. Otherwise, reset the count and treat 237 // this call as if the count were 0. 238 if (IsNotifying()) { 239 // Check for overflows, though unlikely. 240 if (num_notify_sessions_ == std::numeric_limits<size_t>::max()) { 241 error_callback.Run(); 242 return; 243 } 244 245 ++num_notify_sessions_; 246 DCHECK(service_); 247 DCHECK(service_->GetDevice()); 248 scoped_ptr<device::BluetoothGattNotifySession> session( 249 new BluetoothGattNotifySessionChromeOS( 250 service_->GetAdapter(), 251 service_->GetDevice()->GetAddress(), 252 service_->GetIdentifier(), 253 GetIdentifier(), 254 object_path_)); 255 callback.Run(session.Pass()); 256 return; 257 } 258 259 num_notify_sessions_ = 0; 260 } 261 262 // Queue the callbacks if there is a pending call to bluetoothd. 263 if (notify_call_pending_) { 264 pending_start_notify_calls_.push(std::make_pair(callback, error_callback)); 265 return; 266 } 267 268 notify_call_pending_ = true; 269 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StartNotify( 270 object_path_, 271 base::Bind( 272 &BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess, 273 weak_ptr_factory_.GetWeakPtr(), 274 callback), 275 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError, 276 weak_ptr_factory_.GetWeakPtr(), 277 error_callback)); 278 } 279 280 void BluetoothRemoteGattCharacteristicChromeOS::RemoveNotifySession( 281 const base::Closure& callback) { 282 VLOG(1) << __func__; 283 284 if (num_notify_sessions_ > 1) { 285 DCHECK(!notify_call_pending_); 286 --num_notify_sessions_; 287 callback.Run(); 288 return; 289 } 290 291 // Notifications may have stopped outside our control. If the characteristic 292 // is no longer notifying, return success. 293 if (!IsNotifying()) { 294 num_notify_sessions_ = 0; 295 callback.Run(); 296 return; 297 } 298 299 if (notify_call_pending_ || num_notify_sessions_ == 0) { 300 callback.Run(); 301 return; 302 } 303 304 DCHECK(num_notify_sessions_ == 1); 305 notify_call_pending_ = true; 306 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StopNotify( 307 object_path_, 308 base::Bind( 309 &BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess, 310 weak_ptr_factory_.GetWeakPtr(), 311 callback), 312 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError, 313 weak_ptr_factory_.GetWeakPtr(), 314 callback)); 315 } 316 317 void BluetoothRemoteGattCharacteristicChromeOS::GattCharacteristicValueUpdated( 318 const dbus::ObjectPath& object_path, 319 const std::vector<uint8>& value) { 320 if (object_path != object_path_) 321 return; 322 323 cached_value_ = value; 324 325 VLOG(1) << "GATT characteristic value has changed: " << object_path.value() 326 << ": " << value; 327 DCHECK(service_); 328 service_->NotifyCharacteristicValueChanged(this, value); 329 } 330 331 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorAdded( 332 const dbus::ObjectPath& object_path) { 333 if (descriptors_.find(object_path) != descriptors_.end()) { 334 VLOG(1) << "Remote GATT characteristic descriptor already exists: " 335 << object_path.value(); 336 return; 337 } 338 339 BluetoothGattDescriptorClient::Properties* properties = 340 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()-> 341 GetProperties(object_path); 342 DCHECK(properties); 343 if (properties->characteristic.value() != object_path_) { 344 VLOG(2) << "Remote GATT descriptor does not belong to this characteristic."; 345 return; 346 } 347 348 VLOG(1) << "Adding new remote GATT descriptor for GATT characteristic: " 349 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); 350 351 BluetoothRemoteGattDescriptorChromeOS* descriptor = 352 new BluetoothRemoteGattDescriptorChromeOS(this, object_path); 353 descriptors_[object_path] = descriptor; 354 DCHECK(descriptor->GetIdentifier() == object_path.value()); 355 DCHECK(descriptor->GetUUID().IsValid()); 356 DCHECK(service_); 357 358 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, true /* added */); 359 service_->NotifyServiceChanged(); 360 } 361 362 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorRemoved( 363 const dbus::ObjectPath& object_path) { 364 DescriptorMap::iterator iter = descriptors_.find(object_path); 365 if (iter == descriptors_.end()) { 366 VLOG(2) << "Unknown descriptor removed: " << object_path.value(); 367 return; 368 } 369 370 VLOG(1) << "Removing remote GATT descriptor from characteristic: " 371 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); 372 373 BluetoothRemoteGattDescriptorChromeOS* descriptor = iter->second; 374 DCHECK(descriptor->object_path() == object_path); 375 descriptors_.erase(iter); 376 377 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, false /* added */); 378 delete descriptor; 379 380 DCHECK(service_); 381 382 service_->NotifyServiceChanged(); 383 } 384 385 void BluetoothRemoteGattCharacteristicChromeOS::OnValueSuccess( 386 const ValueCallback& callback, 387 const std::vector<uint8>& value) { 388 VLOG(1) << "Characteristic value read: " << value; 389 cached_value_ = value; 390 391 DCHECK(service_); 392 service_->NotifyCharacteristicValueChanged(this, cached_value_); 393 394 callback.Run(value); 395 } 396 397 void BluetoothRemoteGattCharacteristicChromeOS::OnError( 398 const ErrorCallback& error_callback, 399 const std::string& error_name, 400 const std::string& error_message) { 401 VLOG(1) << "Operation failed: " << error_name << ", message: " 402 << error_message; 403 error_callback.Run(); 404 } 405 406 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess( 407 const NotifySessionCallback& callback) { 408 VLOG(1) << "Started notifications from characteristic: " 409 << object_path_.value(); 410 DCHECK(num_notify_sessions_ == 0); 411 DCHECK(notify_call_pending_); 412 413 ++num_notify_sessions_; 414 notify_call_pending_ = false; 415 416 // Invoke the queued callbacks for this operation. 417 DCHECK(service_); 418 DCHECK(service_->GetDevice()); 419 scoped_ptr<device::BluetoothGattNotifySession> session( 420 new BluetoothGattNotifySessionChromeOS( 421 service_->GetAdapter(), 422 service_->GetDevice()->GetAddress(), 423 service_->GetIdentifier(), 424 GetIdentifier(), 425 object_path_)); 426 callback.Run(session.Pass()); 427 428 ProcessStartNotifyQueue(); 429 } 430 431 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError( 432 const ErrorCallback& error_callback, 433 const std::string& error_name, 434 const std::string& error_message) { 435 VLOG(1) << "Failed to start notifications from characteristic: " 436 << object_path_.value() << ": " << error_name << ", " 437 << error_message; 438 DCHECK(num_notify_sessions_ == 0); 439 DCHECK(notify_call_pending_); 440 441 notify_call_pending_ = false; 442 error_callback.Run(); 443 444 ProcessStartNotifyQueue(); 445 } 446 447 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess( 448 const base::Closure& callback) { 449 DCHECK(notify_call_pending_); 450 DCHECK(num_notify_sessions_ == 1); 451 452 notify_call_pending_ = false; 453 --num_notify_sessions_; 454 callback.Run(); 455 456 ProcessStartNotifyQueue(); 457 } 458 459 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError( 460 const base::Closure& callback, 461 const std::string& error_name, 462 const std::string& error_message) { 463 VLOG(1) << "Call to stop notifications failed for characteristic: " 464 << object_path_.value() << ": " << error_name << ", " 465 << error_message; 466 467 // Since this is a best effort operation, treat this as success. 468 OnStopNotifySuccess(callback); 469 } 470 471 void BluetoothRemoteGattCharacteristicChromeOS::ProcessStartNotifyQueue() { 472 while (!pending_start_notify_calls_.empty()) { 473 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front(); 474 pending_start_notify_calls_.pop(); 475 StartNotifySession(callbacks.first, callbacks.second); 476 } 477 } 478 479 } // namespace chromeos 480