Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a909267 authored by Andre Eisenbach's avatar Andre Eisenbach Committed by android-build-merger
Browse files

Merge "Workaround for H4 HCI stream corruption during LE scans" into mnc-dr-dev

am: d08b6e19

* commit 'd08b6e19':
  Workaround for H4 HCI stream corruption during LE scans
parents 314e22b4 d08b6e19
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include "vendor.h"

#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
#define HCI_BLE_EVENT 0x3e

// Increased HCI thread priority to keep up with the audio sub-system
// when streaming time sensitive data (A2DP).
@@ -47,6 +48,8 @@ static int uart_fd;
static eager_reader_t *uart_stream;
static serial_data_type_t current_data_type;
static bool stream_has_interpretation;
static bool stream_corruption_detected;
static uint8_t stream_corruption_bytes_to_ignore;

static void event_uart_has_bytes(eager_reader_t *reader, void *context);

@@ -86,6 +89,8 @@ static bool hal_open() {
  }

  stream_has_interpretation = false;
  stream_corruption_detected = false;
  stream_corruption_bytes_to_ignore = 0;
  eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);

  // Raise thread priorities to keep up with audio
@@ -177,6 +182,40 @@ done:;

// Internal functions

// WORKAROUND:
// As exhibited by b/23934838, during result-heavy LE scans, the UART byte
// stream can get corrupted, leading to assertions caused by mis-interpreting
// the bytes following the corruption.
// This workaround looks for tell-tale signs of a BLE event and attempts to
// skip the correct amount of bytes in the stream to re-synchronize onto
// a packet boundary.
// Function returns true if |byte_read| has been processed by the workaround.
static bool stream_corrupted_during_le_scan_workaround(const uint8_t byte_read)
{
  if (!stream_corruption_detected && byte_read == HCI_BLE_EVENT) {
    LOG_ERROR("%s HCI stream corrupted (message type 0x3E)!", __func__);
    stream_corruption_detected = true;
    return true;
  }

  if (stream_corruption_detected) {
    if (stream_corruption_bytes_to_ignore == 0) {
      stream_corruption_bytes_to_ignore = byte_read;
      LOG_ERROR("%s About to skip %d bytes...", __func__, stream_corruption_bytes_to_ignore);
    } else {
      --stream_corruption_bytes_to_ignore;
    }

    if (stream_corruption_bytes_to_ignore == 0) {
      LOG_ERROR("%s Back to our regularly scheduled program...", __func__);
      stream_corruption_detected = false;
    }
    return true;
  }

  return false;
}

// See what data is waiting, and notify the upper layer
static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *context) {
  if (stream_has_interpretation) {
@@ -187,6 +226,10 @@ static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *conte
      LOG_ERROR("%s could not read HCI message type", __func__);
      return;
    }

    if (stream_corrupted_during_le_scan_workaround(type_byte))
      return;

    if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
      LOG_ERROR("%s Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
      return;
+7 −0
Original line number Diff line number Diff line
@@ -43,6 +43,9 @@ DECLARE_TEST_MODES(
  type_byte_only
);

// Use as packet type to test stream_corrupted_during_le_scan_workaround()
static const uint8_t HCI_BLE_EVENT = 0x3e;

static char sample_data1[100] = "A point is that which has no part.";
static char sample_data2[100] = "A line is breadthless length.";
static char sample_data3[100] = "The ends of a line are points.";
@@ -50,6 +53,9 @@ static char acl_data[100] = "A straight line is a line which lies evenly wit
static char sco_data[100] =     "A surface is that which has length and breadth only.";
static char event_data[100] =   "The edges of a surface are lines.";

// Test data for stream_corrupted_during_le_scan_workaround()
static char corrupted_data[] = { 0x5 /* length of remaining data */, 'H', 'e', 'l', 'l', 'o' };

static const hci_hal_t *hal;
static int dummy_serial_fd;
static int reentry_i = 0;
@@ -221,6 +227,7 @@ TEST_F(HciHalH4Test, test_read_synchronous) {
  reset_for(read_synchronous);

  write_packet(sockfd[1], DATA_TYPE_ACL, acl_data);
  write_packet(sockfd[1], HCI_BLE_EVENT, corrupted_data);
  write_packet(sockfd[1], DATA_TYPE_SCO, sco_data);
  write_packet(sockfd[1], DATA_TYPE_EVENT, event_data);