chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h"

#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/win/post_async_results.h"
#include "base/win/winrt_storage_util.h"
#include "components/device_event_log/device_event_log.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_gatt_discoverer_winrt.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h"
#include "device/bluetooth/bluetooth_remote_gatt_service.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_winrt.h"
#include "device/bluetooth/event_utils_winrt.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"

namespace device {

namespace {

using ABI::Windows::Devices::Bluetooth::BluetoothCacheMode_Uncached;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattCharacteristicProperties;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattClientCharacteristicConfigurationDescriptorValue;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattClientCharacteristicConfigurationDescriptorValue_Indicate;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattClientCharacteristicConfigurationDescriptorValue_None;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattClientCharacteristicConfigurationDescriptorValue_Notify;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattCommunicationStatus;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattCommunicationStatus_Success;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattReadResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattWriteOption;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattWriteOption_WriteWithoutResponse;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattWriteOption_WriteWithResponse;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    GattWriteResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    IGattCharacteristic;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    IGattCharacteristic3;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    IGattReadResult;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    IGattReadResult2;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    IGattValueChangedEventArgs;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
    IGattWriteResult;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Storage::Streams::IBuffer;
using Microsoft::WRL::ComPtr;

}  // namespace

// static
std::unique_ptr<BluetoothRemoteGattCharacteristicWinrt>
BluetoothRemoteGattCharacteristicWinrt::Create(
    BluetoothRemoteGattService* service,
    ComPtr<IGattCharacteristic> characteristic) {
  DCHECK(characteristic);
  GUID guid;
  HRESULT hr = characteristic->get_Uuid(&guid);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting UUID failed: "
                         << logging::SystemErrorCodeToString(hr);
    return nullptr;
  }

  GattCharacteristicProperties properties;
  hr = characteristic->get_CharacteristicProperties(&properties);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting Properties failed: "
                         << logging::SystemErrorCodeToString(hr);
    return nullptr;
  }

  uint16_t attribute_handle;
  hr = characteristic->get_AttributeHandle(&attribute_handle);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting AttributeHandle failed: "
                         << logging::SystemErrorCodeToString(hr);
    return nullptr;
  }

  return base::WrapUnique(new BluetoothRemoteGattCharacteristicWinrt(
      service, std::move(characteristic), BluetoothUUID(guid), properties,
      attribute_handle));
}

BluetoothRemoteGattCharacteristicWinrt::
    ~BluetoothRemoteGattCharacteristicWinrt() {
  destructor_called_ = true;
  if (pending_read_callback_) {
    std::move(pending_read_callback_)
        .Run(BluetoothGattService::GattErrorCode::kFailed,
             /*value=*/std::vector<uint8_t>());
  }

  if (pending_write_callbacks_) {
    std::move(pending_write_callbacks_->error_callback)
        .Run(BluetoothGattService::GattErrorCode::kFailed);
  }

  if (value_changed_token_)
    RemoveValueChangedHandler();
}

std::string BluetoothRemoteGattCharacteristicWinrt::GetIdentifier() const {
  return identifier_;
}

BluetoothUUID BluetoothRemoteGattCharacteristicWinrt::GetUUID() const {
  return uuid_;
}

BluetoothGattCharacteristic::Properties
BluetoothRemoteGattCharacteristicWinrt::GetProperties() const {
  return properties_;
}

BluetoothGattCharacteristic::Permissions
BluetoothRemoteGattCharacteristicWinrt::GetPermissions() const {
  NOTIMPLEMENTED();
  return Permissions();
}

const std::vector<uint8_t>& BluetoothRemoteGattCharacteristicWinrt::GetValue()
    const {
  return value_;
}

BluetoothRemoteGattService* BluetoothRemoteGattCharacteristicWinrt::GetService()
    const {
  return service_;
}

void BluetoothRemoteGattCharacteristicWinrt::ReadRemoteCharacteristic(
    ValueCallback callback) {
  if (!(GetProperties() & PROPERTY_READ)) {
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(callback),
                       BluetoothGattService::GattErrorCode::kNotPermitted,
                       /*value=*/std::vector<uint8_t>()));
    return;
  }

  if (destructor_called_ || pending_read_callback_ ||
      pending_write_callbacks_) {
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(callback),
                       BluetoothGattService::GattErrorCode::kInProgress,
                       /*value=*/std::vector<uint8_t>()));
    return;
  }

  ComPtr<IAsyncOperation<GattReadResult*>> read_value_op;
  HRESULT hr = characteristic_->ReadValueWithCacheModeAsync(
      BluetoothCacheMode_Uncached, &read_value_op);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG)
        << "GattCharacteristic::ReadValueWithCacheModeAsync failed: "
        << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE, base::BindOnce(std::move(callback),
                                  BluetoothGattService::GattErrorCode::kFailed,
                                  /*value=*/std::vector<uint8_t>()));
    return;
  }

  hr = base::win::PostAsyncResults(
      std::move(read_value_op),
      base::BindOnce(&BluetoothRemoteGattCharacteristicWinrt::OnReadValue,
                     weak_ptr_factory_.GetWeakPtr()));

  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
                         << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE, base::BindOnce(std::move(callback),
                                  BluetoothGattService::GattErrorCode::kFailed,
                                  /*value=*/std::vector<uint8_t>()));
    return;
  }

  pending_read_callback_ = std::move(callback);
}

