OSDN Git Service

Preload timeout and retry mechanism (1/3)
authorYK Jeffrey Chao <jechao@broadcom.com>
Wed, 24 Apr 2013 18:38:06 +0000 (11:38 -0700)
committerMatthew Xie <mattx@google.com>
Tue, 14 May 2013 22:50:58 +0000 (15:50 -0700)
If the Preload process was stuck due to unknown hardware init failure,
a 8-second ENABLE_TIMEOUT timeout would be eventually expired in Java layer
at AdapterState and attempted to set BT state back to STATE_OFF.
However BluetoothManagerService did not handle this case accordingly and led
to state mis-matching between Java layer and BTIF at the end.

Add a timeout and retry mechanism to manage Preload process.
Clean up native space resource and explicitly report STATE_OFF back to Java
space when Preload did not go through.

bug  7566317

Change-Id: I99a225e524f2b951249618990a2d0a8a39b43ff3

btif/src/btif_core.c
hci/src/bt_hci_bdroid.c
hci/src/bt_hw.c
main/bte_main.c
stack/btu/btu_task.c
stack/include/bt_types.h

index ca39cc8..a3045d6 100644 (file)
@@ -130,7 +130,7 @@ extern void bte_load_did_conf(const char *p_path);
 
 /** TODO: Move these to _common.h */
 void bte_main_boot_entry(void);
-void bte_main_enable(uint8_t *local_addr);
+void bte_main_enable();
 void bte_main_disable(void);
 void bte_main_shutdown(void);
 #if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
@@ -296,6 +296,23 @@ static void btif_task(UINT32 params)
             BTA_EnableBluetooth(bte_dm_evt);
         }
 
+        /*
+         * Failed to initialize controller hardware, reset state and bring
+         * down all threads
+         */
+        if (event == BT_EVT_HARDWARE_INIT_FAIL)
+        {
+            BTIF_TRACE_DEBUG0("btif_task: hardware init failed");
+            bte_main_disable();
+            btif_queue_release();
+            GKI_task_self_cleanup(BTIF_TASK);
+            bte_main_shutdown();
+            btif_dut_mode = 0;
+            btif_core_state = BTIF_CORE_STATE_DISABLED;
+            HAL_CBACK(bt_hal_cbacks,adapter_state_changed_cb,BT_STATE_OFF);
+            break;
+        }
+
         if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
             break;
 
@@ -516,7 +533,7 @@ bt_status_t btif_enable_bluetooth(void)
     btif_core_state = BTIF_CORE_STATE_ENABLING;
 
     /* Create the GKI tasks and run them */
-    bte_main_enable(btif_local_bd_addr.address);
+    bte_main_enable();
 
     return BT_STATUS_SUCCESS;
 }
@@ -731,6 +748,16 @@ bt_status_t btif_shutdown_bluetooth(void)
 
     btif_shutdown_pending = 0;
 
+    if (btif_core_state == BTIF_CORE_STATE_ENABLING)
+    {
+        // Java layer abort BT ENABLING, could be due to ENABLE TIMEOUT
+        // Direct call from cleanup()@bluetooth.c
+        // bring down HCI/Vendor lib
+        bte_main_disable();
+        btif_core_state = BTIF_CORE_STATE_DISABLED;
+        HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
+    }
+
     GKI_destroy_task(BTIF_TASK);
     btif_queue_release();
     bte_main_shutdown();
index 90249aa..8e4f8ff 100644 (file)
@@ -75,6 +75,7 @@ void btsnoop_close(void);
 bt_hc_callbacks_t *bt_hc_cbacks = NULL;
 BUFFER_Q tx_q;
 tHCI_IF *p_hci_if;
+volatile uint8_t fwcfg_acked;
 
 /******************************************************************************
 **  Local type definitions
@@ -191,6 +192,7 @@ static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
     }
 
     hc_cb.epilog_timer_created = 0;
+    fwcfg_acked = FALSE;
 
     /* store reference to user callbacks */
     bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb;
@@ -361,9 +363,16 @@ static void cleanup( void )
 
     if (lib_running)
     {
-        epilog_wait_timer();
+        if (fwcfg_acked == TRUE)
+        {
+            epilog_wait_timer();
+            bthc_signal_event(HC_EVENT_EPILOG);
+        }
+        else
+        {
+            bthc_signal_event(HC_EVENT_EXIT);
+        }
 
-        bthc_signal_event(HC_EVENT_EPILOG);
         pthread_join(hc_cb.worker_thread, NULL);
 
         if (hc_cb.epilog_timer_created == 1)
@@ -384,6 +393,7 @@ static void cleanup( void )
     if (bt_vnd_if)
         bt_vnd_if->cleanup();
 
+    fwcfg_acked = FALSE;
     bt_hc_cbacks = NULL;
 }
 
index fae296b..5265dce 100644 (file)
@@ -39,6 +39,7 @@
 ******************************************************************************/
 
 extern tHCI_IF *p_hci_if;
+extern uint8_t fwcfg_acked;
 void lpm_vnd_cback(uint8_t vnd_result);
 
 /******************************************************************************
@@ -67,6 +68,8 @@ static void fwcfg_cb(bt_vendor_op_result_t result)
     bt_hc_postload_result_t status = (result == BT_VND_OP_RESULT_SUCCESS) ? \
                                      BT_HC_PRELOAD_SUCCESS : BT_HC_PRELOAD_FAIL;
 
+    fwcfg_acked = TRUE;
+
     if (bt_hc_cbacks)
         bt_hc_cbacks->preload_cb(NULL, status);
 }
index 4e7e37c..3294d79 100644 (file)
@@ -26,6 +26,9 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <signal.h>
+#include <time.h>
+#include <hardware/bluetooth.h>
 
 #include "gki.h"
 #include "bd.h"
 #define HCI_LOGGING_FILENAME  "/data/misc/bluedroid/btsnoop_hci.log"
 #endif
 
+/* Stack preload process timeout period  */
+#ifndef PRELOAD_START_TIMEOUT_MS
+#define PRELOAD_START_TIMEOUT_MS 3000  // 3 seconds
+#endif
+
+/* Stack preload process maximum retry attempts  */
+#ifndef PRELOAD_MAX_RETRY_ATTEMPTS
+#define PRELOAD_MAX_RETRY_ATTEMPTS 0
+#endif
+
 /*******************************************************************************
 **  Local type definitions
 *******************************************************************************/
+/* Preload retry control block */
+typedef struct
+{
+    int     retry_counts;
+    BOOLEAN timer_created;
+    timer_t timer_id;
+} bt_preload_retry_cb_t;
 
 /******************************************************************************
 **  Variables
@@ -65,11 +85,16 @@ char hci_logfile[256] = HCI_LOGGING_FILENAME;
 static bt_hc_interface_t *bt_hc_if=NULL;
 static const bt_hc_callbacks_t hc_callbacks;
 static BOOLEAN lpm_enabled = FALSE;
+static bt_preload_retry_cb_t preload_retry_cb;
 
 /*******************************************************************************
 **  Static functions
 *******************************************************************************/
 static void bte_main_in_hw_init(void);
+static void bte_hci_enable(void);
+static void bte_hci_disable(void);
+static void preload_start_wait_timer(void);
+static void preload_stop_wait_timer(void);
 
 /*******************************************************************************
 **  Externs
@@ -80,6 +105,7 @@ BT_API extern void BTE_LoadStack(void);
 BT_API void BTE_UnloadStack(void);
 extern void scru_flip_bda (BD_ADDR dst, const BD_ADDR src);
 extern void bte_load_conf(const char *p_path);
+extern bt_bdaddr_t btif_local_bd_addr;
 
 
 /*******************************************************************************
@@ -102,13 +128,15 @@ UINT32 bte_btu_stack[(BTE_BTU_STACK_SIZE + 3) / 4];
 ** Returns          None
 **
 ******************************************************************************/
-void bte_main_in_hw_init(void)
+static void bte_main_in_hw_init(void)
 {
     if ( (bt_hc_if = (bt_hc_interface_t *) bt_hc_get_interface()) \
          == NULL)
     {
         APPL_TRACE_ERROR0("!!! Failed to get BtHostControllerInterface !!!");
     }
+
+    memset(&preload_retry_cb, 0, sizeof(bt_preload_retry_cb_t));
 }
 
 /******************************************************************************
@@ -159,7 +187,7 @@ void bte_main_shutdown()
 ** Returns          None
 **
 ******************************************************************************/
