blob: c008b91d5839ad98e6dbd395b781762cad3ea637 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/floss/bluetooth_remote_gatt_characteristic_floss.h"
#include "base/containers/to_vector.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_gatt_service.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
#include "device/bluetooth/floss/bluetooth_adapter_floss.h"
#include "device/bluetooth/floss/bluetooth_device_floss.h"
#include "device/bluetooth/floss/bluetooth_gatt_service_floss.h"
#include "device/bluetooth/floss/bluetooth_remote_gatt_descriptor_floss.h"
#include "device/bluetooth/floss/bluetooth_remote_gatt_service_floss.h"
#include "device/bluetooth/floss/floss_dbus_manager.h"
#include "device/bluetooth/floss/floss_gatt_manager_client.h"
namespace floss {
// static
std::unique_ptr<BluetoothRemoteGattCharacteristicFloss>
BluetoothRemoteGattCharacteristicFloss::Create(
BluetoothRemoteGattServiceFloss* service,
GattCharacteristic* characteristic) {
return base::WrapUnique(
new BluetoothRemoteGattCharacteristicFloss(service, characteristic));
}
BluetoothRemoteGattCharacteristicFloss::BluetoothRemoteGattCharacteristicFloss(
BluetoothRemoteGattServiceFloss* service,
GattCharacteristic* characteristic)
: characteristic_(characteristic), service_(service) {
DCHECK(service);
DCHECK(service->GetDevice());
DCHECK(characteristic);
service_->AddObserverForHandle(characteristic_->instance_id, this);
device_address_ = service_->GetDevice()->GetAddress();
for (GattDescriptor& d : characteristic_->descriptors) {
AddDescriptor(
BluetoothRemoteGattDescriptorFloss::Create(service_, this, &d));
}
}
BluetoothRemoteGattCharacteristicFloss::
~BluetoothRemoteGattCharacteristicFloss() {
// Reply to pending callbacks
if (std::get<1>(pending_write_callbacks_)) {
auto [callback, error_callback, data] = std::move(pending_write_callbacks_);
if (error_callback) {
std::move(error_callback)
.Run(BluetoothGattServiceFloss::GattErrorCode::kUnknown);
}
}
if (pending_read_callback_) {
std::move(pending_read_callback_)
.Run(BluetoothGattServiceFloss::GattErrorCode::kUnknown, {});
}
descriptors_.clear();
service_->RemoveObserverForHandle(characteristic_->instance_id);
}
std::string BluetoothRemoteGattCharacteristicFloss::GetIdentifier() const {
return base::StringPrintf("%s/%04x", service_->GetIdentifier().c_str(),
characteristic_->instance_id);
}
device::BluetoothUUID BluetoothRemoteGattCharacteristicFloss::GetUUID() const {
return characteristic_->uuid;
}
BluetoothRemoteGattCharacteristicFloss::Properties
BluetoothRemoteGattCharacteristicFloss::GetProperties() const {
const auto& [props, perms] = ConvertPropsAndPermsFromFloss(
characteristic_->properties, characteristic_->permissions);
return props;
}
BluetoothRemoteGattCharacteristicFloss::Permissions
BluetoothRemoteGattCharacteristicFloss::GetPermissions() const {
const auto& [props, perms] = ConvertPropsAndPermsFromFloss(
characteristic_->properties, characteristic_->permissions);
return perms;
}
const std::vector<uint8_t>& BluetoothRemoteGattCharacteristicFloss::GetValue()
const {
return cached_data_;
}
device::BluetoothRemoteGattService*
BluetoothRemoteGattCharacteristicFloss::GetService() const {
return static_cast<device::BluetoothRemoteGattService*>(service_.get());
}
void BluetoothRemoteGattCharacteristicFloss::ReadRemoteCharacteristic(
ValueCallback callback) {
DCHECK_GE(num_of_reads_in_progress_, 0);
++num_of_reads_in_progress_;
AuthRequired auth = GetAuthForRead();
FlossDBusManager::Get()->GetGattManagerClient()->ReadCharacteristic(
base::BindOnce(
&BluetoothRemoteGattCharacteristicFloss::OnReadCharacteristic,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
device_address_, characteristic_->instance_id, auth);
}
void BluetoothRemoteGattCharacteristicFloss::WriteRemoteCharacteristic(
base::span<const uint8_t> value,
device::BluetoothRemoteGattCharacteristic::WriteType write_type,
base::OnceClosure callback,
ErrorCallback error_callback) {
floss::WriteType gatt_write_type = floss::WriteType::kWriteNoResponse;
if (write_type ==
device::BluetoothRemoteGattCharacteristic::WriteType::kWithResponse) {
gatt_write_type = floss::WriteType::kWrite;
}
WriteRemoteCharacteristicImpl(value, gatt_write_type, std::move(callback),
std::move(error_callback));
}
void BluetoothRemoteGattCharacteristicFloss::
DeprecatedWriteRemoteCharacteristic(base::span<const uint8_t> value,
base::OnceClosure callback,
ErrorCallback error_callback) {
Properties props = GetProperties();
floss::WriteType write_type = floss::WriteType::kWrite;
if (props & PROPERTY_WRITE_WITHOUT_RESPONSE) {
write_type = floss::WriteType::kWriteNoResponse;
}
WriteRemoteCharacteristicImpl(value, write_type, std::move(callback),
std::move(error_callback));
}
#if BUILDFLAG(IS_CHROMEOS)
void BluetoothRemoteGattCharacteristicFloss::PrepareWriteRemoteCharacteristic(
base::span<const uint8_t> value,
base::OnceClosure callback,
ErrorCallback error_callback) {
// Make sure we're using reliable writes before starting a prepared write.
BluetoothDeviceFloss* device =
static_cast<BluetoothDeviceFloss*>(service_->GetDevice());
if (device && !device->UsingReliableWrite()) {
device->BeginReliableWrite();
}
WriteRemoteCharacteristicImpl(value, floss::WriteType::kWritePrepare,
std::move(callback), std::move(error_callback));
}
#endif // BUILDFLAG(IS_CHROMEOS)
void BluetoothRemoteGattCharacteristicFloss::WriteRemoteCharacteristicImpl(
base::span<const uint8_t> value,
floss::WriteType write_type,
base::OnceClosure callback,
ErrorCallback error_callback) {
AuthRequired auth = GetAuthForWrite();
FlossDBusManager::Get()->GetGattManagerClient()->WriteCharacteristic(
base::BindOnce(
&BluetoothRemoteGattCharacteristicFloss::OnWriteCharacteristic,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(error_callback), base::ToVector(value)),
device_address_, characteristic_->instance_id, write_type, auth, value);
}
void BluetoothRemoteGattCharacteristicFloss::GattCharacteristicRead(
std::string address,
GattStatus status,
int32_t handle,
const std::vector<uint8_t>& data) {
// Make sure this notification is for this characteristic.
if (handle != characteristic_->instance_id || address != device_address_) {
return;
}
if (num_of_reads_in_progress_ == 0 || !pending_read_callback_) {
return;
}
--num_of_reads_in_progress_;
DCHECK_GE(num_of_reads_in_progress_, 0);
if (status == GattStatus::kSuccess) {
cached_data_ = data;
std::move(pending_read_callback_)
.Run(/*error_code=*/std::nullopt, cached_data_);
} else {
std::move(pending_read_callback_)
.Run(BluetoothGattServiceFloss::GattStatusToServiceError(status), {});
}
}
void BluetoothRemoteGattCharacteristicFloss::GattCharacteristicWrite(
std::string address,
GattStatus status,
int32_t handle) {
// Make sure this notification is for this characteristic.
if (handle != characteristic_->instance_id || address != device_address_) {
return;
}
auto [callback, error_callback, data] = std::move(pending_write_callbacks_);
if (!callback || !error_callback) {
return;
}
if (status == GattStatus::kSuccess) {
cached_data_ = data;
std::move(callback).Run();
} else {
std::move(error_callback)
.Run(BluetoothGattServiceFloss::GattStatusToServiceError(status));
}
}
void BluetoothRemoteGattCharacteristicFloss::GattNotify(
std::string address,
int32_t handle,
const std::vector<uint8_t>& data) {
// Make sure this notification is for this characteristic.
if (handle != characteristic_->instance_id || address != device_address_) {
return;
}
cached_data_ = data;
NotifyValueChanged();
}
void BluetoothRemoteGattCharacteristicFloss::OnReadCharacteristic(
ValueCallback callback,
DBusResult<Void> result) {
if (!result.has_value()) {
--num_of_reads_in_progress_;
DCHECK_GE(num_of_reads_in_progress_, 0);
std::move(callback).Run(
/*error_code=*/BluetoothGattServiceFloss::GattErrorCode::kFailed, {});
return;
}
pending_read_callback_ = std::move(callback);
}
void BluetoothRemoteGattCharacteristicFloss::OnWriteCharacteristic(
base::OnceClosure callback,
ErrorCallback error_callback,
std::vector<uint8_t> data,
DBusResult<GattWriteRequestStatus> result) {
if (!result.has_value()) {
std::move(error_callback)
.Run(/*error_code=*/BluetoothGattServiceFloss::GattErrorCode::kFailed);
return;
}
if (result.value() != GattWriteRequestStatus::kSuccess) {
BluetoothGattServiceFloss::GattErrorCode error_code =
(result.value() == GattWriteRequestStatus::kBusy
? BluetoothGattServiceFloss::GattErrorCode::kInProgress
: BluetoothGattServiceFloss::GattErrorCode::kFailed);
std::move(error_callback).Run(error_code);
return;
}
pending_write_callbacks_ = std::make_tuple(
std::move(callback), std::move(error_callback), std::move(data));
}
void BluetoothRemoteGattCharacteristicFloss::SubscribeToNotifications(
device::BluetoothRemoteGattDescriptor* ccc_descriptor,
#if BUILDFLAG(IS_CHROMEOS)
NotificationType notification_type,
#endif // BUILDFLAG(IS_CHROMEOS)
base::OnceClosure callback,
ErrorCallback error_callback) {
#if !BUILDFLAG(IS_CHROMEOS)
NotificationType notification_type = NotificationType::kNotification;
#endif
// Set CCCD value to notification type
std::vector<uint8_t> value = {static_cast<uint8_t>(notification_type), 0};
// Register this characteristic for notifications
FlossDBusManager::Get()->GetGattManagerClient()->RegisterForNotification(
base::BindOnce(
&BluetoothRemoteGattCharacteristicFloss::OnRegisterForNotification,
weak_ptr_factory_.GetWeakPtr(), ccc_descriptor, value,
std::move(callback), std::move(error_callback)),
device_address_, characteristic_->instance_id);
}
void BluetoothRemoteGattCharacteristicFloss::UnsubscribeFromNotifications(
device::BluetoothRemoteGattDescriptor* ccc_descriptor,
base::OnceClosure callback,
ErrorCallback error_callback) {
// Set CCCD value back to default
std::vector<uint8_t> value = {0, 0};
// Unregister this characteristic for notifications
FlossDBusManager::Get()->GetGattManagerClient()->UnregisterNotification(
base::BindOnce(
&BluetoothRemoteGattCharacteristicFloss::OnRegisterForNotification,
weak_ptr_factory_.GetWeakPtr(), ccc_descriptor, value,
std::move(callback), std::move(error_callback)),
device_address_, characteristic_->instance_id);
}
void BluetoothRemoteGattCharacteristicFloss::OnRegisterForNotification(
device::BluetoothRemoteGattDescriptor* ccc_descriptor,
const std::vector<uint8_t>& value,
base::OnceClosure callback,
ErrorCallback error_callback,
DBusResult<GattStatus> result) {
if (!result.has_value() || result.value() != GattStatus::kSuccess) {
std::move(error_callback)
.Run(/*error_code=*/BluetoothGattServiceFloss::GattStatusToServiceError(
result.value()));
return;
}
BluetoothRemoteGattDescriptorFloss* descriptor =
static_cast<BluetoothRemoteGattDescriptorFloss*>(ccc_descriptor);
DCHECK(descriptor);
// Write to the Client Characteristic Configuration descriptor.
descriptor->WriteRemoteDescriptor(value, std::move(callback),
std::move(error_callback));
}
AuthRequired BluetoothRemoteGattCharacteristicFloss::GetAuthForRead() const {
AuthRequired auth = AuthRequired::kNoAuth;
Properties props = GetProperties();
if (props & PROPERTY_READ_ENCRYPTED_AUTHENTICATED) {
auth = AuthRequired::kReqMitm;
} else if (props & PROPERTY_READ_ENCRYPTED) {
auth = AuthRequired::kNoMitm;
}
return auth;
}
AuthRequired BluetoothRemoteGattCharacteristicFloss::GetAuthForWrite() const {
AuthRequired auth = AuthRequired::kNoAuth;
Properties props = GetProperties();
if (props & PROPERTY_WRITE_ENCRYPTED_AUTHENTICATED) {
auth = AuthRequired::kReqMitm;
if (props & PROPERTY_AUTHENTICATED_SIGNED_WRITES) {
auth = AuthRequired::kSignedReqMitm;
}
} else if (props & PROPERTY_WRITE_ENCRYPTED) {
auth = AuthRequired::kNoMitm;
if (props & PROPERTY_AUTHENTICATED_SIGNED_WRITES) {
auth = AuthRequired::kSignedNoMitm;
}
}
return auth;
}
void BluetoothRemoteGattCharacteristicFloss::NotifyValueChanged() {
DCHECK(service_->GetAdapter());
service_->GetAdapter()->NotifyGattCharacteristicValueChanged(this,
cached_data_);
}
} // namespace floss