void BluetoothRemoteGattCharacteristicWinrt::WriteRemoteCharacteristic(
    const std::vector<uint8_t>& value,
    WriteType write_type,
    base::OnceClosure callback,
    ErrorCallback error_callback) {
  if (destructor_called_ || pending_read_callback_ ||
      pending_write_callbacks_) {
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kInProgress));
    return;
  }

  ComPtr<IGattCharacteristic3> characteristic_3;
  HRESULT hr = characteristic_.As(&characteristic_3);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "As IGattCharacteristic3 failed: "
                         << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  ComPtr<IBuffer> buffer;
  hr = base::win::CreateIBufferFromData(value.data(), value.size(), &buffer);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "base::win::CreateIBufferFromData failed: "
                         << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  GattWriteOption write_option;
  switch (write_type) {
    case WriteType::kWithResponse:
      write_option = GattWriteOption_WriteWithResponse;
      break;
    case WriteType::kWithoutResponse:
      write_option = GattWriteOption_WriteWithoutResponse;
      break;
  }

  ComPtr<IAsyncOperation<GattWriteResult*>> write_value_op;
  hr = characteristic_3->WriteValueWithResultAndOptionAsync(
      buffer.Get(), write_option, &write_value_op);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG)
        << "GattCharacteristic::WriteValueWithResultAndOptionAsync failed: "
        << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  hr = base::win::PostAsyncResults(
      std::move(write_value_op),
      base::BindOnce(&BluetoothRemoteGattCharacteristicWinrt::
                         OnWriteValueWithResultAndOption,
                     weak_ptr_factory_.GetWeakPtr()));

  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
                         << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  pending_write_callbacks_ = std::make_unique<PendingWriteCallbacks>(
      std::move(callback), std::move(error_callback));
}

void BluetoothRemoteGattCharacteristicWinrt::
    DeprecatedWriteRemoteCharacteristic(const std::vector<uint8_t>& value,
                                        base::OnceClosure callback,
                                        ErrorCallback error_callback) {
  if (!(GetProperties() & PROPERTY_WRITE) &&
      !(GetProperties() & PROPERTY_WRITE_WITHOUT_RESPONSE)) {
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kNotPermitted));
    return;
  }

  WriteType write_type = (GetProperties() & PROPERTY_WRITE)
                             ? WriteType::kWithResponse
                             : WriteType::kWithoutResponse;

  WriteRemoteCharacteristic(value, write_type, std::move(callback),
                            std::move(error_callback));
}

void BluetoothRemoteGattCharacteristicWinrt::UpdateDescriptors(
    BluetoothGattDiscovererWinrt* gatt_discoverer) {
  const auto* gatt_descriptors =
      gatt_discoverer->GetDescriptors(attribute_handle_);
  DCHECK(gatt_descriptors);

  // Instead of clearing out |descriptors_| and creating each descriptor
  // from scratch, we create a new map and move already existing descriptors
  // into it in order to preserve pointer stability.
  DescriptorMap descriptors;
  for (const auto& gatt_descriptor : *gatt_descriptors) {
    auto descriptor =
        BluetoothRemoteGattDescriptorWinrt::Create(this, gatt_descriptor.Get());
    if (!descriptor)
      continue;

    std::string identifier = descriptor->GetIdentifier();
    auto iter = descriptors_.find(identifier);
    if (iter != descriptors_.end())
      descriptors.emplace(std::move(*iter));
    else
      descriptors.emplace(std::move(identifier), std::move(descriptor));
  }

  std::swap(descriptors, descriptors_);
}

IGattCharacteristic*
BluetoothRemoteGattCharacteristicWinrt::GetCharacteristicForTesting() {
  return characteristic_.Get();
}

