Commit 39c6286b authored by Qiyu Hu's avatar Qiyu Hu Committed by Commit Bot

bluetooth: Implement "PrepareWriteValue" for GATT characteristic

PrepareWriteValue is a procedure to reliably write to GATT
characteristics in a GATT service. A client can PrepareWrite to
various characteristics in a reliable write session and Execute or Abort
those writes later.

For now, BlueZ handles prepare writes by caching them and then sends out
regular write requests to the application in the case of commit, or
silently drops them in the case of abort.

We keep the caching in BlueZ but implement a new function named
PrepareWriteValue() such that applications can tell prepare write
requests from regular write requests. Since BlueZ only sends out the
write requests when the remote device commits, applications not
interested in achieving reliable writes can safely regard all prepare
write requests as regular ones.

A relevant patch is crrev.com/c/1094214

Bug: b:78650442
CQ-DEPEND: CL:1094214
Test: Pass Android CtsVerifier test on GATT server reliable write
Change-Id: If2464cf3a17e7c91dc11dc8f4c37734a2987543e
Reviewed-on: https://chromium-review.googlesource.com/1094316
Commit-Queue: Qiyu Hu <qiyuh@google.com>
Reviewed-by: default avatarGreg Kerr <kerrnel@chromium.org>
Reviewed-by: default avatarRahul Chaturvedi <rkc@chromium.org>
Reviewed-by: default avatarLuis Hector Chavez <lhchavez@chromium.org>
Reviewed-by: default avatarMiao-chen Chou <mcchou@chromium.org>
Reviewed-by: default avatarToni Barzic <tbarzic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#573539}
parent 4eb127ce
......@@ -843,6 +843,31 @@ void ArcBluetoothBridge::OnGattAttributeReadRequest(
base::BindOnce(&OnGattServerRead, success_callback, error_callback));
}
void ArcBluetoothBridge::OnGattServerPrepareWrite(
mojom::BluetoothAddressPtr addr,
bool has_subsequent_write,
const base::Closure& success_callback,
const ErrorCallback& error_callback,
mojom::BluetoothGattStatus status) {
bool success = (status == mojom::BluetoothGattStatus::GATT_SUCCESS);
const base::Closure& callback = (success ? success_callback : error_callback);
if (success && has_subsequent_write) {
callback.Run();
return;
}
auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc_bridge_service_->bluetooth(), RequestGattExecuteWrite);
if (bluetooth_instance == nullptr) {
error_callback.Run();
return;
}
bluetooth_instance->RequestGattExecuteWrite(
std::move(addr), success,
base::BindOnce(&OnGattServerWrite, callback, error_callback));
}
template <class LocalGattAttribute>
void ArcBluetoothBridge::OnGattAttributeWriteRequest(
const BluetoothDevice* device,
......@@ -850,6 +875,8 @@ void ArcBluetoothBridge::OnGattAttributeWriteRequest(
const std::vector<uint8_t>& value,
int offset,
mojom::BluetoothGattDBAttributeType attribute_type,
bool is_prepare,
bool has_subsequent_write,
const base::Closure& success_callback,
const ErrorCallback& error_callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
......@@ -860,12 +887,19 @@ void ArcBluetoothBridge::OnGattAttributeWriteRequest(
return;
}
GattStatusCallback callback =
is_prepare ? base::BindOnce(
&ArcBluetoothBridge::OnGattServerPrepareWrite,
weak_factory_.GetWeakPtr(),
mojom::BluetoothAddress::From(device->GetAddress()),
has_subsequent_write, success_callback, error_callback)
: base::BindOnce(&OnGattServerWrite, success_callback,
error_callback);
DCHECK(gatt_handle_.find(attribute->GetIdentifier()) != gatt_handle_.end());
bluetooth_instance->RequestGattWrite(
mojom::BluetoothAddress::From(device->GetAddress()),
gatt_handle_[attribute->GetIdentifier()], offset, value, attribute_type,
base::BindOnce(&OnGattServerWrite, success_callback, error_callback));
is_prepare, std::move(callback));
}
void ArcBluetoothBridge::OnCharacteristicReadRequest(
......@@ -889,10 +923,25 @@ void ArcBluetoothBridge::OnCharacteristicWriteRequest(
const ErrorCallback& error_callback) {
OnGattAttributeWriteRequest(
device, characteristic, value, offset,
mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC, callback,
mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
/* is_prepare = */ false, /* has_subsequent_write, = */ false, callback,
error_callback);
}
void ArcBluetoothBridge::OnCharacteristicPrepareWriteRequest(
const BluetoothDevice* device,
const BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_write,
const base::Closure& callback,
const ErrorCallback& error_callback) {
OnGattAttributeWriteRequest(
device, characteristic, value, offset,
mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
/* is_prepare = */ true, has_subsequent_write, callback, error_callback);
}
void ArcBluetoothBridge::OnDescriptorReadRequest(
const BluetoothDevice* device,
const BluetoothLocalGattDescriptor* descriptor,
......@@ -914,7 +963,8 @@ void ArcBluetoothBridge::OnDescriptorWriteRequest(
const ErrorCallback& error_callback) {
OnGattAttributeWriteRequest(
device, descriptor, value, offset,
mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR, callback,
mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR,
/* is_prepare = */ false, /* has_subsequent_write = */ false, callback,
error_callback);
}
......
......@@ -162,6 +162,15 @@ class ArcBluetoothBridge
const base::Closure& callback,
const ErrorCallback& error_callback) override;
void OnCharacteristicPrepareWriteRequest(
const device::BluetoothDevice* device,
const device::BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_write,
const base::Closure& callback,
const ErrorCallback& error_callback) override;
void OnDescriptorReadRequest(
const device::BluetoothDevice* device,
const device::BluetoothLocalGattDescriptor* descriptor,
......@@ -448,6 +457,9 @@ class ArcBluetoothBridge
const ErrorCallback& error_callback);
// Common code for OnCharacteristicWriteRequest and OnDescriptorWriteRequest
// |is_prepare| is only set when a local characteristic receives a prepare
// write request, and |has_subsequent_write| indicates whether there are
// subsequent prepare write requests following the current one.
template <class LocalGattAttribute>
void OnGattAttributeWriteRequest(
const device::BluetoothDevice* device,
......@@ -455,6 +467,8 @@ class ArcBluetoothBridge
const std::vector<uint8_t>& value,
int offset,
mojom::BluetoothGattDBAttributeType attribute_type,
bool is_prepare,
bool has_subsequent_write,
const base::Closure& success_callback,
const ErrorCallback& error_callback);
......@@ -519,6 +533,19 @@ class ArcBluetoothBridge
void SendDevice(const device::BluetoothDevice* device,
bool include_cached_device) const;
void OnGattServerPrepareWrite(mojom::BluetoothAddressPtr addr,
bool has_subsequent_write,
const base::Closure& success_callback,
const ErrorCallback& error_callback,
mojom::BluetoothGattStatus status);
void SendDevice(const device::BluetoothDevice* device) const;
// Shows a pairing dialog to handle incoming pairing requests.
// Returns the pairing delegate of the dialog UI.
device::BluetoothDevice::PairingDelegate* ShowPairingDialog(
device::BluetoothDevice* device);
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
scoped_refptr<bluez::BluetoothAdapterBlueZ> bluetooth_adapter_;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Next MinVersion: 12
// Next MinVersion: 13
module arc.mojom;
......@@ -409,7 +409,7 @@ interface BluetoothHost {
=> (BluetoothGattStatus status);
};
// Next Method ID: 20
// Next Method ID: 21
interface BluetoothInstance {
// DEPRECATED: Please use Init@18 instead.
InitDeprecated@0(BluetoothHost host_ptr);
......@@ -467,7 +467,12 @@ interface BluetoothInstance {
int32 attribute_handle,
int32 offset,
array<uint8> value,
[MinVersion=9] BluetoothGattDBAttributeType attribute_type)
[MinVersion=9] BluetoothGattDBAttributeType attribute_type,
[MinVersion=12] bool is_prepare)
=> (BluetoothGattStatus status);
[MinVersion=12] RequestGattExecuteWrite@20(
BluetoothAddress address,
bool execute)
=> (BluetoothGattStatus status);
[MinVersion=10] OnMTUReceived@19(BluetoothAddress remote_addr, uint16 mtu);
......
......@@ -122,8 +122,14 @@ void FakeBluetoothInstance::RequestGattWrite(
int32_t offset,
const std::vector<uint8_t>& value,
mojom::BluetoothGattDBAttributeType attribute_type,
bool is_prepare,
RequestGattWriteCallback callback) {}
void FakeBluetoothInstance::RequestGattExecuteWrite(
mojom::BluetoothAddressPtr address,
bool execute,
RequestGattExecuteWriteCallback callback) {}
void FakeBluetoothInstance::OnGetSdpRecords(
mojom::BluetoothStatus status,
mojom::BluetoothAddressPtr remote_addr,
......
......@@ -124,8 +124,14 @@ class FakeBluetoothInstance : public mojom::BluetoothInstance {
int32_t offset,
const std::vector<uint8_t>& value,
mojom::BluetoothGattDBAttributeType attribute_type,
bool is_prepare,
RequestGattWriteCallback callback) override;
void RequestGattExecuteWrite(
mojom::BluetoothAddressPtr address,
bool execute,
RequestGattExecuteWriteCallback callback) override;
void OnGetSdpRecords(
mojom::BluetoothStatus status,
mojom::BluetoothAddressPtr remote_addr,
......
......@@ -87,6 +87,36 @@ TEST_F(BluetoothLocalGattCharacteristicTest,
EXPECT_EQ(device_->GetIdentifier(), delegate_->last_seen_device_);
}
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
#define MAYBE_PrepareWriteLocalCharacteristicValue \
PrepareWriteLocalCharacteristicValue
#else
#define MAYBE_PrepareWriteLocalCharacteristicValue \
DISABLED_PrepareWriteLocalCharacteristicValue
#endif
TEST_F(BluetoothLocalGattCharacteristicTest,
MAYBE_PrepareWriteLocalCharacteristicValue) {
const uint64_t kValueToWrite = 0x7331ul;
// Clear existing value.
SimulateLocalGattCharacteristicValueWriteRequest(
device_, write_characteristic_.get(), GetValue(0),
GetCallback(Call::EXPECTED), GetCallback(Call::NOT_EXPECTED));
// Reliable write session is going on.
SimulateLocalGattCharacteristicValuePrepareWriteRequest(
device_, write_characteristic_.get(), GetValue(402289342ul), 0, true,
GetCallback(Call::EXPECTED), GetCallback(Call::NOT_EXPECTED));
EXPECT_EQ(0ul, delegate_->last_written_value_);
EXPECT_EQ(device_->GetIdentifier(), delegate_->last_seen_device_);
// Reliable write session ends.
SimulateLocalGattCharacteristicValuePrepareWriteRequest(
device_, write_characteristic_.get(), GetValue(kValueToWrite), 0, false,
GetCallback(Call::EXPECTED), GetCallback(Call::NOT_EXPECTED));
EXPECT_EQ(kValueToWrite, delegate_->last_written_value_);
EXPECT_EQ(device_->GetIdentifier(), delegate_->last_seen_device_);
}
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
#define MAYBE_ReadLocalCharacteristicValueFail ReadLocalCharacteristicValueFail
#else
......
......@@ -87,6 +87,31 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothLocalGattService
const base::Closure& callback,
const ErrorCallback& error_callback) = 0;
// Called when a remote device |device| requests to prepare write the value
// of the characteristic |characteristic| starting at offset |offset|.
// This method is only called if the characteristic was specified as
// reliable writable and any authentication and authorization challenges
// were satisfied by the remote device.
//
// |has_subsequent_request| is true when the reliable write session is still
// ongoing, false otherwise. When |has_subsequent_request| is false,
// delegates MUST tear down the current reliable write session with |device|
// and commit all the prepare writes in that session in order.
//
// To respond to the request with success the delegate must invoke
// |callback|. To respond to the request with failure delegates must invoke
// |error_callback|. If neither callback parameter is invoked, the request
// will time out and result in an error. Therefore, delegates MUST invoke
// either |callback| or |error_callback|.
virtual void OnCharacteristicPrepareWriteRequest(
const BluetoothDevice* device,
const BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const ErrorCallback& error_callback) = 0;
// Called when a remote device |device| requests to read the value of the
// descriptor |descriptor| starting at offset |offset|.
// This method is only called if the descriptor was specified as
......
......@@ -73,6 +73,19 @@ class BluetoothGattAttributeValueDelegate {
// descriptors.
virtual void StopNotifications(const dbus::ObjectPath& device_path) = 0;
// This method will be called, when a remote device requests to prepare
// write the value of the exported GATT characteristic. Invoke |callback| to
// report that the request was successful. Invoke |error_callback| to report
// a failure. This will never be called for descriptors.
virtual void PrepareSetValue(
const dbus::ObjectPath& device_path,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const device::BluetoothLocalGattService::Delegate::ErrorCallback&
error_callback) {}
protected:
// Gets the Bluetooth device object on the current service's adapter with
// the given object path.
......
......@@ -49,4 +49,17 @@ void BluetoothGattCharacteristicDelegateWrapper::StopNotifications(
characteristic_);
}
void BluetoothGattCharacteristicDelegateWrapper::PrepareSetValue(
const dbus::ObjectPath& device_path,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const device::BluetoothLocalGattService::Delegate::ErrorCallback&
error_callback) {
service()->GetDelegate()->OnCharacteristicPrepareWriteRequest(
GetDeviceWithPath(device_path), characteristic_, value, offset,
has_subsequent_request, callback, error_callback);
}
} // namespace bluez
......@@ -41,6 +41,14 @@ class BluetoothGattCharacteristicDelegateWrapper
const base::Closure& callback,
const device::BluetoothLocalGattService::Delegate::ErrorCallback&
error_callback) override;
void PrepareSetValue(
const dbus::ObjectPath& device_path,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const device::BluetoothLocalGattService::Delegate::ErrorCallback&
error_callback) override;
void StartNotifications(const dbus::ObjectPath& device_path,
device::BluetoothGattCharacteristic::NotificationType
notification_type) override;
......
......@@ -11,6 +11,7 @@
#include "base/strings/string_util.h"
#include "device/bluetooth/bluetooth_gatt_characteristic.h"
#include "device/bluetooth/dbus/bluetooth_gatt_attribute_helpers.h"
#include "device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace bluez {
......@@ -89,6 +90,14 @@ BluetoothGattCharacteristicServiceProviderImpl::
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
bluetooth_gatt_characteristic::kPrepareWriteValue,
base::Bind(
&BluetoothGattCharacteristicServiceProviderImpl::PrepareWriteValue,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnExported,
weak_ptr_factory_.GetWeakPtr()));
exported_object_->ExportMethod(
bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
bluetooth_gatt_characteristic::kStartNotify,
......@@ -123,9 +132,9 @@ void BluetoothGattCharacteristicServiceProviderImpl::SendValueChanged(
dbus::Signal signal(dbus::kDBusPropertiesInterface,
dbus::kDBusPropertiesChangedSignal);
dbus::MessageWriter writer(&signal);
dbus::MessageWriter array_writer(NULL);
dbus::MessageWriter dict_entry_writer(NULL);
dbus::MessageWriter variant_writer(NULL);
dbus::MessageWriter array_writer(nullptr);
dbus::MessageWriter dict_entry_writer(nullptr);
dbus::MessageWriter variant_writer(nullptr);
// interface_name
writer.AppendString(
......@@ -187,7 +196,7 @@ void BluetoothGattCharacteristicServiceProviderImpl::Get(
std::unique_ptr<dbus::Response> response =
dbus::Response::FromMethodCall(method_call);
dbus::MessageWriter writer(response.get());
dbus::MessageWriter variant_writer(NULL);
dbus::MessageWriter variant_writer(nullptr);
if (property_name == bluetooth_gatt_characteristic::kUUIDProperty) {
writer.OpenVariant("s", &variant_writer);
......@@ -299,7 +308,7 @@ void BluetoothGattCharacteristicServiceProviderImpl::WriteValue(
DCHECK(OnOriginThread());
dbus::MessageReader reader(method_call);
const uint8_t* bytes = NULL;
const uint8_t* bytes = nullptr;
size_t length = 0;
std::vector<uint8_t> value;
......@@ -334,6 +343,57 @@ void BluetoothGattCharacteristicServiceProviderImpl::WriteValue(
weak_ptr_factory_.GetWeakPtr(), method_call, response_sender));
}
void BluetoothGattCharacteristicServiceProviderImpl::PrepareWriteValue(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
VLOG(3) << "BluetoothGattCharacteristicServiceProvider::PrepareWriteValue: "
<< object_path_.value();
DCHECK(OnOriginThread());
dbus::MessageReader reader(method_call);
const uint8_t* bytes = nullptr;
size_t length = 0;
std::vector<uint8_t> value;
if (!reader.PopArrayOfBytes(&bytes, &length)) {
LOG(WARNING) << "Error reading value parameter. PrepareWriteValue called "
<< "with incorrect parameters: " << method_call->ToString();
}
if (bytes)
value.assign(bytes, bytes + length);
std::map<std::string, dbus::MessageReader> options;
dbus::ObjectPath device_path;
uint16_t offset = 0;
bool has_subsequent_write = false;
ReadOptions(&reader, &options);
auto it = options.find(bluetooth_gatt_characteristic::kOptionDevice);
if (it != options.end())
it->second.PopObjectPath(&device_path);
it = options.find(bluetooth_gatt_characteristic::kOptionOffset);
if (it != options.end())
it->second.PopUint16(&offset);
// TODO(b/78650442): kOptionHasSubsequentWrite
it = options.find("has-subsequent-write");
if (it != options.end())
it->second.PopBool(&has_subsequent_write);
if (device_path.value().empty()) {
LOG(WARNING) << "PrepareWriteValue called with incorrect parameters: "
<< method_call->ToString();
// Continue on with an empty device path. This will return a null device to
// the delegate, which should know how to handle it.
}
DCHECK(delegate_);
delegate_->PrepareSetValue(
device_path, value, offset, has_subsequent_write,
base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnWriteValue,
weak_ptr_factory_.GetWeakPtr(), method_call, response_sender),
base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
weak_ptr_factory_.GetWeakPtr(), method_call, response_sender));
}
void BluetoothGattCharacteristicServiceProviderImpl::StartNotify(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
......@@ -418,9 +478,9 @@ void BluetoothGattCharacteristicServiceProviderImpl::OnWriteValue(
void BluetoothGattCharacteristicServiceProviderImpl::WriteProperties(
dbus::MessageWriter* writer) {
dbus::MessageWriter array_writer(NULL);
dbus::MessageWriter dict_entry_writer(NULL);
dbus::MessageWriter variant_writer(NULL);
dbus::MessageWriter array_writer(nullptr);
dbus::MessageWriter dict_entry_writer(nullptr);
dbus::MessageWriter variant_writer(nullptr);
writer->OpenArray("{sv}", &array_writer);
......
......@@ -70,6 +70,11 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothGattCharacteristicServiceProviderImpl
void WriteValue(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
// Called by BlueZ when a remote central is requesting to prepare the reliable
// write value of this characteristic.
void PrepareWriteValue(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
// Called by BlueZ when a remote central is requesting to start a
// notification session for this characteristic.
void StartNotify(dbus::MethodCall* method_call,
......
......@@ -170,6 +170,38 @@ void FakeBluetoothGattCharacteristicServiceProvider::SetValue(
delegate_->SetValue(device_path, value, callback, error_callback);
}
void FakeBluetoothGattCharacteristicServiceProvider::PrepareSetValue(
const dbus::ObjectPath& device_path,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_write,
const base::Closure& callback,
const device::BluetoothLocalGattService::Delegate::ErrorCallback&
error_callback) {
VLOG(1) << "GATT characteristic value Prepare Set request: "
<< object_path_.value() << " UUID: " << uuid_;
// Check if this characteristic is registered.
FakeBluetoothGattManagerClient* fake_bluetooth_gatt_manager_client =
static_cast<FakeBluetoothGattManagerClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothGattManagerClient());
if (!fake_bluetooth_gatt_manager_client->IsServiceRegistered(service_path_)) {
VLOG(1) << "GATT characteristic not registered.";
error_callback.Run();
return;
}
if (!CanWrite(flags_)) {
VLOG(1) << "GATT characteristic not writeable.";
error_callback.Run();
return;
}
// Pass on to the delegate.
DCHECK(delegate_);
delegate_->PrepareSetValue(device_path, value, offset, has_subsequent_write,
callback, error_callback);
}
bool FakeBluetoothGattCharacteristicServiceProvider::NotificationsChange(
bool start) {
VLOG(1) << "GATT characteristic value notification request: "
......
......@@ -51,6 +51,14 @@ class DEVICE_BLUETOOTH_EXPORT FakeBluetoothGattCharacteristicServiceProvider
const base::Closure& callback,
const device::BluetoothLocalGattService::Delegate::ErrorCallback&
error_callback);
void PrepareSetValue(
const dbus::ObjectPath& device_path,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_write,
const base::Closure& callback,
const device::BluetoothLocalGattService::Delegate::ErrorCallback&
error_callback);
// Method to simulate starting and stopping notifications.
bool NotificationsChange(bool start);
......
......@@ -378,6 +378,17 @@ class BluetoothTestBase : public testing::Test {
const base::Closure& success_callback,
const base::Closure& error_callback) {}
// Simulates prepare write a value to a locally hosted GATT characteristic by
// a remote central device.
virtual void SimulateLocalGattCharacteristicValuePrepareWriteRequest(
BluetoothDevice* from_device,
BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value_to_write,
int offset,
bool has_subsequent_write,
const base::Closure& success_callback,
const base::Closure& error_callback) {}
// Simulates reading a value from a locally hosted GATT descriptor by a
// remote central device. Returns the value that was read from the local
// GATT descriptor in the value callback.
......
......@@ -224,6 +224,41 @@ void BluetoothTestBlueZ::SimulateLocalGattCharacteristicValueWriteRequest(
run_loop.Run();
}
void BluetoothTestBlueZ::
SimulateLocalGattCharacteristicValuePrepareWriteRequest(
BluetoothDevice* from_device,
BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value_to_write,
int offset,
bool has_subsequent_write,
const base::Closure& success_callback,
const base::Closure& error_callback) {
bluez::BluetoothLocalGattCharacteristicBlueZ* characteristic_bluez =
static_cast<bluez::BluetoothLocalGattCharacteristicBlueZ*>(
characteristic);
bluez::FakeBluetoothGattManagerClient* fake_bluetooth_gatt_manager_client =
static_cast<bluez::FakeBluetoothGattManagerClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothGattManagerClient());
bluez::FakeBluetoothGattCharacteristicServiceProvider*
characteristic_provider =
fake_bluetooth_gatt_manager_client->GetCharacteristicServiceProvider(
characteristic_bluez->object_path());
bluez::BluetoothLocalGattServiceBlueZ* service_bluez =
static_cast<bluez::BluetoothLocalGattServiceBlueZ*>(
characteristic->GetService());
static_cast<TestBluetoothLocalGattServiceDelegate*>(
service_bluez->GetDelegate())
->set_expected_characteristic(characteristic);
base::RunLoop run_loop;
characteristic_provider->PrepareSetValue(
GetDevicePath(from_device), value_to_write, offset, has_subsequent_write,
base::Bind(&ClosureCallback, run_loop.QuitClosure(), success_callback),
base::Bind(&ClosureCallback, run_loop.QuitClosure(), error_callback));
run_loop.Run();
}
void BluetoothTestBlueZ::SimulateLocalGattDescriptorValueReadRequest(
BluetoothDevice* from_device,
BluetoothLocalGattDescriptor* descriptor,
......
......@@ -47,6 +47,14 @@ class BluetoothTestBlueZ : public BluetoothTestBase {
const std::vector<uint8_t>& value_to_write,
const base::Closure& success_callback,
const base::Closure& error_callback) override;
void SimulateLocalGattCharacteristicValuePrepareWriteRequest(
BluetoothDevice* from_device,
BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value_to_write,
int offset,
bool has_subsequent_write,
const base::Closure& success_callback,
const base::Closure& error_callback) override;
void SimulateLocalGattDescriptorValueReadRequest(
BluetoothDevice* from_device,
BluetoothLocalGattDescriptor* descriptor,
......
......@@ -53,6 +53,29 @@ void TestBluetoothLocalGattServiceDelegate::OnCharacteristicWriteRequest(
callback.Run();
}
void TestBluetoothLocalGattServiceDelegate::OnCharacteristicPrepareWriteRequest(
const BluetoothDevice* device,
const BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const ErrorCallback& error_callback) {
EXPECT_EQ(expected_characteristic_->GetIdentifier(),
characteristic->GetIdentifier());
if (should_fail_) {
error_callback.Run();
return;
}
// For testing purpose, we don't maintain a queue for all the pending prepare
// write requests. Instead, we just write the last value, that is, we assume
// |offset| is always 0.
if (!has_subsequent_request)
last_written_value_ = BluetoothGattServerTest::GetInteger(value);
last_seen_device_ = device->GetIdentifier();
callback.Run();
}
void TestBluetoothLocalGattServiceDelegate::OnDescriptorReadRequest(
const BluetoothDevice* device,
const BluetoothLocalGattDescriptor* descriptor,
......
......@@ -36,6 +36,14 @@ class TestBluetoothLocalGattServiceDelegate
int offset,
const base::Closure& callback,
const ErrorCallback& error_callback) override;
void OnCharacteristicPrepareWriteRequest(
const BluetoothDevice* device,
const BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const ErrorCallback& error_callback) override;
void OnDescriptorReadRequest(const BluetoothDevice* device,
const BluetoothLocalGattDescriptor* descriptor,
int offset,
......
......@@ -1142,6 +1142,19 @@ void BluetoothLowEnergyEventRouter::OnCharacteristicWriteRequest(
request, characteristic->GetIdentifier()));
}
void BluetoothLowEnergyEventRouter::OnCharacteristicPrepareWriteRequest(
const device::BluetoothDevice* device,
const device::BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const Delegate::ErrorCallback& error_callback) {
// TODO(crbug/856869): Support reliable write.
OnCharacteristicWriteRequest(device, characteristic, value, offset, callback,
error_callback);
}
void BluetoothLowEnergyEventRouter::OnDescriptorReadRequest(
const device::BluetoothDevice* device,
const device::BluetoothLocalGattDescriptor* descriptor,
......
......@@ -319,6 +319,14 @@ class BluetoothLowEnergyEventRouter
int offset,
const base::Closure& callback,
const Delegate::ErrorCallback& error_callback) override;
void OnCharacteristicPrepareWriteRequest(
const device::BluetoothDevice* device,
const device::BluetoothLocalGattCharacteristic* characteristic,
const std::vector<uint8_t>& value,
int offset,
bool has_subsequent_request,
const base::Closure& callback,
const Delegate::ErrorCallback& error_callback) override;
void OnDescriptorReadRequest(
const device::BluetoothDevice* device,
const device::BluetoothLocalGattDescriptor* descriptor,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment