Bluetooth HAL: Add missing retry logic to the H4Protocol::Send()
As part of an optimization, H4Protocol::Send() is modified to
use writev() instead of WriteSafely(), which has a retry logic
to send remaining bytes if the underlying write() call couldn't
transfer all the bytes in a single system call. This cl is now
adding this missing retry logic to this function.
Bug: 198992020
Test: H4 UTTest, Bluetooth functional test.
Change-Id: I78fad886d52f0910c83b000d5768128f00d3ddbc
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index 43abbe4..33238da 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -30,21 +30,52 @@
namespace hci {
size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
- struct iovec iov[] = {{&type, sizeof(type)},
- {const_cast<uint8_t*>(data), length}};
- ssize_t ret = 0;
- do {
- ret =
- TEMP_FAILURE_RETRY(writev(uart_fd_, iov, sizeof(iov) / sizeof(iov[0])));
- } while (-1 == ret && EAGAIN == errno);
-
- if (ret == -1) {
- ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
- } else if (ret < static_cast<ssize_t>(length + 1)) {
- ALOGE("%s: %d / %d bytes written - something went wrong...", __func__,
- static_cast<int>(ret), static_cast<int>(length + 1));
+ struct iovec iov_array[] = {{&type, sizeof(type)},
+ {const_cast<uint8_t*>(data), length}};
+ struct iovec* iov = iov_array;
+ int iovcnt = sizeof(iov_array) / sizeof(iov_array[0]);
+ size_t total_bytes = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ total_bytes += iov_array[i].iov_len;
}
- return ret;
+ size_t bytes_written = 0;
+ size_t remaining_bytes = total_bytes;
+
+ while (remaining_bytes > 0) {
+ ssize_t ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, iovcnt));
+ if (ret == -1) {
+ if (errno == EAGAIN) continue;
+ ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ break;
+ } else if (ret == 0) {
+ // Nothing written
+ ALOGE("%s zero bytes written - something went wrong...", __func__);
+ break;
+ } else if (ret == remaining_bytes) {
+ // Everything written
+ bytes_written += ret;
+ break;
+ }
+
+ bytes_written += ret;
+ remaining_bytes -= ret;
+ ALOGW("%s: %d/%d bytes written - retrying remaining %d bytes", __func__,
+ static_cast<int>(bytes_written), static_cast<int>(total_bytes),
+ static_cast<int>(remaining_bytes));
+
+ // Remove iovs which are written from the list
+ while (ret >= iov->iov_len) {
+ ret -= iov->iov_len;
+ ++iov;
+ --iovcnt;
+ }
+ // Adjust the iov to point to the remaining data which needs to be written
+ if (ret) {
+ iov->iov_base = static_cast<uint8_t*>(iov->iov_base) + ret;
+ iov->iov_len -= ret;
+ }
+ }
+ return bytes_written;
}
void H4Protocol::OnPacketReady() {