zoukankan      html  css  js  c++  java
  • 蓝牙重启case之:hardware error

    蓝牙的通信分为host和controller,host端发送数据和命令到controller,controller 上传event以及数据到host端,这要求上下两端的通信要求状态一致性。

    当发生状态不一致的时候,Bluetooth进程应该有预案去重新初始化蓝牙。

    这篇文章就介绍一种case,当控制端出现hardware error 的时候,host是如何处理此case的,结果就是host会重新启动蓝牙进程,现在我们简单分析其流程。

    在之前的 hci 消息的处理线程中,我们已经知道,底层上传的数据都会塞到btu_hci_msg_queue 这个队列,我们看下协议栈是如何来处理这个队列中的数据:

      fixed_queue_register_dequeue(btu_hci_msg_queue,
          thread_get_reactor(bt_workqueue_thread),
          btu_hci_msg_ready,//使用该函数处理
          NULL);
    void btu_hci_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
        BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);//数据出列
        btu_hci_msg_process(p_msg);//处理数据
    }

    我们可以看出btu_hci_msg_process 是用来处理数据的,这里我们就看看其是如何处理hci event的:

    static void btu_hci_msg_process(BT_HDR *p_msg) {
        /* Determine the input message type. */
        switch (p_msg->event & BT_EVT_MASK)
        {
    ...
            case BT_EVT_TO_BTU_HCI_ACL:
                /* All Acl Data goes to L2CAP */
                l2c_rcv_acl_data (p_msg);
                breakcase BT_EVT_TO_BTU_HCI_EVT:
                btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
                GKI_freebuf(p_msg);
    ...
        }
    
    }

    处理函数是btu_hcif_process_event 

    void btu_hcif_process_event (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_msg)
    {
        UINT8   *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
        UINT8   hci_evt_code, hci_evt_len;
        STREAM_TO_UINT8  (hci_evt_code, p);
        STREAM_TO_UINT8  (hci_evt_len, p);
    
        switch (hci_evt_code)
        {
            case HCI_INQUIRY_COMP_EVT:
                btu_hcif_inquiry_comp_evt (p);
                break;
            case HCI_INQUIRY_RESULT_EVT:
                btu_hcif_inquiry_result_evt (p);
                break;
            case HCI_INQUIRY_RSSI_RESULT_EVT:
                btu_hcif_inquiry_rssi_result_evt (p);
    ...
             case HCI_HARDWARE_ERROR_EVT:
                btu_hcif_hardware_error_evt (p);//处理hardware 错误的函数
                break;    
    ...
    static void btu_hcif_hardware_error_evt (UINT8 *p)
    {
        /* If anyone wants device status notifications, give him one. */
        btm_report_device_status (BTM_DEV_STATUS_DOWN);//向上层汇报状态
        /* Reset the controller */
        if (BTM_IsDeviceUp())
            BTM_DeviceReset (NULL);
    }

    btm_report_device_status (BTM_DEV_STATUS_DOWN); 这个函数里面是调用btm的callback,

    /*******************************************************************************
    **
    ** Function         btm_report_device_status
    **
    ** Description      This function is called when there is a change in the device
    **                  status. This function will report the new device status to
    **                  the application
    **
    ** Returns          void
    **
    *******************************************************************************/
    void btm_report_device_status (tBTM_DEV_STATUS status)
    {
        tBTM_DEV_STATUS_CB *p_cb = btm_cb.devcb.p_dev_status_cb;
    
        /* Call the call back to pass the device status to application */
        if (p_cb)
            (*p_cb)(status);
    }

    看注释知道是当有设备状态发生改变的时候,会将这个消息发送给应用层。

    那可以想象,这些状态通过回调函数一层一层往上调用,最终会通知到应用层,那么首先看看btm_cb.devcb.p_dev_status_cb 是在哪里注册。这里搜索了一下代码发现是在bta_sys_init里面:

    /*******************************************************************************
    **
    ** Function         bta_sys_init
    **
    ** Description      BTA initialization; called from task initialization.
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    void bta_sys_init(void)
    {
        memset(&bta_sys_cb, 0, sizeof(tBTA_SYS_CB));
    ...

      /* register BTA SYS message handler */
      bta_sys_register( BTA_ID_SYS, &bta_sys_hw_reg);

    /* register for BTM notifications */
        BTM_RegisterForDeviceStatusNotif ((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback ); 

    那我们知道btm_cb.devcb.p_dev_status_cb = bta_sys_hw_btm_cback

    并且我们知道BTA_ID_SYS 对应的处理 handler 是bta_sys_hw_reg

    static const tBTA_SYS_REG bta_sys_hw_reg =
    {
        bta_sys_sm_execute,
        NULL
    };
    /*******************************************************************************
    **
    ** Function         bta_sys_hw_btm_cback
    **
    ** Description     This function is registered by BTA SYS to BTM in order to get status notifications
    **
    **
    ** Returns
    **
    *******************************************************************************/
    void bta_sys_hw_btm_cback( tBTM_DEV_STATUS status )
    {
        tBTA_SYS_HW_MSG *sys_event;
        /* send a message to BTA SYS */
        if ((sys_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL)
        {
            if (status == BTM_DEV_STATUS_UP)
                sys_event->hdr.event = BTA_SYS_EVT_STACK_ENABLED_EVT;
            else if (status == BTM_DEV_STATUS_DOWN)
                sys_event->hdr.event = BTA_SYS_ERROR_EVT;//向bta发送此消息
            else
            {
                /* BTM_DEV_STATUS_CMD_TOUT is ignored for now. */
                GKI_freebuf (sys_event);
                sys_event = NULL;
            }
            if (sys_event)
            {
                bta_sys_sendmsg(sys_event);//向bta 发送消息
            }
        }
    }

     可以看出这个回调函数只是向BTA 模块发送event = BTA_SYS_ERROR_EVT

    我们接着看其处理流程:

    /* events sent to SYS HW manager - must be kept synchronized with tables in bta_sys_main.c  与该文件保持一致*/ 
    enum
    {
        /* device manager local device API events */
        BTA_SYS_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SYS),//sys id = 0
        BTA_SYS_EVT_ENABLED_EVT,
        BTA_SYS_EVT_STACK_ENABLED_EVT,
        BTA_SYS_API_DISABLE_EVT,
        BTA_SYS_EVT_DISABLED_EVT,
        BTA_SYS_ERROR_EVT,
    
        BTA_SYS_MAX_EVT
    };

     现在简单看下 bta_sys_sendmsg 的数据走向:

      fixed_queue_register_dequeue(btu_bta_msg_queue,
          thread_get_reactor(bt_workqueue_thread),
          btu_bta_msg_ready, //当队列有数据,使用这个函数处理
          NULL);
    void btu_bta_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
        BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);//数据出列
        bta_sys_event(p_msg);//处理数据
    }

     从上面我们可以知道,处理数据的函数就是bta_sys_event,但是这个函数并不是最终的每个msg的处理函数,它只是一个中介,它会将各个消息按照类型分发到不同的具体的处理函数:

    void bta_sys_event(BT_HDR *p_msg)
    {
        UINT8       id;
        BOOLEAN     freebuf = TRUE;
        /* get subsystem id from event */
        id = (UINT8) (p_msg->event >> 8);
    
        /* verify id and call subsystem event handler */
        if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
        {
            freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
        }
    }

     从上面的代码可以看出其实际调用(*bta_sys_cb.reg[id]->evt_hdlr)(p_msg) 来处理消息的,其寻找处理函数是根据 id作为index 来搜索的,那我们很容易想到,这个函数肯定是之前已经注册好的。

    不同的event 会由不同的handler来处理。

     在bta_sys_init中,我们已经知道BTA_ID_SYS 对应的处理 handler 是bta_sys_hw_reg,我们看看其具体的处理:

    虽然是经过状态机来轮转处理的,但是最终执行的action是:BTA_SYS_HW_ERROR,对应的实现:

    void bta_sys_hw_error(tBTA_SYS_HW_MSG *p_sys_hw_msg)
    {
    ...
                    case BTA_SYS_HW_BLUETOOTH:
                       /* Send BTA_SYS_HW_ERROR_EVT to DM */
                       if (bta_sys_cb.sys_hw_cback[module_index] != NULL)
                           bta_sys_cb.sys_hw_cback[module_index] (BTA_SYS_HW_ERROR_EVT);
    ...
    }

    在bta_dm_enable函数中已经注册了sys_hw_cback:

        /* first, register our callback to SYS HW manager */
        bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback );
    /*******************************************************************************
    **
    ** Function         bta_dm_sys_hw_cback
    **
    ** Description     callback register to SYS to get HW status updates
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status )
    {
        DEV_CLASS   dev_class;
        tBTA_DM_SEC_CBACK           *temp_cback;
    
        /* On H/W error evt, report to the registered DM application callback */
        if (status == BTA_SYS_HW_ERROR_EVT) {
              if( bta_dm_cb.p_sec_cback != NULL )
                    bta_dm_cb.p_sec_cback(BTA_DM_HW_ERROR_EVT, NULL);
              return;
        }
    ...
    }

    这里发现,又调用了bta_dm_cb.p_sec_cback(BTA_DM_HW_ERROR_EVT, NULL);

    这个函数的回调其实是调用到了btif线程(JNI线程)

    void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param) {
      BTIF_TRACE_DEBUG("btif_task: received trigger stack init event");
    #if (BLE_INCLUDED == TRUE)
      btif_dm_load_ble_local_keys();
    #endif
      BTA_EnableBluetooth(bte_dm_evt);//bta_dm_cb.p_sec_cback= bte_dm_evt
    }

    看看这个bte_dm_evt:

    /*******************************************************************************
    **
    ** Function         bte_dm_evt
    **
    ** Description      Switches context from BTE to BTIF for all DM events
    **
    ** Returns          void
    **
    *******************************************************************************/
    
    void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data)
    {
        /* switch context to btif task context (copy full union size for convenience) */
        bt_status_t status = btif_transfer_context(btif_dm_upstreams_evt, (uint16_t)event,
                                    (void*)p_data, sizeof(tBTA_DM_SEC), btif_dm_data_copy);//将函数btif_dm_upstreams_evt transfer 到btif线程执行,也即是向btif线程发送消息
        /* catch any failed context transfers */
        ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
    }

     那实际处理的函数就是btif_dm_upstreams_evt ,其参数是BTA_DM_HW_ERROR_EVT

    static void btif_dm_upstreams_evt(UINT16 event, char* p_param){
    ...
     case BTA_DM_HW_ERROR_EVT:
                BTIF_TRACE_ERROR("Received H/W Error. ");
                /* Flush storage data */
                btif_config_flush();
                usleep(100000); /* 100milliseconds */
                /* Killing the process to force a restart as part of fault tolerance */
                kill(getpid(), SIGKILL);
                break;
    ...
    }

    这个函数btif_dm_upstreams_evt 就是上报event 事件到 btif层面。我们发现最终的处理是kill掉当前的进程,也就是重启蓝牙进程。

  • 相关阅读:
    iscroll.js
    HTML 第九章总结
    HTML第八章总结
    HTML第七章总结
    HTML第六章总结
    HTML第五章总结
    HTML第四章总结
    HTML第三章总结
    HTML第二章总结
    HTML第一章总结
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9214372.html
Copyright © 2011-2022 走看看