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

Commit 1663b471 authored by Myles Watson's avatar Myles Watson
Browse files

HCI: Set a timer to abort after a timeout

Add code to clean up the timer and close the file whether
abort gets called or not.

Bug: 72719600
Bug: 72474659
Test: Cause an HCI timeout and wait for the firmware dump
Change-Id: I713f440d77bfad4c9f17dfc57f98ba5bada37fff
parent 5ef1d020
Loading
Loading
Loading
Loading
+36 −8
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ static const int BT_HCI_RT_PRIORITY = 1;

// Abort if there is no response to an HCI command.
static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 2000;
static const uint32_t COMMAND_TIMEOUT_RESTART_US = 5000000;
static const uint32_t COMMAND_TIMEOUT_RESTART_MS = 5000;

// Our interface
static bool interface_created;
@@ -106,6 +106,7 @@ static std::queue<base::Closure> command_queue;
static alarm_t* command_response_timer;
static list_t* commands_pending_response;
static std::recursive_mutex commands_pending_response_mutex;
static alarm_t* hci_timeout_abort_timer;

// The hand-off point for data going to a higher layer, set by the higher layer
static base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
@@ -286,6 +287,17 @@ static future_t* hci_module_shut_down() {
  thread_free(thread);
  thread = NULL;

  // Clean up abort timer, if it exists.
  if (hci_timeout_abort_timer != NULL) {
    alarm_free(hci_timeout_abort_timer);
    hci_timeout_abort_timer = NULL;
  }

  if (hci_firmware_log_fd != INVALID_FD) {
    hci_close_firmware_log_file(hci_firmware_log_fd);
    hci_firmware_log_fd = INVALID_FD;
  }

  return NULL;
}

@@ -453,6 +465,16 @@ static void fragmenter_transmit_finished(BT_HDR* packet,
  }
}

// Abort.  The chip has had time to write any debugging information.
static void hci_timeout_abort(void* unused_data) {
  LOG_ERROR(LOG_TAG, "%s restarting the Bluetooth process.", __func__);
  hci_close_firmware_log_file(hci_firmware_log_fd);

  // We shouldn't try to recover the stack from this command timeout.
  // If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
  abort();
}

// Print debugging information and quit. Don't dereference original_wait_entry.
static void command_timed_out(void* original_wait_entry) {
  std::unique_lock<std::recursive_mutex> lock(commands_pending_response_mutex);
@@ -488,6 +510,11 @@ static void command_timed_out(void* original_wait_entry) {
  }
  lock.unlock();

  // Don't request a firmware dump for multiple hci timeouts
  if (hci_timeout_abort_timer != NULL || hci_firmware_log_fd != INVALID_FD) {
    return;
  }

  LOG_ERROR(LOG_TAG, "%s: requesting a firmware dump.", __func__);

  /* Allocate a buffer to hold the HCI command. */
@@ -509,15 +536,16 @@ static void command_timed_out(void* original_wait_entry) {
  transmit_fragment(bt_hdr, true);

  osi_free(bt_hdr);
  LOG_ERROR(LOG_TAG, "%s: Setting a timer to restart.", __func__);

  LOG_ERROR(LOG_TAG, "%s restarting the Bluetooth process.", __func__);
  usleep(COMMAND_TIMEOUT_RESTART_US);
  hci_close_firmware_log_file(hci_firmware_log_fd);

  // We shouldn't try to recover the stack from this command timeout.
  // If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
  hci_timeout_abort_timer = alarm_new("hci.hci_timeout_aborter");
  if (!hci_timeout_abort_timer) {
    LOG_ERROR(LOG_TAG, "%s unable to create an abort timer.", __func__);
    abort();
  }
  alarm_set(hci_timeout_abort_timer, COMMAND_TIMEOUT_RESTART_MS,
            hci_timeout_abort, nullptr);
}

// Event/packet receiving functions
void process_command_credits(int credits) {