-void bte_main_enable(uint8_t *local_addr)
+void bte_main_enable()
 {
     APPL_TRACE_DEBUG1("%s", __FUNCTION__);
 
@@ -168,9 +196,53 @@ void bte_main_enable(uint8_t *local_addr)
 
     lpm_enabled = FALSE;
 
+    bte_hci_enable();
+
+    GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
+                    (UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
+                    sizeof(bte_btu_stack));
+
+    GKI_run(0);
+}
+
+/******************************************************************************
+**
+** Function         bte_main_disable
+**
+** Description      BTE MAIN API - Destroys all the BTE tasks. Should be called
+**                  part of the Bluetooth stack disable sequence
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_disable(void)
+{
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    preload_stop_wait_timer();
+    bte_hci_disable();
+    GKI_destroy_task(BTU_TASK);
+    GKI_freeze();
+}
+
+/******************************************************************************
+**
+** Function         bte_hci_enable
+**
+** Description      Enable HCI & Vendor modules
+**
+** Returns          None
+**
+******************************************************************************/
+static void bte_hci_enable(void)
+{
+    APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+    preload_start_wait_timer();
+
     if (bt_hc_if)
     {
-        int result = bt_hc_if->init(&hc_callbacks, local_addr);
+        int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
         APPL_TRACE_EVENT1("libbt-hci init returns %d", result);
 
         assert(result == BT_HC_STATUS_SUCCESS);
@@ -200,25 +272,18 @@ void bte_main_enable(uint8_t *local_addr)
 
         bt_hc_if->preload(NULL);
     }
-
-    GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
-                    (UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
-                    sizeof(bte_btu_stack));
-
-    GKI_run(0);
 }
 
 /******************************************************************************
 **
-** Function         bte_main_disable
+** Function         bte_hci_disable
 **
-** Description      BTE MAIN API - Destroys all the BTE tasks. Should be called
-**                  part of the Bluetooth stack disable sequence
+** Description      Disable HCI & Vendor modules
 **
 ** Returns          None
 **
 ******************************************************************************/
-void bte_main_disable(void)
+static void bte_hci_disable(void)
 {
     APPL_TRACE_DEBUG1("%s", __FUNCTION__);
 
@@ -226,11 +291,97 @@ void bte_main_disable(void)
     {
         bt_hc_if->cleanup();
         bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF);
+        if (hci_logging_enabled == TRUE)
+            bt_hc_if->logging(BT_HC_LOGGING_OFF, hci_logfile);
     }
+}
 
