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_chromeos.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_->GetAdapter()); 248 DCHECK(service_->GetDevice()); 249 scoped_ptr<device::BluetoothGattNotifySession> session( 250 new BluetoothGattNotifySessionChromeOS( 251 service_->GetAdapter(), 252 service_->GetDevice()->GetAddress(), 253 service_->GetIdentifier(), 254 GetIdentifier(), 255 object_path_)); 256 callback.Run(session.Pass()); 257 return; 258 } 259 260 num_notify_sessions_ = 0; 261 } 262 263 // Queue the callbacks if there is a pending call to bluetoothd. 264 if (notify_call_pending_) { 265 pending_start_notify_calls_.push(std::make_pair(callback, error_callback)); 266 return; 267 } 268 269 notify_call_pending_ = true; 270 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StartNotify( 271 object_path_, 272 base::Bind( 273 &BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess, 274 weak_ptr_factory_.GetWeakPtr(), 275 callback), 276 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError, 277 weak_ptr_factory_.GetWeakPtr(), 278 error_callback)); 279 } 280 281 void BluetoothRemoteGattCharacteristicChromeOS::RemoveNotifySession( 282 const base::Closure& callback) { 283 VLOG(1) << __func__; 284 285 if (num_notify_sessions_ > 1) { 286 DCHECK(!notify_call_pending_); 287 --num_notify_sessions_; 288 callback.Run(); 289 return; 290 } 291 292 // Notifications may have stopped outside our control. If the characteristic 293 // is no longer notifying, return success. 294 if (!IsNotifying()) { 295 num_notify_sessions_ = 0; 296 callback.Run(); 297 return; 298 } 299 300 if (notify_call_pending_ || num_notify_sessions_ == 0) { 301 callback.Run(); 302 return; 303 } 304 305 DCHECK(num_notify_sessions_ == 1); 306 notify_call_pending_ = true; 307 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StopNotify( 308 object_path_, 309 base::Bind( 310 &BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess, 311 weak_ptr_factory_.GetWeakPtr(), 312 callback), 313 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError, 314 weak_ptr_factory_.GetWeakPtr(), 315 callback)); 316 } 317 318 void BluetoothRemoteGattCharacteristicChromeOS::GattCharacteristicValueUpdated( 319 const dbus::ObjectPath& object_path, 320 const std::vector<uint8>& value) { 321 if (object_path != object_path_) 322 return; 323 324 cached_value_ = value; 325 326 VLOG(1) << "GATT characteristic value has changed: " << object_path.value() 327 << ": " << value; 328 DCHECK(service_); 329 service_->NotifyCharacteristicValueChanged(this, value); 330 } 331 332 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorAdded( 333 const dbus::ObjectPath& object_path) { 334 if (descriptors_.find(object_path) != descriptors_.end()) { 335 VLOG(1) << "Remote GATT characteristic descriptor already exists: " 336 << object_path.value(); 337 return; 338 } 339 340 BluetoothGattDescriptorClient::Properties* properties = 341 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()-> 342 GetProperties(object_path); 343 DCHECK(properties); 344 if (properties->characteristic.value() != object_path_) { 345 VLOG(3) << "Remote GATT descriptor does not belong to this characteristic."; 346 return; 347 } 348 349 VLOG(1) << "Adding new remote GATT descriptor for GATT characteristic: " 350 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); 351 352 BluetoothRemoteGattDescriptorChromeOS* descriptor = 353 new BluetoothRemoteGattDescriptorChromeOS(this, object_path); 354 descriptors_[object_path] = descriptor; 355 DCHECK(descriptor->GetIdentifier() == object_path.value()); 356 DCHECK(descriptor->GetUUID().IsValid()); 357 DCHECK(service_); 358 359 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, true /* added */); 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 DCHECK(service_); 378 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, false /* added */); 379 380 delete descriptor; 381 } 382 383 void BluetoothRemoteGattCharacteristicChromeOS::OnValueSuccess( 384 const ValueCallback& callback, 385 const std::vector<uint8>& value) { 386 VLOG(1) << "Characteristic value read: " << value; 387 cached_value_ = value; 388 389 DCHECK(service_); 390 service_->NotifyCharacteristicValueChanged(this, cached_value_); 391 392 callback.Run(value); 393 } 394 395 void BluetoothRemoteGattCharacteristicChromeOS::OnError( 396 const ErrorCallback& error_callback, 397 const std::string& error_name, 398 const std::string& error_message) { 399 VLOG(1) << "Operation failed: " << error_name << ", message: " 400 << error_message; 401 error_callback.Run(); 402 } 403 404 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess( 405 const NotifySessionCallback& callback) { 406 VLOG(1) << "Started notifications from characteristic: " 407 << object_path_.value(); 408 DCHECK(num_notify_sessions_ == 0); 409 DCHECK(notify_call_pending_); 410 411 ++num_notify_sessions_; 412 notify_call_pending_ = false; 413 414 // Invoke the queued callbacks for this operation. 415 DCHECK(service_); 416 DCHECK(service_->GetDevice()); 417 scoped_ptr<device::BluetoothGattNotifySession> session( 418 new BluetoothGattNotifySessionChromeOS( 419 service_->GetAdapter(), 420 service_->GetDevice()->GetAddress(), 421 service_->GetIdentifier(), 422 GetIdentifier(), 423 object_path_)); 424 callback.Run(session.Pass()); 425 426 ProcessStartNotifyQueue(); 427 } 428 429 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError( 430 const ErrorCallback& error_callback, 431 const std::string& error_name, 432 const std::string& error_message) { 433 VLOG(1) << "Failed to start notifications from characteristic: " 434 << object_path_.value() << ": " << error_name << ", " 435 << error_message; 436 DCHECK(num_notify_sessions_ == 0); 437 DCHECK(notify_call_pending_); 438 439 notify_call_pending_ = false; 440 error_callback.Run(); 441 442 ProcessStartNotifyQueue(); 443 } 444 445 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess( 446 const base::Closure& callback) { 447 DCHECK(notify_call_pending_); 448 DCHECK(num_notify_sessions_ == 1); 449 450 notify_call_pending_ = false; 451 --num_notify_sessions_; 452 callback.Run(); 453 454 ProcessStartNotifyQueue(); 455 } 456 457 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError( 458 const base::Closure& callback, 459 const std::string& error_name, 460 const std::string& error_message) { 461 VLOG(1) << "Call to stop notifications failed for characteristic: " 462 << object_path_.value() << ": " << error_name << ", " 463 << error_message; 464 465 // Since this is a best effort operation, treat this as success. 466 OnStopNotifySuccess(callback); 467 } 468 469 void BluetoothRemoteGattCharacteristicChromeOS::ProcessStartNotifyQueue() { 470 while (!pending_start_notify_calls_.empty()) { 471 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front(); 472 pending_start_notify_calls_.pop(); 473 StartNotifySession(callbacks.first, callbacks.second); 474 } 475 } 476 477 } // namespace chromeos 478