void BluetoothRemoteGattCharacteristicWinrt::SubscribeToNotifications(
    BluetoothRemoteGattDescriptor* ccc_descriptor,
    base::OnceClosure callback,
    ErrorCallback error_callback) {
  value_changed_token_ = AddTypedEventHandler(
      characteristic_.Get(), &IGattCharacteristic::add_ValueChanged,
      base::BindRepeating(
          &BluetoothRemoteGattCharacteristicWinrt::OnValueChanged,
          weak_ptr_factory_.GetWeakPtr()));

  if (!value_changed_token_) {
    BLUETOOTH_LOG(DEBUG) << "Adding Value Changed Handler failed.";
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  WriteCccDescriptor(
      (GetProperties() & PROPERTY_NOTIFY)
          ? GattClientCharacteristicConfigurationDescriptorValue_Notify
          : GattClientCharacteristicConfigurationDescriptorValue_Indicate,
      std::move(callback), std::move(error_callback));
}

void BluetoothRemoteGattCharacteristicWinrt::UnsubscribeFromNotifications(
    BluetoothRemoteGattDescriptor* ccc_descriptor,
    base::OnceClosure callback,
    ErrorCallback error_callback) {
  auto split_error_callback =
      base::SplitOnceCallback(std::move(error_callback));
  base::OnceClosure success_callback = base::BindOnce(
      [](base::WeakPtr<BluetoothRemoteGattCharacteristicWinrt> characteristic,
         base::OnceClosure callback, ErrorCallback error_callback) {
        if (characteristic && !characteristic->RemoveValueChangedHandler()) {
          std::move(error_callback)
              .Run(BluetoothGattService::GattErrorCode::kFailed);
          return;
        }

        std::move(callback).Run();
      },
      weak_ptr_factory_.GetWeakPtr(), std::move(callback),
      std::move(split_error_callback.first));
  WriteCccDescriptor(
      GattClientCharacteristicConfigurationDescriptorValue_None,
      // Wrap the success and error callbacks in a lambda, so that we can
      // notify callers whether removing the event handler succeeded after
      // the descriptor has been written to.
      std::move(success_callback), std::move(split_error_callback.second));
}

BluetoothRemoteGattCharacteristicWinrt::PendingWriteCallbacks::
    PendingWriteCallbacks(base::OnceClosure callback,
                          ErrorCallback error_callback)
    : callback(std::move(callback)),
      error_callback(std::move(error_callback)) {}
BluetoothRemoteGattCharacteristicWinrt::PendingWriteCallbacks::
    ~PendingWriteCallbacks() = default;

BluetoothRemoteGattCharacteristicWinrt::BluetoothRemoteGattCharacteristicWinrt(
    BluetoothRemoteGattService* service,
    ComPtr<IGattCharacteristic> characteristic,
    BluetoothUUID uuid,
    Properties properties,
    uint16_t attribute_handle)
    : service_(service),
      characteristic_(std::move(characteristic)),
      uuid_(std::move(uuid)),
      properties_(properties),
      attribute_handle_(attribute_handle),
      identifier_(base::StringPrintf("%s/%s_%04x",
                                     service_->GetIdentifier().c_str(),
                                     uuid_.value().c_str(),
                                     attribute_handle_)) {}

void BluetoothRemoteGattCharacteristicWinrt::WriteCccDescriptor(
    GattClientCharacteristicConfigurationDescriptorValue value,
    base::OnceClosure callback,
    ErrorCallback error_callback) {
  DCHECK(!pending_notification_callbacks_);
  ComPtr<IGattCharacteristic3> characteristic_3;
  HRESULT hr = characteristic_.As(&characteristic_3);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "As IGattCharacteristic3 failed: "
                         << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  ComPtr<IAsyncOperation<GattWriteResult*>> write_ccc_descriptor_op;
  hr = characteristic_3
           ->WriteClientCharacteristicConfigurationDescriptorWithResultAsync(
               value, &write_ccc_descriptor_op);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG)
        << "GattCharacteristic::"
           "WriteClientCharacteristicConfigurationDescriptorWithResultAsync"
           " failed: "
        << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  hr = base::win::PostAsyncResults(
      std::move(write_ccc_descriptor_op),
      base::BindOnce(
          &BluetoothRemoteGattCharacteristicWinrt::OnWriteCccDescriptor,
          weak_ptr_factory_.GetWeakPtr()));

  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
                         << logging::SystemErrorCodeToString(hr);
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(error_callback),
                       BluetoothGattService::GattErrorCode::kFailed));
    return;
  }

  pending_notification_callbacks_ =
      std::make_unique<PendingNotificationCallbacks>(std::move(callback),
                                                     std::move(error_callback));
}

