// TODO(armansito): Implement.
}
+void HeartRateServer::OnCharacteristicWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) {
+ // TODO(armansito): Implement.
+}
+
+void HeartRateServer::OnDescriptorWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) {
+ // TODO(armansito): Implement.
+}
+
+void HeartRateServer::OnExecuteWriteRequest(
+ const std::string& device_address,
+ int request_id, bool is_execute) {
+ // TODO(armansito): Implement.
+}
+
} // namespace heart_rate
const std::string& device_address,
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& descriptor_id) override;
+ void OnCharacteristicWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) override;
+ void OnDescriptorWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) override;
+ void OnExecuteWriteRequest(
+ const std::string& device_address,
+ int request_id, bool is_execute) override;
std::mutex mutex_;
btgatt_response_t response;
memset(&response, 0, sizeof(response));
- response.handle = connection->request_id_to_handle[request_id];
- memcpy(response.attr_value.value, value.data(), value.size());
- response.attr_value.handle = response.handle;
- response.attr_value.offset = offset;
- response.attr_value.len = value.size();
+ // We keep -1 as the handle for "Execute Write Request". In that case,
+ // there is no need to populate the response data. Just send zeros back.
+ int handle = connection->request_id_to_handle[request_id];
+ response.handle = handle;
+ response.attr_value.handle = handle;
+ if (handle != -1) {
+ memcpy(response.attr_value.value, value.data(), value.size());
+ response.attr_value.offset = offset;
+ response.attr_value.len = value.size();
+ }
bt_status_t result = hal::BluetoothGattInterface::Get()->
GetServerHALInterface()->send_response(
}
}
+void GattServer::RequestWriteCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attr_handle, int offset, int length,
+ bool need_rsp, bool is_prep, uint8_t* value) {
+ lock_guard<mutex> lock(mutex_);
+
+ if (length < 0) {
+ LOG(WARNING) << "Negative length value received";
+ return;
+ }
+
+ // Check to see if we know about this connection. Otherwise ignore the
+ // request.
+ auto conn = GetConnection(conn_id, bda, trans_id);
+ if (!conn)
+ return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " BD_ADDR: " << device_address
+ << " attr_handle: " << attr_handle << " offset: " << offset
+ << " length: " << length << " need_rsp: " << need_rsp
+ << " is_prep: " << is_prep;
+
+ // Make sure that the handle is valid.
+ auto iter = handle_to_id_map_.find(attr_handle);
+ if (iter == handle_to_id_map_.end()) {
+ LOG(ERROR) << "Request received for unknown handle: " << attr_handle;
+ return;
+ }
+
+ // Store the request ID only if this is not a write-without-response. If
+ // another request occurs after this with the same request ID, then we'll
+ // simply process it normally, though that shouldn't ever happen.
+ if (need_rsp)
+ conn->request_id_to_handle[trans_id] = attr_handle;
+
+ // If there is no delegate then there is nobody to handle request. The request
+ // will eventually timeout and we should get a connection update that
+ // terminates the connection.
+ if (!delegate_) {
+ // TODO(armansito): Require a delegate at server registration so that this
+ // is never possible.
+ LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+ << "will time out.";
+ return;
+ }
+
+ std::vector<uint8_t> value_vec(value, value + length);
+
+ if (iter->second.IsCharacteristic()) {
+ delegate_->OnCharacteristicWriteRequest(
+ this, device_address, trans_id, offset, is_prep, need_rsp,
+ value_vec, iter->second);
+ } else if (iter->second.IsDescriptor()) {
+ delegate_->OnDescriptorWriteRequest(
+ this, device_address, trans_id, offset, is_prep, need_rsp,
+ value_vec, iter->second);
+ } else {
+ // Our API only delegates to applications those read requests for
+ // characteristic value and descriptor attributes. Everything else should be
+ // handled by the stack.
+ LOG(WARNING) << "Write request received for unsupported attribute";
+ }
+}
+
+void GattServer::RequestExecWriteCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int exec_write) {
+ lock_guard<mutex> lock(mutex_);
+
+ // Check to see if we know about this connection. Otherwise ignore the
+ // request.
+ auto conn = GetConnection(conn_id, bda, trans_id);
+ if (!conn)
+ return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " BD_ADDR: " << device_address << " exec_write: " << exec_write;
+
+ // Just store a dummy invalid handle as this request doesn't apply to a
+ // specific handle.
+ conn->request_id_to_handle[trans_id] = -1;
+
+ // If there is no delegate then there is nobody to handle request. The request
+ // will eventually timeout and we should get a connection update that
+ // terminates the connection.
+ if (!delegate_) {
+ // TODO(armansito): Require a delegate at server registration so that this
+ // is never possible.
+ LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+ << "will time out.";
+ return;
+ }
+
+ delegate_->OnExecuteWriteRequest(this, device_address, trans_id, exec_write);
+}
+
void GattServer::NotifyEndCallbackAndClearData(
BLEStatus status, const GattIdentifier& id) {
VLOG(1) << __func__ << " status: " << status;
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& descriptor_id) = 0;
+ // Called when there is an incoming write request for the characteristic
+ // with ID |characteristic_id| from a remote device with address
+ // |device_address|. |request_id| can be used to respond to this request by
+ // calling SendResponse, if the |need_response| parameter is true. Otherwise
+ // this is a "Write Without Reponse" procedure and SendResponse will fail.
+ // If |is_prepare_write| is true, then the write should not be committed
+ // immediately as this is a "Prepared Write Request". Instead, the Delegate
+ // should hold on to the value and either discard it or complete the write
+ // when it receives the OnExecuteWriteRequest event.
+ virtual void OnCharacteristicWriteRequest(
+ GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) = 0;
+
+ // Called when there is an incoming write request for the descriptor
+ // with ID |descriptor_id| from a remote device with address
+ // |device_address|. |request_id| can be used to respond to this request by
+ // calling SendResponse, if the |need_response| parameter is true. Otherwise
+ // this is a "Write Without Response" procedure and SendResponse will fail.
+ // If |is_prepare_write| is true, then the write should not be committed
+ // immediately as this is a "Prepared Write Request". Instead, the Delegate
+ // should hold on to the value and either discard it or complete the write
+ // when it receives the OnExecuteWriteRequest event.
+ virtual void OnDescriptorWriteRequest(
+ GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) = 0;
+
+ // Called when there is an incoming "Execute Write Request". If |is_execute|
+ // is true, then the Delegate should commit all previously prepared writes.
+ // Otherwise, all prepared writes should be aborted. The Delegate should
+ // call "SendResponse" to complete the procedure.
+ virtual void OnExecuteWriteRequest(
+ GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, bool is_execute) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
const bt_bdaddr_t& bda,
int attribute_handle, int offset,
bool is_long) override;
+ void RequestWriteCallback(
+ hal::BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attr_handle, int offset, int length,
+ bool need_rsp, bool is_prep, uint8_t* value) override;
+ void RequestExecWriteCallback(
+ hal::BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int exec_write) override;
// Helper function that notifies and clears the pending callback.
void NotifyEndCallbackAndClearData(BLEStatus status,
g_interface, conn_id, trans_id, *bda, attr_handle, offset, is_long));
}
+void RequestWriteCallback(int conn_id, int trans_id,
+ bt_bdaddr_t* bda,
+ int attr_handle, int offset, int length,
+ bool need_rsp, bool is_prep, uint8_t* value) {
+ lock_guard<mutex> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " attr_handle: " << attr_handle << " offset: " << offset
+ << " length: " << length << " need_rsp: " << need_rsp
+ << " is_prep: " << is_prep;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(RequestWriteCallback(
+ g_interface, conn_id, trans_id, *bda, attr_handle, offset, length,
+ need_rsp, is_prep, value));
+}
+
+void RequestExecWriteCallback(int conn_id, int trans_id,
+ bt_bdaddr_t* bda, int exec_write) {
+ lock_guard<mutex> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " exec_write: " << exec_write;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(RequestExecWriteCallback(
+ g_interface, conn_id, trans_id, *bda, exec_write));
+}
+
// The HAL Bluetooth GATT client interface callbacks. These signal a mixture of
// GATT client-role and GAP events.
const btgatt_client_callbacks_t gatt_client_callbacks = {
ServiceStoppedCallback,
nullptr, // service_deleted_cb,
RequestReadCallback,
- nullptr, // request_write_cb,
- nullptr, // request_exec_write_cb,
+ RequestWriteCallback,
+ RequestExecWriteCallback,
nullptr, // response_confirmation_cb,
nullptr, // indication_sent_cb
nullptr, // congestion_cb
// Do nothing.
}
+void BluetoothGattInterface::ServerObserver::RequestWriteCallback(
+ BluetoothGattInterface* /* gatt_iface */,
+ int /* conn_id */,
+ int /* trans_id */,
+ const bt_bdaddr_t& /* bda */,
+ int /* attr_handle */,
+ int /* offset */,
+ int /* length */,
+ bool /* need_rsp */,
+ bool /* is_prep */,
+ uint8_t* /* value */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestExecWriteCallback(
+ BluetoothGattInterface* gatt_iface,
+ int /* conn_id */,
+ int /* trans_id */,
+ const bt_bdaddr_t& /* bda */,
+ int /* exec_write */) {
+ // Do nothing.
+}
+
// static
bool BluetoothGattInterface::Initialize() {
lock_guard<mutex> lock(g_instance_lock);
int attr_handle, int offset,
bool is_long);
+ virtual void RequestWriteCallback(
+ BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attr_handle, int offset, int length,
+ bool need_rsp, bool is_prep, uint8_t* value);
+
+ virtual void RequestExecWriteCallback(
+ BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int exec_write);
+
// TODO(armansito): Complete the list of callbacks.
};
this, conn_id, trans_id, bda, attr_handle, offset, is_long));
}
+void FakeBluetoothGattInterface::NotifyRequestWriteCallback(
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle,
+ int offset, int length,
+ bool need_rsp, bool is_prep, uint8_t* value) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ RequestWriteCallback(
+ this, conn_id, trans_id, bda, attr_handle, offset, length, need_rsp,
+ is_prep, value));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestExecWriteCallback(
+ int conn_id, int trans_id, const bt_bdaddr_t& bda, int exec_write) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ RequestExecWriteCallback(this, conn_id, trans_id, bda, exec_write));
+}
+
void FakeBluetoothGattInterface::AddClientObserver(ClientObserver* observer) {
CHECK(observer);
client_observers_.AddObserver(observer);
void NotifyRequestReadCallback(int conn_id, int trans_id,
const bt_bdaddr_t& bda, int attr_handle,
int offset, bool is_long);
+ void NotifyRequestWriteCallback(int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle,
+ int offset, int length,
+ bool need_rsp, bool is_prep, uint8_t* value);
+ void NotifyRequestExecWriteCallback(int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int exec_write);
// BluetoothGattInterface overrides:
void AddClientObserver(ClientObserver* observer) override;
*desc_id);
return android::NO_ERROR;
}
+ case ON_CHARACTERISTIC_WRITE_REQUEST_TRANSACTION: {
+ std::string device_address = data.readCString();
+ int request_id = data.readInt32();
+ int offset = data.readInt32();
+ bool is_prep = data.readInt32();
+ bool need_rsp = data.readInt32();
+
+ std::vector<uint8_t> value;
+ int value_len = data.readInt32();
+ if (value_len != -1) {
+ uint8_t bytes[value_len];
+ data.read(bytes, value_len);
+ value.insert(value.begin(), bytes, bytes + value_len);
+ }
+
+ auto char_id = CreateGattIdentifierFromParcel(data);
+ CHECK(char_id);
+
+ OnCharacteristicWriteRequest(
+ device_address, request_id, offset, is_prep, need_rsp, value, *char_id);
+ return android::NO_ERROR;
+ }
+ case ON_DESCRIPTOR_WRITE_REQUEST_TRANSACTION: {
+ std::string device_address = data.readCString();
+ int request_id = data.readInt32();
+ int offset = data.readInt32();
+ bool is_prep = data.readInt32();
+ bool need_rsp = data.readInt32();
+
+ std::vector<uint8_t> value;
+ int value_len = data.readInt32();
+ if (value_len != -1) {
+ uint8_t bytes[value_len];
+ data.read(bytes, value_len);
+ value.insert(value.begin(), bytes, bytes + value_len);
+ }
+
+ auto desc_id = CreateGattIdentifierFromParcel(data);
+ CHECK(desc_id);
+
+ OnDescriptorWriteRequest(
+ device_address, request_id, offset, is_prep, need_rsp, value, *desc_id);
+ return android::NO_ERROR;
+ }
+ case ON_EXECUTE_WRITE_REQUEST_TRANSACTION: {
+ std::string device_address = data.readCString();
+ int request_id = data.readInt32();
+ bool is_exec = data.readInt32();
+
+ OnExecuteWriteRequest(device_address, request_id, is_exec);
+ return android::NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
IBinder::FLAG_ONEWAY);
}
+void BpBluetoothGattServerCallback::OnCharacteristicWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(
+ IBluetoothGattServerCallback::getInterfaceDescriptor());
+ data.writeCString(device_address.c_str());
+ data.writeInt32(request_id);
+ data.writeInt32(offset);
+ data.writeInt32(is_prepare_write);
+ data.writeInt32(need_response);
+ data.writeByteArray(value.size(), value.data());
+ WriteGattIdentifierToParcel(characteristic_id, &data);
+
+ remote()->transact(
+ IBluetoothGattServerCallback::ON_CHARACTERISTIC_WRITE_REQUEST_TRANSACTION,
+ data, &reply,
+ IBinder::FLAG_ONEWAY);
+}
+
+void BpBluetoothGattServerCallback::OnDescriptorWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(
+ IBluetoothGattServerCallback::getInterfaceDescriptor());
+ data.writeCString(device_address.c_str());
+ data.writeInt32(request_id);
+ data.writeInt32(offset);
+ data.writeInt32(is_prepare_write);
+ data.writeInt32(need_response);
+ data.writeByteArray(value.size(), value.data());
+ WriteGattIdentifierToParcel(descriptor_id, &data);
+
+ remote()->transact(
+ IBluetoothGattServerCallback::ON_DESCRIPTOR_WRITE_REQUEST_TRANSACTION,
+ data, &reply,
+ IBinder::FLAG_ONEWAY);
+}
+
+void BpBluetoothGattServerCallback::OnExecuteWriteRequest(
+ const std::string& device_address,
+ int request_id, bool is_execute) {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(
+ IBluetoothGattServerCallback::getInterfaceDescriptor());
+ data.writeCString(device_address.c_str());
+ data.writeInt32(request_id);
+ data.writeInt32(is_execute);
+
+ remote()->transact(
+ IBluetoothGattServerCallback::ON_EXECUTE_WRITE_REQUEST_TRANSACTION,
+ data, &reply,
+ IBinder::FLAG_ONEWAY);
+}
+
IMPLEMENT_META_INTERFACE(BluetoothGattServerCallback,
IBluetoothGattServerCallback::kServiceName);
#pragma once
+#include <cstdint>
#include <string>
+#include <vector>
#include <base/macros.h>
#include <binder/IBinder.h>
ON_DESCRIPTOR_READ_REQUEST_TRANSACTION,
ON_CHARACTERISTIC_WRITE_REQUEST_TRANSACTION,
ON_DESCRIPTOR_WRITE_REQUEST_TRANSACTION,
- ON_EXECUTE_WRITE_TRANSACTION,
+ ON_EXECUTE_WRITE_REQUEST_TRANSACTION,
ON_NOTIFICATION_SENT_TRANSACTION,
};
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& descriptor_id) = 0;
+ virtual void OnCharacteristicWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) = 0;
+
+ virtual void OnDescriptorWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) = 0;
+
+ virtual void OnExecuteWriteRequest(
+ const std::string& device_address,
+ int request_id, bool is_execute) = 0;
+
// TODO(armansito): Complete the API definition.
private:
const std::string& device_address,
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& descriptor_id) override;
+ void OnCharacteristicWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) override;
+ void OnDescriptorWriteRequest(
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) override;
+ void OnExecuteWriteRequest(
+ const std::string& device_address,
+ int request_id, bool is_execute) override;
private:
DISALLOW_COPY_AND_ASSIGN(BpBluetoothGattServerCallback);
const std::string& device_address,
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& characteristic_id) {
- VLOG(1) << __func__;
+ VLOG(2) << __func__;
std::lock_guard<std::mutex> lock(*maps_lock());
auto gatt_cb = GetGattServerCallback(gatt_server->GetClientId());
const std::string& device_address,
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& descriptor_id) {
- VLOG(1) << __func__;
+ VLOG(2) << __func__;
std::lock_guard<std::mutex> lock(*maps_lock());
auto gatt_cb = GetGattServerCallback(gatt_server->GetClientId());
client->GetClientId() : kInvalidClientId);
}
+void BluetoothGattServerBinderServer::OnCharacteristicWriteRequest(
+ bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetClientId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnCharacteristicWriteRequest(
+ device_address, request_id, offset, is_prepare_write, need_response,
+ value, characteristic_id);
+}
+
+void BluetoothGattServerBinderServer::OnDescriptorWriteRequest(
+ bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetClientId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnDescriptorWriteRequest(
+ device_address, request_id, offset, is_prepare_write, need_response,
+ value, descriptor_id);
+}
+
+void BluetoothGattServerBinderServer::OnExecuteWriteRequest(
+ bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, bool is_execute) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetClientId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnExecuteWriteRequest(device_address, request_id, is_execute);
+}
+
} // namespace binder
} // namespace ipc
const std::string& device_address,
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& descriptor_id) override;
+ void OnCharacteristicWriteRequest(
+ bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) override;
+ void OnDescriptorWriteRequest(
+ bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) override;
+ void OnExecuteWriteRequest(
+ bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, bool is_execute) override;
private:
// Returns a pointer to the IBluetoothGattServerBinderServer instance
~TestDelegate() override = default;
struct RequestData {
- RequestData() : id(-1), offset(-1), is_long(false), count(0) {}
+ RequestData() : id(-1), offset(-1), is_long(false), is_prep(false),
+ need_rsp(false), is_exec(false), count(0) {}
~RequestData() = default;
std::string device_address;
int id;
int offset;
bool is_long;
+ bool is_prep;
+ bool need_rsp;
+ bool is_exec;
GattIdentifier gatt_id;
int count;
+ std::vector<uint8_t> write_value;
};
void OnCharacteristicReadRequest(
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& characteristic_id) override {
ASSERT_TRUE(gatt_server);
- char_req_.device_address = device_address;
- char_req_.id = request_id;
- char_req_.offset = offset;
- char_req_.is_long = is_long;
- char_req_.gatt_id = characteristic_id;
- char_req_.count++;
+ char_read_req_.device_address = device_address;
+ char_read_req_.id = request_id;
+ char_read_req_.offset = offset;
+ char_read_req_.is_long = is_long;
+ char_read_req_.gatt_id = characteristic_id;
+ char_read_req_.count++;
}
void OnDescriptorReadRequest(
int request_id, int offset, bool is_long,
const bluetooth::GattIdentifier& descriptor_id) override {
ASSERT_TRUE(gatt_server);
- desc_req_.device_address = device_address;
- desc_req_.id = request_id;
- desc_req_.offset = offset;
- desc_req_.is_long = is_long;
- desc_req_.gatt_id = descriptor_id;
- desc_req_.count++;
+ desc_read_req_.device_address = device_address;
+ desc_read_req_.id = request_id;
+ desc_read_req_.offset = offset;
+ desc_read_req_.is_long = is_long;
+ desc_read_req_.gatt_id = descriptor_id;
+ desc_read_req_.count++;
}
- const RequestData& char_req() const { return char_req_; }
- const RequestData& desc_req() const { return desc_req_; }
+ void OnCharacteristicWriteRequest(
+ GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& characteristic_id) override {
+ ASSERT_TRUE(gatt_server);
+ char_write_req_.device_address = device_address;
+ char_write_req_.id = request_id;
+ char_write_req_.offset = offset;
+ char_write_req_.is_prep = is_prepare_write;
+ char_write_req_.need_rsp = need_response;
+ char_write_req_.gatt_id = characteristic_id;
+ char_write_req_.count++;
+ char_write_req_.write_value = value;
+ }
+
+ void OnDescriptorWriteRequest(
+ GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ const bluetooth::GattIdentifier& descriptor_id) override {
+ ASSERT_TRUE(gatt_server);
+ desc_write_req_.device_address = device_address;
+ desc_write_req_.id = request_id;
+ desc_write_req_.offset = offset;
+ desc_write_req_.is_prep = is_prepare_write;
+ desc_write_req_.need_rsp = need_response;
+ desc_write_req_.gatt_id = descriptor_id;
+ desc_write_req_.count++;
+ desc_write_req_.write_value = value;
+ }
+
+ void OnExecuteWriteRequest(
+ GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, bool is_execute) override {
+ ASSERT_TRUE(gatt_server);
+ exec_req_.device_address = device_address;
+ exec_req_.id = request_id;
+ exec_req_.is_exec = is_execute;
+ exec_req_.count++;
+ }
+
+ const RequestData& char_read_req() const { return char_read_req_; }
+ const RequestData& desc_read_req() const { return desc_read_req_; }
+ const RequestData& char_write_req() const { return char_write_req_; }
+ const RequestData& desc_write_req() const { return desc_write_req_; }
private:
- RequestData char_req_;
- RequestData desc_req_;
+ RequestData char_read_req_;
+ RequestData desc_read_req_;
+ RequestData char_write_req_;
+ RequestData desc_write_req_;
+ RequestData exec_req_;
};
class GattServerTest : public ::testing::Test {
// Unknown connection ID shouldn't trigger anything.
fake_hal_gatt_iface_->NotifyRequestReadCallback(
kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0, false);
- EXPECT_EQ(0, test_delegate.char_req().count);
- EXPECT_EQ(0, test_delegate.desc_req().count);
+ EXPECT_EQ(0, test_delegate.char_read_req().count);
+ EXPECT_EQ(0, test_delegate.desc_read_req().count);
// Unknown device address shouldn't trigger anything.
fake_hal_gatt_iface_->NotifyRequestReadCallback(
kConnId0, kReqId0, hal_addr1, char_handle_, 0, false);
- EXPECT_EQ(0, test_delegate.char_req().count);
- EXPECT_EQ(0, test_delegate.desc_req().count);
+ EXPECT_EQ(0, test_delegate.char_read_req().count);
+ EXPECT_EQ(0, test_delegate.desc_read_req().count);
// Unknown attribute handle shouldn't trigger anything.
fake_hal_gatt_iface_->NotifyRequestReadCallback(
kConnId0, kReqId0, hal_addr0, char_handle_ + 50, 0, false);
- EXPECT_EQ(0, test_delegate.char_req().count);
- EXPECT_EQ(0, test_delegate.desc_req().count);
+ EXPECT_EQ(0, test_delegate.char_read_req().count);
+ EXPECT_EQ(0, test_delegate.desc_read_req().count);
// Characteristic and descriptor handles should trigger correct callbacks.
fake_hal_gatt_iface_->NotifyRequestReadCallback(
kConnId0, kReqId0, hal_addr0, char_handle_, 0, false);
- EXPECT_EQ(1, test_delegate.char_req().count);
- EXPECT_EQ(kTestAddress0, test_delegate.char_req().device_address);
- EXPECT_EQ(kReqId0, test_delegate.char_req().id);
- EXPECT_EQ(0, test_delegate.char_req().offset);
- EXPECT_FALSE(test_delegate.char_req().is_long);
- EXPECT_TRUE(test_char_id_ == test_delegate.char_req().gatt_id);
- EXPECT_EQ(0, test_delegate.desc_req().count);
+ EXPECT_EQ(1, test_delegate.char_read_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.char_read_req().device_address);
+ EXPECT_EQ(kReqId0, test_delegate.char_read_req().id);
+ EXPECT_EQ(0, test_delegate.char_read_req().offset);
+ EXPECT_FALSE(test_delegate.char_read_req().is_long);
+ EXPECT_TRUE(test_char_id_ == test_delegate.char_read_req().gatt_id);
+ EXPECT_EQ(0, test_delegate.desc_read_req().count);
fake_hal_gatt_iface_->NotifyRequestReadCallback(
kConnId0, kReqId1, hal_addr0, desc_handle_, 2, true);
- EXPECT_EQ(1, test_delegate.char_req().count);
- EXPECT_EQ(1, test_delegate.desc_req().count);
- EXPECT_EQ(kTestAddress0, test_delegate.desc_req().device_address);
- EXPECT_EQ(kReqId1, test_delegate.desc_req().id);
- EXPECT_EQ(2, test_delegate.desc_req().offset);
- EXPECT_TRUE(test_delegate.desc_req().is_long);
- EXPECT_TRUE(test_desc_id_ == test_delegate.desc_req().gatt_id);
+ EXPECT_EQ(1, test_delegate.char_read_req().count);
+ EXPECT_EQ(1, test_delegate.desc_read_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.desc_read_req().device_address);
+ EXPECT_EQ(kReqId1, test_delegate.desc_read_req().id);
+ EXPECT_EQ(2, test_delegate.desc_read_req().offset);
+ EXPECT_TRUE(test_delegate.desc_read_req().is_long);
+ EXPECT_TRUE(test_desc_id_ == test_delegate.desc_read_req().gatt_id);
// Callback with a pending request ID will be ignored.
fake_hal_gatt_iface_->NotifyRequestReadCallback(
kConnId0, kReqId0, hal_addr0, char_handle_, 0, false);
fake_hal_gatt_iface_->NotifyRequestReadCallback(
kConnId0, kReqId1, hal_addr0, char_handle_, 0, false);
- EXPECT_EQ(1, test_delegate.char_req().count);
- EXPECT_EQ(1, test_delegate.desc_req().count);
+ EXPECT_EQ(1, test_delegate.char_read_req().count);
+ EXPECT_EQ(1, test_delegate.desc_read_req().count);
// Send response for wrong device address.
EXPECT_FALSE(gatt_server_->SendResponse(
gatt_server_->SetDelegate(nullptr);
}
+TEST_F(GattServerPostRegisterTest, RequestWrite) {
+ SetUpTestService();
+
+ TestDelegate test_delegate;
+ gatt_server_->SetDelegate(&test_delegate);
+
+ const std::vector<uint8_t> kTestValue = { 0x01, 0x02, 0x03 };
+ const std::string kTestAddress0 = "01:23:45:67:89:AB";
+ const std::string kTestAddress1 = "CD:EF:01:23:45:67";
+ const int kReqId0 = 0;
+ const int kReqId1 = 1;
+ const int kConnId0 = 1;
+
+ // No pending request.
+ EXPECT_FALSE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ bt_bdaddr_t hal_addr0, hal_addr1;
+ ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0));
+ ASSERT_TRUE(util::BdAddrFromString(kTestAddress1, &hal_addr1));
+
+ // Send a connection callback. The GattServer should store the connection
+ // information and be able to process the incoming read requests for this
+ // connection.
+ fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+ kConnId0, kDefaultServerId, true, hal_addr0);
+
+ // Unknown connection ID shouldn't trigger anything.
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0,
+ kTestValue.size(), true, false, (uint8_t *)kTestValue.data());
+ EXPECT_EQ(0, test_delegate.char_write_req().count);
+ EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+ // Unknown device address shouldn't trigger anything.
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0, kReqId0, hal_addr1, char_handle_, 0,
+ kTestValue.size(), true, false, (uint8_t *)kTestValue.data());
+ EXPECT_EQ(0, test_delegate.char_write_req().count);
+ EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+ // Unknown attribute handle shouldn't trigger anything.
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_ + 50, 0,
+ kTestValue.size(), true, false, (uint8_t *)kTestValue.data());
+ EXPECT_EQ(0, test_delegate.char_write_req().count);
+ EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+ // Characteristic and descriptor handles should trigger correct callbacks.
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0,
+ kTestValue.size(), true, false, (uint8_t *)kTestValue.data());
+ EXPECT_EQ(1, test_delegate.char_write_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.char_write_req().device_address);
+ EXPECT_EQ(kReqId0, test_delegate.char_write_req().id);
+ EXPECT_EQ(0, test_delegate.char_write_req().offset);
+ EXPECT_EQ(true, test_delegate.char_write_req().need_rsp);
+ EXPECT_EQ(false, test_delegate.char_write_req().is_exec);
+ EXPECT_EQ(kTestValue, test_delegate.char_write_req().write_value);
+ EXPECT_TRUE(test_char_id_ == test_delegate.char_write_req().gatt_id);
+ EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0, kReqId1, hal_addr0, desc_handle_, 2,
+ kTestValue.size(), true, false, (uint8_t *)kTestValue.data());
+ EXPECT_EQ(1, test_delegate.char_write_req().count);
+ EXPECT_EQ(1, test_delegate.desc_write_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.desc_write_req().device_address);
+ EXPECT_EQ(kReqId1, test_delegate.desc_write_req().id);
+ EXPECT_EQ(2, test_delegate.desc_write_req().offset);
+ EXPECT_EQ(true, test_delegate.desc_write_req().need_rsp);
+ EXPECT_EQ(false, test_delegate.desc_write_req().is_exec);
+ EXPECT_EQ(kTestValue, test_delegate.desc_write_req().write_value);
+ EXPECT_TRUE(test_desc_id_ == test_delegate.desc_write_req().gatt_id);
+
+ // Callback with a pending request ID will be ignored.
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0,
+ kTestValue.size(), true, false, (uint8_t *)kTestValue.data());
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0, kReqId1, hal_addr0, char_handle_, 0,
+ kTestValue.size(), true, false, (uint8_t *)kTestValue.data());
+ EXPECT_EQ(1, test_delegate.char_write_req().count);
+ EXPECT_EQ(1, test_delegate.desc_write_req().count);
+
+ // Send response for wrong device address.
+ EXPECT_FALSE(gatt_server_->SendResponse(
+ kTestAddress1, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId0,
+ BT_STATUS_SUCCESS, _))
+ .Times(2)
+ .WillOnce(Return(BT_STATUS_FAIL))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // Stack call fails.
+ EXPECT_FALSE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Successful send response for characteristic.
+ EXPECT_TRUE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Characteristic request ID no longer pending.
+ EXPECT_FALSE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId1,
+ BT_STATUS_SUCCESS, _))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // Successful send response for descriptor.
+ EXPECT_TRUE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId1,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Descriptor request ID no longer pending.
+ EXPECT_FALSE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId1,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // SendResponse should fail for a "Write Without Response".
+ fake_hal_gatt_iface_->NotifyRequestWriteCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0,
+ kTestValue.size(), false, false, (uint8_t *)kTestValue.data());
+ EXPECT_EQ(false, test_delegate.char_write_req().need_rsp);
+ EXPECT_FALSE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ gatt_server_->SetDelegate(nullptr);
+}
+
} // namespace
} // namespace bluetooth