service: Support GattServer notifications/indications
Added outgoing notification/indication support to
bluetooth::GattServer and implemented the related Binder API.
Bug: 24245347
Change-Id: I2d5cea90137e5d771f969163591b50aee1ad171c
diff --git a/service/gatt_server.cpp b/service/gatt_server.cpp
index 0a4ba0a..0517684 100644
--- a/service/gatt_server.cpp
+++ b/service/gatt_server.cpp
@@ -366,6 +366,85 @@
return true;
}
+bool GattServer::SendNotification(
+ const std::string& device_address,
+ const GattIdentifier& characteristic_id,
+ bool confirm,
+ const std::vector<uint8_t>& value,
+ const GattCallback& callback) {
+ VLOG(1) << " - server_if: " << server_if_
+ << " device_address: " << device_address
+ << " confirm: " << confirm;
+ lock_guard<mutex> lock(mutex_);
+
+ bt_bdaddr_t addr;
+ if (!util::BdAddrFromString(device_address, &addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ // Get the connection IDs for which we will send this notification.
+ auto conn_iter = conn_addr_map_.find(device_address);
+ if (conn_iter == conn_addr_map_.end()) {
+ LOG(ERROR) << "No known connections for device with address: "
+ << device_address;
+ return false;
+ }
+
+ // Make sure that |characteristic_id| matches a valid attribute handle.
+ auto handle_iter = id_to_handle_map_.find(characteristic_id);
+ if (handle_iter == id_to_handle_map_.end()) {
+ LOG(ERROR) << "Unknown characteristic";
+ return false;
+ }
+
+ std::shared_ptr<PendingIndication> pending_ind(
+ new PendingIndication(callback));
+
+ // Send the notification/indication on all matching connections.
+ int send_count = 0;
+ for (auto conn : conn_iter->second) {
+ // Make sure that one isn't already pending for this connection.
+ if (pending_indications_.find(conn->conn_id) !=
+ pending_indications_.end()) {
+ VLOG(1) << "A" << (confirm ? "n indication" : " notification")
+ << " is already pending for connection: " << conn->conn_id;
+ continue;
+ }
+
+ // The HAL API takes char* rather const char* for |value|, so we have to
+ // cast away the const.
+ // TODO(armansito): Make HAL accept const char*.
+ bt_status_t status = hal::BluetoothGattInterface::Get()->
+ GetServerHALInterface()->send_indication(
+ server_if_,
+ handle_iter->second,
+ conn->conn_id,
+ value.size(),
+ confirm,
+ reinterpret_cast<char*>(const_cast<uint8_t*>(value.data())));
+
+ // Increment the send count if this was successful. We don't immediately
+ // fail if the HAL returned an error. It's better to report success as long
+ // as we sent out at least one notification to this device as
+ // multi-transport GATT connections from the same BD_ADDR will be rare
+ // enough already.
+ if (status != BT_STATUS_SUCCESS)
+ continue;
+
+ send_count++;
+ pending_indications_[conn->conn_id] = pending_ind;
+ }
+
+ if (send_count == 0) {
+ LOG(ERROR) << "Failed to send notifications/indications to device: "
+ << device_address;
+ return false;
+ }
+
+ return true;
+}
+
void GattServer::ConnectionCallback(
hal::BluetoothGattInterface* /* gatt_iface */,
int conn_id, int server_if,
@@ -711,6 +790,32 @@
delegate_->OnExecuteWriteRequest(this, device_address, trans_id, exec_write);
}
+void GattServer::IndicationSentCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */,
+ int conn_id, int status) {
+ VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status;
+ lock_guard<mutex> lock(mutex_);
+
+ const auto& pending_ind_iter = pending_indications_.find(conn_id);
+ if (pending_ind_iter == pending_indications_.end()) {
+ VLOG(1) << "Unknown connection: " << conn_id;
+ return;
+ }
+
+ std::shared_ptr<PendingIndication> pending_ind = pending_ind_iter->second;
+ pending_indications_.erase(pending_ind_iter);
+
+ if (status == BT_STATUS_SUCCESS)
+ pending_ind->has_success = true;
+
+ // Invoke it if this was the last reference to the confirmation callback.
+ if (pending_ind.unique() && pending_ind->callback) {
+ pending_ind->callback(
+ pending_ind->has_success ?
+ GATT_ERROR_NONE : static_cast<GATTError>(status));
+ }
+}
+
void GattServer::NotifyEndCallbackAndClearData(
BLEStatus status, const GattIdentifier& id) {
VLOG(1) << __func__ << " status: " << status;