Home | History | Annotate | Download | only in bluetooth
      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