OSDN Git Service

service: Support GATT server async write requests.
authorArman Uguray <armansito@google.com>
Wed, 30 Sep 2015 05:09:46 +0000 (22:09 -0700)
committerArman Uguray <armansito@google.com>
Mon, 5 Oct 2015 23:43:58 +0000 (16:43 -0700)
Added support for incoming characteristic/descriptor read requests
to bluetooth::GattServer and implemented the related Binder API.

Bug: 24245347
Change-Id: I18202c3255f0fb8fc5338b1139c375e1439b6568

13 files changed:
service/example/heart_rate/heart_rate_server.cpp
service/example/heart_rate/heart_rate_server.h
service/gatt_server.cpp
service/gatt_server.h
service/hal/bluetooth_gatt_interface.cpp
service/hal/bluetooth_gatt_interface.h
service/hal/fake_bluetooth_gatt_interface.cpp
service/hal/fake_bluetooth_gatt_interface.h
service/ipc/binder/IBluetoothGattServerCallback.cpp
service/ipc/binder/IBluetoothGattServerCallback.h
service/ipc/binder/bluetooth_gatt_server_binder_server.cpp
service/ipc/binder/bluetooth_gatt_server_binder_server.h
service/test/gatt_server_unittest.cpp

index cd1c4c9..6f4a691 100644 (file)
@@ -188,4 +188,26 @@ void HeartRateServer::OnDescriptorReadRequest(
   // 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
index 19d824f..f70673d 100644 (file)
@@ -51,6 +51,19 @@ class HeartRateServer : public ipc::binder::BnBluetoothGattServerCallback {
       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_;
 
index 272d24a..0a4ba0a 100644 (file)
@@ -342,11 +342,16 @@ bool GattServer::SendResponse(
   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(
@@ -602,6 +607,110 @@ void GattServer::RequestReadCallback(
   }
 }
 
+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;
index dc48b3f..35cc587 100644 (file)
@@ -65,6 +65,47 @@ class GattServer : public BluetoothClientInstance,
         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);
   };
@@ -223,6 +264,16 @@ class GattServer : public BluetoothClientInstance,
       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,
index ae8d2df..d4ea097 100644 (file)
@@ -204,6 +204,35 @@ void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
       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 = {
@@ -253,8 +282,8 @@ const btgatt_server_callbacks_t gatt_server_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
@@ -498,6 +527,29 @@ void BluetoothGattInterface::ServerObserver::RequestReadCallback(
   // 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);
index 4ee9820..8dfba6e 100644 (file)
@@ -124,6 +124,18 @@ class BluetoothGattInterface {
         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.
   };
 
index 7ebbf65..8ab2a41 100644 (file)
@@ -306,6 +306,25 @@ void FakeBluetoothGattInterface::NotifyRequestReadCallback(
           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);
index 9aeabc3..7b24928 100644 (file)
@@ -107,6 +107,12 @@ class FakeBluetoothGattInterface : public BluetoothGattInterface {
   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;
index ac4e746..de9d0ba 100644 (file)
@@ -81,6 +81,58 @@ status_t BnBluetoothGattServerCallback::onTransact(
                             *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);
   }
@@ -164,6 +216,69 @@ void BpBluetoothGattServerCallback::OnDescriptorReadRequest(
       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);
 
index 1f31903..ca3e036 100644 (file)
@@ -16,7 +16,9 @@
 
 #pragma once
 
+#include <cstdint>
 #include <string>
+#include <vector>
 
 #include <base/macros.h>
 #include <binder/IBinder.h>
@@ -48,7 +50,7 @@ namespace binder {
     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,
   };
 
@@ -67,6 +69,22 @@ namespace binder {
       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:
@@ -111,6 +129,19 @@ class BpBluetoothGattServerCallback
       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);
index 1c250b4..0f7e850 100644 (file)
@@ -192,7 +192,7 @@ void BluetoothGattServerBinderServer::OnCharacteristicReadRequest(
     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());
@@ -210,7 +210,7 @@ void BluetoothGattServerBinderServer::OnDescriptorReadRequest(
     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());
@@ -254,5 +254,61 @@ void BluetoothGattServerBinderServer::OnRegisterClientImpl(
           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
index 5dd78bd..ae90af9 100644 (file)
@@ -69,6 +69,22 @@ class BluetoothGattServerBinderServer : public BnBluetoothGattServer,
       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
index f1759c0..fb1b5eb 100644 (file)
@@ -53,15 +53,20 @@ class TestDelegate : public GattServer::Delegate {
   ~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(
@@ -70,12 +75,12 @@ class TestDelegate : public GattServer::Delegate {
       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(
@@ -84,20 +89,70 @@ class TestDelegate : public GattServer::Delegate {
       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 {
@@ -915,49 +970,49 @@ TEST_F(GattServerPostRegisterTest, RequestRead) {
   // 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(
@@ -1008,5 +1063,144 @@ TEST_F(GattServerPostRegisterTest, RequestRead) {
   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