-    GKI_destroy_task(BTU_TASK);
+/*******************************************************************************
+**
+** Function        preload_wait_timeout
+**
+** Description     Timeout thread of preload watchdog timer
+**
+** Returns         None
+**
+*******************************************************************************/
+static void preload_wait_timeout(union sigval arg)
+{
+    APPL_TRACE_ERROR2("...preload_wait_timeout (retried:%d/max-retry:%d)...",
+                        preload_retry_cb.retry_counts,
+                        PRELOAD_MAX_RETRY_ATTEMPTS);
 
-    GKI_freeze();
+    if (preload_retry_cb.retry_counts++ < PRELOAD_MAX_RETRY_ATTEMPTS)
+    {
+        bte_hci_disable();
+        GKI_delay(100);
+        bte_hci_enable();
+    }
+    else
+    {
+        /* Notify BTIF_TASK that the init procedure had failed*/
+        GKI_send_event(BTIF_TASK, BT_EVT_HARDWARE_INIT_FAIL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function        preload_start_wait_timer
+**
+** Description     Launch startup watchdog timer
+**
+** Returns         None
+**
+*******************************************************************************/
+static void preload_start_wait_timer(void)
+{
+    int status;
+    struct itimerspec ts;
+    struct sigevent se;
+    UINT32 timeout_ms = PRELOAD_START_TIMEOUT_MS;
+
+    if (preload_retry_cb.timer_created == FALSE)
+    {
+        se.sigev_notify = SIGEV_THREAD;
+        se.sigev_value.sival_ptr = &preload_retry_cb.timer_id;
+        se.sigev_notify_function = preload_wait_timeout;
+        se.sigev_notify_attributes = NULL;
+
+        status = timer_create(CLOCK_MONOTONIC, &se, &preload_retry_cb.timer_id);
+
+        if (status == 0)
+            preload_retry_cb.timer_created = TRUE;
+    }
+
+    if (preload_retry_cb.timer_created == TRUE)
+    {
+        ts.it_value.tv_sec = timeout_ms/1000;
+        ts.it_value.tv_nsec = 1000000*(timeout_ms%1000);
+        ts.it_interval.tv_sec = 0;
+        ts.it_interval.tv_nsec = 0;
+
+        status = timer_settime(preload_retry_cb.timer_id, 0, &ts, 0);
+        if (status == -1)
+            APPL_TRACE_ERROR0("Failed to fire preload watchdog timer");
+    }
+}
+
+/*******************************************************************************
+**
+** Function        preload_stop_wait_timer
+**
+** Description     Stop preload watchdog timer
+**
+** Returns         None
+**
+*******************************************************************************/
+static void preload_stop_wait_timer(void)
+{
+    if (preload_retry_cb.timer_created == TRUE)
+    {
+        timer_delete(preload_retry_cb.timer_id);
+        preload_retry_cb.timer_created = FALSE;
+    }
 }
 
 /******************************************************************************
@@ -380,9 +531,14 @@ static void preload_cb(TRANSAC transac, bt_hc_preload_result_t result)
 {
     APPL_TRACE_EVENT1("HC preload_cb %d [0:SUCCESS 1:FAIL]", result);
 
-    /* notify BTU task that libbt-hci is ready */
-    /* even if PRELOAD process failed */
-    GKI_send_event(BTU_TASK, TASK_MBOX_0_EVT_MASK);
+
+    if (result == BT_HC_PRELOAD_SUCCESS)
+    {
+        preload_stop_wait_timer();
+
+        /* notify BTU task that libbt-hci is ready */
+        GKI_send_event(BTU_TASK, BT_EVT_PRELOAD_CMPL);
+    }
 }
 
 /******************************************************************************
index 5147518..e18b4ed 100644 (file)
@@ -169,11 +169,35 @@ BTU_API UINT32 btu_task (UINT32 param)
 
 #if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE)
     /* wait an event that HCISU is ready */
-    event = GKI_wait (0xFFFF, 0);
-    if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
-        /* indicates BT ENABLE abort */
-        return (0);
+    BT_TRACE_0(TRACE_LAYER_BTU, TRACE_TYPE_API,
+                "btu_task pending for preload complete event");
+
+    for (;;)
+    {
+        event = GKI_wait (0xFFFF, 0);
+        if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
+        {
+            /* indicates BT ENABLE abort */
+            BT_TRACE_0(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
+                        "btu_task start abort!");
+            return (0);
+        }
+        else if (event & BT_EVT_PRELOAD_CMPL)
+        {
+            break;
+        }
+        else
+        {
+            BT_TRACE_1(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
+                "btu_task ignore evt %04x while pending for preload complete",
+                event);
+        }
+    }
+
+    BT_TRACE_0(TRACE_LAYER_BTU, TRACE_TYPE_API,
+                "btu_task received preload complete event");
 #endif
+
     /* Initialize the mandatory core stack control blocks
        (BTU, BTM, L2CAP, and SDP)
      */
index 020a281..33fb884 100644 (file)
 #define BT_EVT_CONTEXT_SWITCH_EVT  (0x0001 | BT_EVT_BTIF)
 
 #define BT_EVT_TRIGGER_STACK_INIT   EVENT_MASK(APPL_EVT_0)
+#define BT_EVT_HARDWARE_INIT_FAIL   EVENT_MASK(APPL_EVT_1)
 
+#define BT_EVT_PRELOAD_CMPL         EVENT_MASK(APPL_EVT_6)
 
 /* Define the header of each buffer used in the Bluetooth stack.
 */