OSDN Git Service

HCI: Set a timer to abort after a timeout
authorMyles Watson <mylesgw@google.com>
Sat, 24 Feb 2018 01:28:23 +0000 (17:28 -0800)
committerMyles Watson <mylesgw@google.com>
Mon, 26 Feb 2018 23:43:00 +0000 (23:43 +0000)
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

hci/src/hci_layer.cc

index 2ae12f3..5111fc5 100644 (file)
@@ -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,14 +536,15 @@ 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.
-  abort();
+  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