void BluetoothRemoteGattCharacteristicWinrt::OnReadValue(
    ComPtr<IGattReadResult> read_result) {
  DCHECK(pending_read_callback_);
  auto pending_read_callback = std::move(pending_read_callback_);

  if (!read_result) {
    std::move(pending_read_callback)
        .Run(BluetoothGattService::GattErrorCode::kFailed,
             /*value=*/std::vector<uint8_t>());
    return;
  }

  GattCommunicationStatus status;
  HRESULT hr = read_result->get_Status(&status);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting GATT Communication Status failed: "
                         << logging::SystemErrorCodeToString(hr);
    std::move(pending_read_callback)
        .Run(BluetoothGattService::GattErrorCode::kFailed,
             /*value=*/std::vector<uint8_t>());
    return;
  }

  if (status != GattCommunicationStatus_Success) {
    BLUETOOTH_LOG(DEBUG) << "Unexpected GattCommunicationStatus: " << status;
    ComPtr<IGattReadResult2> read_result_2;
    hr = read_result.As(&read_result_2);
    if (FAILED(hr)) {
      BLUETOOTH_LOG(DEBUG) << "As IGattReadResult2 failed: "
                           << logging::SystemErrorCodeToString(hr);
      std::move(pending_read_callback)
          .Run(BluetoothGattService::GattErrorCode::kFailed,
               /*value=*/std::vector<uint8_t>());
      return;
    }

    std::move(pending_read_callback)
        .Run(BluetoothRemoteGattServiceWinrt::GetGattErrorCode(
                 read_result_2.Get()),
             /*value=*/std::vector<uint8_t>());
    return;
  }

  ComPtr<IBuffer> value;
  hr = read_result->get_Value(&value);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting Characteristic Value failed: "
                         << logging::SystemErrorCodeToString(hr);
    std::move(pending_read_callback)
        .Run(BluetoothGattService::GattErrorCode::kFailed,
             /*value=*/std::vector<uint8_t>());
    return;
  }

  uint8_t* data = nullptr;
  uint32_t length = 0;
  hr = base::win::GetPointerToBufferData(value.Get(), &data, &length);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting Pointer To Buffer Data failed: "
                         << logging::SystemErrorCodeToString(hr);
    std::move(pending_read_callback)
        .Run(BluetoothGattService::GattErrorCode::kFailed,
             /*value=*/std::vector<uint8_t>());
    return;
  }

  value_.assign(data, data + length);
  std::move(pending_read_callback).Run(/*error_code=*/std::nullopt, value_);
}

void BluetoothRemoteGattCharacteristicWinrt::OnWriteValueWithResultAndOption(
    ComPtr<IGattWriteResult> write_result) {
  DCHECK(pending_write_callbacks_);
  OnWriteImpl(std::move(write_result), std::move(pending_write_callbacks_));
}

void BluetoothRemoteGattCharacteristicWinrt::OnWriteCccDescriptor(
    ComPtr<IGattWriteResult> write_result) {
  OnWriteImpl(std::move(write_result),
              std::move(pending_notification_callbacks_));
}

void BluetoothRemoteGattCharacteristicWinrt::OnWriteImpl(
    ComPtr<IGattWriteResult> write_result,
    std::unique_ptr<PendingWriteCallbacks> callbacks) {
  if (!write_result) {
    std::move(callbacks->error_callback)
        .Run(BluetoothGattService::GattErrorCode::kFailed);
    return;
  }

  GattCommunicationStatus status;
  HRESULT hr = write_result->get_Status(&status);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting GATT Communication Status failed: "
                         << logging::SystemErrorCodeToString(hr);
    std::move(callbacks->error_callback)
        .Run(BluetoothGattService::GattErrorCode::kFailed);
    return;
  }

  if (status != GattCommunicationStatus_Success) {
    BLUETOOTH_LOG(DEBUG) << "Unexpected GattCommunicationStatus: " << status;
    std::move(callbacks->error_callback)
        .Run(BluetoothRemoteGattServiceWinrt::GetGattErrorCode(
            write_result.Get()));
    return;
  }

  std::move(callbacks->callback).Run();
}

void BluetoothRemoteGattCharacteristicWinrt::OnValueChanged(
    IGattCharacteristic* characteristic,
    IGattValueChangedEventArgs* event_args) {
  ComPtr<IBuffer> value;
  HRESULT hr = event_args->get_CharacteristicValue(&value);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting Characteristic Value failed: "
                         << logging::SystemErrorCodeToString(hr);
    return;
  }

  uint8_t* data = nullptr;
  uint32_t length = 0;
  hr = base::win::GetPointerToBufferData(value.Get(), &data, &length);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Getting Pointer To Buffer Data failed: "
                         << logging::SystemErrorCodeToString(hr);
    return;
  }

  value_.assign(data, data + length);
  service_->GetDevice()->GetAdapter()->NotifyGattCharacteristicValueChanged(
      this, value_);
}

bool BluetoothRemoteGattCharacteristicWinrt::RemoveValueChangedHandler() {
  DCHECK(value_changed_token_);
  HRESULT hr = characteristic_->remove_ValueChanged(*value_changed_token_);
  if (FAILED(hr)) {
    BLUETOOTH_LOG(DEBUG) << "Removing the Value Changed Handler failed: "
                         << logging::SystemErrorCodeToString(hr);
  }

  value_changed_token_.reset();
  return SUCCEEDED(hr);
}

}  // namespace device