blob: 6b8dbc7c10e64f34da724227ab1c58ecc3b55267 [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_descriptor_floss.h"
#include <memory>
#include "base/containers/to_vector.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "components/device_event_log/device_event_log.h"
#include "device/bluetooth/floss/bluetooth_adapter_floss.h"
#include "device/bluetooth/floss/bluetooth_remote_gatt_characteristic_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 {
const int kGattTimeoutMs = 2000;
// static
std::unique_ptr<BluetoothRemoteGattDescriptorFloss>
BluetoothRemoteGattDescriptorFloss::Create(
BluetoothRemoteGattServiceFloss* service,
BluetoothRemoteGattCharacteristicFloss* characteristic,
GattDescriptor* descriptor) {
return base::WrapUnique(new BluetoothRemoteGattDescriptorFloss(
service, characteristic, descriptor));
}
BluetoothRemoteGattDescriptorFloss::BluetoothRemoteGattDescriptorFloss(
BluetoothRemoteGattServiceFloss* service,
BluetoothRemoteGattCharacteristicFloss* characteristic,
GattDescriptor* descriptor)
: characteristic_(characteristic),
descriptor_(descriptor),
service_(service) {
DCHECK(service);
DCHECK(characteristic);
DCHECK(descriptor);
service_->AddObserverForHandle(descriptor_->instance_id, this);
}
BluetoothRemoteGattDescriptorFloss::~BluetoothRemoteGattDescriptorFloss() {
service_->RemoveObserverForHandle(descriptor_->instance_id);
}
std::string BluetoothRemoteGattDescriptorFloss::GetIdentifier() const {
return base::StringPrintf("%s/%04x", characteristic_->GetIdentifier().c_str(),
descriptor_->instance_id);
}
device::BluetoothUUID BluetoothRemoteGattDescriptorFloss::GetUUID() const {
return descriptor_->uuid;
}
const std::vector<uint8_t>& BluetoothRemoteGattDescriptorFloss::GetValue()
const {
return cached_data_;
}
device::BluetoothRemoteGattCharacteristic*
BluetoothRemoteGattDescriptorFloss::GetCharacteristic() const {
return static_cast<device::BluetoothRemoteGattCharacteristic*>(
characteristic_.get());
}
device::BluetoothRemoteGattCharacteristic::Permissions
BluetoothRemoteGattDescriptorFloss::GetPermissions() const {
const auto& [props, perms] =
BluetoothGattCharacteristicFloss::ConvertPropsAndPermsFromFloss(
/*properties=*/0, descriptor_->permissions);
return perms;
}
void BluetoothRemoteGattDescriptorFloss::ReadRemoteDescriptor(
ValueCallback callback) {
DCHECK_GE(num_of_reads_in_progress_, 0);
++num_of_reads_in_progress_;
AuthRequired auth = characteristic_->GetAuthForRead();
FlossDBusManager::Get()->GetGattManagerClient()->ReadDescriptor(
base::BindOnce(&BluetoothRemoteGattDescriptorFloss::OnReadDescriptor,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
service_->GetDevice()->GetAddress(), descriptor_->instance_id, auth);
}
void BluetoothRemoteGattDescriptorFloss::WriteRemoteDescriptor(
base::span<const uint8_t> new_value,
base::OnceClosure callback,
ErrorCallback error_callback) {
AuthRequired auth = characteristic_->GetAuthForWrite();
FlossDBusManager::Get()->GetGattManagerClient()->WriteDescriptor(
base::BindOnce(&BluetoothRemoteGattDescriptorFloss::OnWriteDescriptor,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(error_callback), base::ToVector(new_value)),
service_->GetDevice()->GetAddress(), descriptor_->instance_id, auth,
new_value);
}
void BluetoothRemoteGattDescriptorFloss::GattDescriptorRead(
std::string address,
GattStatus status,
int32_t handle,
const std::vector<uint8_t>& data) {
if (handle != descriptor_->instance_id ||
address != service_->GetDevice()->GetAddress()) {
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 BluetoothRemoteGattDescriptorFloss::GattDescriptorWrite(
std::string address,
GattStatus status,
int32_t handle) {
if (handle != descriptor_->instance_id ||
address != service_->GetDevice()->GetAddress()) {
return;
}
// Only handle if there is a write callback pending.
auto [callback, error_callback, data] = std::move(pending_write_callbacks_);
if (!callback) {
return;
}
if (status == GattStatus::kSuccess) {
cached_data_ = data;
std::move(callback).Run();
} else {
std::move(error_callback)
.Run(BluetoothGattServiceFloss::GattStatusToServiceError(status));
}
}
void BluetoothRemoteGattDescriptorFloss::GattNotify(
std::string address,
int32_t handle,
const std::vector<uint8_t>& data) {
if (handle != descriptor_->instance_id ||
address != service_->GetDevice()->GetAddress()) {
return;
}
cached_data_ = data;
NotifyValueChanged();
}
void BluetoothRemoteGattDescriptorFloss::OnReadDescriptor(
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(BluetoothGattServiceFloss::GattErrorCode::kFailed,
{});
return;
}
pending_read_callback_ = std::move(callback);
}
void BluetoothRemoteGattDescriptorFloss::OnWriteDescriptor(
base::OnceClosure callback,
ErrorCallback error_callback,
std::vector<uint8_t> data,
DBusResult<Void> result) {
if (!result.has_value()) {
std::move(error_callback)
.Run(BluetoothGattServiceFloss::GattErrorCode::kFailed);
return;
}
pending_write_callbacks_ = std::make_tuple(
std::move(callback), std::move(error_callback), std::move(data));
// Ensure callbacks don't get dropped if no |GattDescriptorWrite| received.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&BluetoothRemoteGattDescriptorFloss::OnWriteTimeout,
weak_ptr_factory_.GetWeakPtr()),
base::Milliseconds(kGattTimeoutMs));
}
void BluetoothRemoteGattDescriptorFloss::OnWriteTimeout() {
if (std::get<0>(pending_write_callbacks_)) {
BLUETOOTH_LOG(ERROR)
<< "Timeout waiting for GattDescriptorWrite for Device "
<< service_->GetDevice()->GetAddress();
GattDescriptorWrite(service_->GetDevice()->GetAddress(), GattStatus::kError,
descriptor_->instance_id);
}
}
void BluetoothRemoteGattDescriptorFloss::NotifyValueChanged() {
DCHECK(service_->GetAdapter());
service_->GetAdapter()->NotifyGattDescriptorValueChanged(this, cached_data_);
}
} // namespace floss