• 蓝牙Remove Bond的流程分析


    此篇文章简单分析一下蓝牙解除配对在协议栈中的工作流程。分析的协议栈版本是Android8.0

    协议栈的接口都定义在bluetooth.cc这个文件中:

    static int remove_bond(const bt_bdaddr_t* bd_addr) {
      if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr))
        return BT_STATUS_SUCCESS;
      /* sanity check */
      if (interface_ready() == false) return BT_STATUS_NOT_READY;
      return btif_dm_remove_bond(bd_addr);
    }

    这里需要注意一下bt_bdaddr_t 是一个结构体,内部一个元素是数组。

     /** Bluetooth Address */
     typedef struct {
        uint8_t address[6];
     } __attribute__((packed))bt_bdaddr_t;

    进入btif_dm_remove_bond:

    bt_status_t btif_dm_remove_bond(const bt_bdaddr_t* bd_addr) {
      bdstr_t bdstr;
      btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_REMOVE_BOND,
                            (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
      return BT_STATUS_SUCCESS;
    }

    这个函数btif_transfer_context 是将remove bond这件事情交给bt_jni_workqueue_thread来处理。在该线程中执行的函数就是btif_dm_generic_evt

    static void btif_dm_generic_evt(uint16_t event, char* p_param) {
      BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
      switch (event) {
        case BTIF_DM_CB_REMOVE_BOND: {
          btif_dm_cb_remove_bond((bt_bdaddr_t*)p_param);
        } break;
      }
    }

    执行的函数:btif_dm_cb_remove_bond 

    void btif_dm_cb_remove_bond(bt_bdaddr_t* bd_addr) {
        BTA_DmRemoveDevice((uint8_t*)bd_addr->address);
    }

    函数执行到了BTA层面。

    tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr) {
      tBTA_DM_API_REMOVE_DEVICE* p_msg =
       (tBTA_DM_API_REMOVE_DEVICE*)osi_calloc(sizeof(tBTA_DM_API_REMOVE_DEVICE));
      p_msg->hdr.event = BTA_DM_API_REMOVE_DEVICE_EVT;
      bdcpy(p_msg->bd_addr, bd_addr);
      bta_sys_sendmsg(p_msg);
      return BTA_SUCCESS;
    }

    这边是发送了一个BTA_DM_API_REMOVE_DEVICE_EVT到另一个线程:bt_workqueue_thread,这个线程是专门处理bt里面的队列的,当队列里面有数据都会在这个线程里面处理。

    通过bta_sys_sendmsg发送的信号都会经过bta_sys_event来处理,bta_sys_event会根据相应的事件路由到相应的处理函数。这里处理这个事件的函数是:

    /*******************************************************************************
     *
     * Function         bta_dm_remove_device
     *
     * Description      Removes device, disconnects ACL link if required.
     ***
     ******************************************************************************/
    void bta_dm_remove_device(tBTA_DM_MSG* p_data) {
      tBTA_DM_API_REMOVE_DEVICE* p_dev = &p_data->remove_dev;//获取消息
      bool continue_delete_other_dev = false;/* If ACL exists for the device in the remove_bond message*/
      bool continue_delete_dev = false;
      uint8_t other_transport = BT_TRANSPORT_INVALID;
    /*首先判断该address 是否存有link*/
      if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) ||
          BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR)) {
        APPL_TRACE_DEBUG("%s: ACL Up count  %d", __func__,
                         bta_dm_cb.device_list.count);
        continue_delete_dev = false;
        /* Take the link down first, and mark the device for removal when
         * disconnected */
        for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
          if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
                     p_dev->bd_addr)) {
            uint8_t transport = BT_TRANSPORT_BR_EDR;
            transport = bta_dm_cb.device_list.peer_device[i].transport;
            bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;//设置标志位,在acl link状态改变的函数中会去删除link key
            btm_remove_acl(p_dev->bd_addr, transport);//已经存在link,那么要先删除这条linkbreak;
          }
        }
      } else {
        continue_delete_dev = true;
      }
    ...
      /* Delete the device mentioned in the msg */
      if (continue_delete_dev) bta_dm_process_remove_device(p_dev->bd_addr);//解配的设备没有处于连接状态则执行
    }

    从上面的代码可以看出,核心的地方就两处:

    1. bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING; 标记该设备是要解除配对的,后续会删除其link key
    2. btm_remove_acl 做实际的断开连接的操作。

     现在简单看看btm_remove_acl 的实现:

    tBTM_STATUS btm_remove_acl(BD_ADDR bd_addr, tBT_TRANSPORT transport) {
      uint16_t hci_handle = BTM_GetHCIConnHandle(bd_addr, transport);
      tBTM_STATUS status = BTM_SUCCESS;
    ...
      {
        if (hci_handle != 0xFFFF && p_dev_rec &&
            p_dev_rec->sec_state != BTM_SEC_STATE_DISCONNECTING) {
          btsnd_hcic_disconnect(hci_handle, HCI_ERR_PEER_USER);
        } else
          status = BTM_UNKNOWN_ADDR;
      }
      return status;
    }

    先搜索btm_cb.acl_db 找到该地址对应的ACL link 的控制体,获取该link 的handle,该handle用于标志是哪一条link,然后调用btsnd_hcic_disconnect(hci_handle, HCI_ERR_PEER_USER); 向controller发送断开的命令。

    到这里,在bt_workqueue_thread 线程中发送断开link 的消息是结束了,controller收到信息处理之后,会有断开完成事件上来,这个时候处理该事件的线程依然是bt_workqueue_thread,我们看看具体的处理过程:处理底层的事件的接口实现在btu_hcif.cc中:

    /*******************************************************************************
     *
     * Function         btu_hcif_disconnection_comp_evt
     *
     * Description      Process event HCI_DISCONNECTION_COMP_EVT
     *
     * Returns          void
     *
     ******************************************************************************/
    static void btu_hcif_disconnection_comp_evt(uint8_t* p) {
      uint16_t handle;
      uint8_t reason;
      ++p;
      STREAM_TO_UINT16(handle, p);
      STREAM_TO_UINT8(reason, p);
      handle = HCID_GET_HANDLE(handle);
      l2c_link_hci_disc_comp(handle, reason);
      /* Notify security manager */
      btm_sec_disconnected(handle, reason);
    }

    从函数的注释我们也能看出其是处理HCI_DISCONNECTION_COMP_EVT 这个事件的。从代码流程中,我们能看到代码主要做了两件事:

    1. l2c_link_hci_disc_comp
    2. btm_sec_disconnected,这个函数是用来通知security manager的。

    下面依次看看这两个函数的实现:

    bool l2c_link_hci_disc_comp(uint16_t handle, uint8_t reason) {
      L2CAP_TRACE_EVENT("entry l2c_link_hci_disc_comp libs_liu");
      tL2C_LCB* p_lcb;
      tL2C_CCB* p_ccb;
      bool status = true;
      bool lcb_is_free = true;
      tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
      /* See if we have a link control block for the connection */
      p_lcb = l2cu_find_lcb_by_handle(handle);
    ...
     {
        /* Just in case app decides to try again in the callback context */
        p_lcb->link_state = LST_DISCONNECTING;
    
        /* Check for BLE and handle that differently */
        if (p_lcb->transport == BT_TRANSPORT_LE)
          btm_ble_update_link_topology_mask(p_lcb->link_role, false);
        /* Link is disconnected. For all channels, send the event through */
        /* their FSMs. The CCBs should remove themselves from the LCB     */
        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;) {
          tL2C_CCB* pn = p_ccb->p_next_ccb;
          /* Keep connect pending control block (if exists)
           * Possible Race condition when a reconnect occurs
           * on the channel during a disconnect of link. This
           * ccb will be automatically retried after link disconnect
           * arrives
           */
          if (p_ccb != p_lcb->p_pending_ccb) {
            l2c_csm_execute(p_ccb, L2CEVT_LP_DISCONNECT_IND, &reason);
          }
          p_ccb = pn;
        }
        p_lcb->p_pending_ccb = NULL;
    
        /* Release the LCB */
        if (lcb_is_free){ 
        l2cu_release_lcb(p_lcb);}
      }
    ...
      return status;
    }

    上面函数核心的地方 是释放link 相关的结构体l2cu_release_lcb,这个函数主要就是释放一些定时器,内存以及channel结构释放,另外还做一些通知的事情:

          /* If anyone cares, tell him database changed */
          if (btm_cb.p_bl_changed_cb) {
            evt_data.event = BTM_BL_DISCN_EVT;
            evt_data.discn.p_bda = bda;
            evt_data.discn.handle = p->hci_handle;
            evt_data.discn.transport = p->transport;
            (*btm_cb.p_bl_changed_cb)(&evt_data);
          }

    这里需要思考一下,这个btm_cb.p_bl_changed_cb 回调函数是哪里注册。这个函数其实在bta_dm_sys_hw_cback 函数中注册的:

    BTM_RegBusyLevelNotif(bta_dm_bl_change_cback, NULL,
                              BTM_BL_UPDATE_MASK | BTM_BL_ROLE_CHG_MASK);
    //那其实是
    btm_cb.p_bl_changed_cb  = bta_dm_bl_change_cback

    那我们现在看看这个busy level change的实现:从上面也可以看出是把BTM_BL_DISCN_EVT 传入到 bta_dm_bl_change_cback 来执行:

    static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data) {
      tBTA_DM_ACL_CHANGE* p_msg =
          (tBTA_DM_ACL_CHANGE*)osi_malloc(sizeof(tBTA_DM_ACL_CHANGE));
    
      p_msg->event = p_data->event;
      p_msg->is_new = false;
    
      switch (p_msg->event) {
        case BTM_BL_CONN_EVT:
          p_msg->is_new = true;
          bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
          p_msg->transport = p_data->conn.transport;
          p_msg->handle = p_data->conn.handle;
          break;
        case BTM_BL_DISCN_EVT:
          bdcpy(p_msg->bd_addr, p_data->discn.p_bda);
          p_msg->transport = p_data->discn.transport;
          p_msg->handle = p_data->discn.handle;
          break;
        case BTM_BL_UPDATE_EVT:
          p_msg->busy_level = p_data->update.busy_level;
          p_msg->busy_level_flags = p_data->update.busy_level_flags;
          break;
        case BTM_BL_ROLE_CHG_EVT:
          p_msg->new_role = p_data->role_chg.new_role;
          p_msg->hci_status = p_data->role_chg.hci_status;
          bdcpy(p_msg->bd_addr, p_data->role_chg.p_bda);
          break;
        case BTM_BL_COLLISION_EVT:
          bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
          break;
      }
    
      p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
      bta_sys_sendmsg(p_msg);
    }

    从这个函数的实现来看,他是可以处理很多的event的。然后统一发送给bt_workqueue_thread中的另外一个队列中,看看具体的处理流程:

    其实现的函数是在bta_dm_act.cc中,

    void bta_dm_acl_change(tBTA_DM_MSG* p_data) {
      uint8_t i;
      uint8_t* p;
      tBTA_DM_SEC conn;
      bool is_new = p_data->acl_change.is_new;
      BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr;
      bool need_policy_change = false;
      bool issue_unpair_cb = false;
    
      tBTA_DM_PEER_DEVICE* p_dev;
      memset(&conn, 0, sizeof(tBTA_DM_SEC));
    ...
        for (i = 0; i < bta_dm_cb.device_list.count; i++) {
          if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda) ||
              bta_dm_cb.device_list.peer_device[i].transport !=
                  p_data->acl_change.transport)
            continue;
        /*找到之后*/
          if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING) {//之前已经标记过
            if (BTM_SecDeleteDevice(bta_dm_cb.device_list.peer_device[i].peer_bdaddr))
          BTA_GATTC_Refresh(p_bda);//remove all gatt information issue_unpair_cb
    = true; } conn.link_down.is_removed = bta_dm_cb.device_list.peer_device[i].remove_dev_pending; break; } ... conn.link_down.link_type = p_data->acl_change.transport; ... bdcpy(conn.link_down.bd_addr, p_bda); conn.link_down.status = (uint8_t)btm_get_acl_disc_reason_code(); if (bta_dm_cb.p_sec_cback) { //执行这里的函数 bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn); if (issue_unpair_cb) bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn); } bta_dm_adjust_roles(true); }

    上面的回调函数主要执行如下:

    1. 从bta_dm_cb 查找到该地址的结构。
    2. 找到之后判断bta_dm_cb.device_list.peer_device[i].conn_state的状态,如果是BTA_DM_UNPAIRING,则开始删除link key:BTM_SecDeleteDevice
    3. 回调bta_dm_cb.p_sec_cback :BTA_DM_LINK_DOWN_EVT以及BTA_DM_DEV_UNPAIRED_EVT

    前两个容易理解,看看第三点:

    第三点的回调函数在enable 的时候就已经注册好了:bta_dm_cb.p_sec_cback = bte_dm_evt ,我们进一步看看:

    void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
      bt_status_t status = btif_transfer_context(
          btif_dm_upstreams_evt, (uint16_t)event, (char*)p_data,
          sizeof(tBTA_DM_SEC), btif_dm_data_copy);
    }

    发现其实 他实质执行的函数是btif_dm_upstreams_evt ,这个函数处理的event非常的多,这里就列出相关的代码:

    static void btif_dm_upstreams_evt(uint16_t event, char* p_param) {
      tBTA_DM_SEC* p_data = (tBTA_DM_SEC*)p_param;
      tBTA_SERVICE_MASK service_mask;
      uint32_t i;
      bt_bdaddr_t bd_addr;
    
      switch (event) {
    ...
        case BTA_DM_DEV_UNPAIRED_EVT:
          bdcpy(bd_addr.address, p_data->link_down.bd_addr);
          btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
    
    /*special handling for HID devices */
    #if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == true))
          btif_hh_remove_device(bd_addr);
    #endif
    #if (defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE))
          btif_hd_remove_device(bd_addr);
    #endif
          btif_storage_remove_bonded_device(&bd_addr);
          bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
          break;
    
        case BTA_DM_LINK_DOWN_EVT:
          bdcpy(bd_addr.address, p_data->link_down.bd_addr);
          btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
          btif_av_move_idle(bd_addr);
          BTIF_TRACE_DEBUG(
              "BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
          HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
                    &bd_addr, BT_ACL_STATE_DISCONNECTED);
          break;
      }
    
      btif_dm_data_free(event, p_data);
    }

    处理的两个事件是BTA_DM_LINK_DOWN_EVT和BTA_DM_DEV_UNPAIRED_EVT 

    其中BTA_DM_LINK_DOWN_EVT 主要是执行acl_state_changed_cb,向上层传导BT_ACL_STATE_DISCONNECTED

    这里主要看一下BTA_DM_DEV_UNPAIRED_EVT  的处理:

    1. btif_hh_remove_device   
    2. btif_storage_remove_bonded_device  删除config中的key 的信息。

    下面看看btif_hh_remove_device

    void btif_hh_remove_device(bt_bdaddr_t bd_addr) {
      int i;
      btif_hh_device_t* p_dev;
      btif_hh_added_device_t* p_added_dev;for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
        p_added_dev = &btif_hh_cb.added_devices[i];
        if (memcmp(&(p_added_dev->bd_addr), &bd_addr, 6) == 0) {
          BTA_HhRemoveDev(p_added_dev->dev_handle);//remove dev
          btif_storage_remove_hid_info(&(p_added_dev->bd_addr));//删除config中的hid信息
          memset(&(p_added_dev->bd_addr), 0, 6);
          p_added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
          break;
        }
      }
    ... p_dev
    = btif_hh_find_dev_by_bda(&bd_addr);/* need to notify up-layer device is disconnected to avoid state out of sync * with up-layer */ HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),//向上层汇报状态 BTHH_CONN_STATE_DISCONNECTED); p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN; p_dev->dev_handle = BTA_HH_INVALID_HANDLE; p_dev->ready_for_data = false; ...if (p_dev->fd >= 0) { bta_hh_co_destroy(p_dev->fd);//销毁相关的结构 p_dev->fd = -1; } }

    上面代码很简单,主要做清理工作:下面具体看看BTA_HhRemoveDev

    void BTA_HhRemoveDev(uint8_t dev_handle) {
      tBTA_HH_MAINT_DEV* p_buf =
          (tBTA_HH_MAINT_DEV*)osi_calloc(sizeof(tBTA_HH_MAINT_DEV));
      p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
      p_buf->sub_event = BTA_HH_RMV_DEV_EVT;
      p_buf->hdr.layer_specific = (uint16_t)dev_handle;
      bta_sys_sendmsg(p_buf);
    }

    发送了一个BTA_HH_API_MAINT_DEV_EVT的事件到达BTU task,

    void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
      tBTA_HH_MAINT_DEV* p_dev_info = &p_data->api_maintdev;
      tBTA_HH_DEV_INFO dev_info;
      uint8_t dev_handle;
    
      dev_info.status = BTA_HH_ERR;
      dev_info.handle = BTA_HH_INVALID_HANDLE;
    
      switch (p_dev_info->sub_event) {
    ...
        case BTA_HH_RMV_DEV_EVT: /* remove device */
          dev_info.handle = (uint8_t)p_dev_info->hdr.layer_specific;
          bdcpy(dev_info.bda, p_cb->addr);
    
          if (p_cb->is_le_device) {//le 设备
            bta_hh_le_remove_dev_bg_conn(p_cb);//移除background 里面的list,让其不要回连
            bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
            bta_hh_clean_up_kdev(p_cb);
          } else//bredr 设备
          {
            if (HID_HostRemoveDev(dev_info.handle) == HID_SUCCESS) {
              dev_info.status = BTA_HH_OK;
              /* remove from known device list in BTA */
              bta_hh_clean_up_kdev(p_cb);
            }
          }
          break;
      }
      (*bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH*)&dev_info);
    }

    这里先讲一下bta_hh_cb.p_cback,也是在 BTA_HhEnable(BTUI_HH_SECURITY, bte_hh_evt); 时候注册的,那么也就是说bta_hh_cb.p_cback = bte_hh_evt

    void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {
      bt_status_t status;
      int param_len = 0;
    
      if (BTA_HH_ENABLE_EVT == event)
        param_len = sizeof(tBTA_HH_STATUS);
      else if (BTA_HH_OPEN_EVT == event)
        param_len = sizeof(tBTA_HH_CONN);
      else if (BTA_HH_DISABLE_EVT == event)
        param_len = sizeof(tBTA_HH_STATUS);
      else if (BTA_HH_CLOSE_EVT == event)
        param_len = sizeof(tBTA_HH_CBDATA);
      else if (BTA_HH_GET_DSCP_EVT == event)
        param_len = sizeof(tBTA_HH_DEV_DSCP_INFO);
      else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_RPT_EVT == event) ||
               (BTA_HH_GET_IDLE_EVT == event))
        param_len = sizeof(tBTA_HH_HSDATA);
      else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) ||
               (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event))
        param_len = sizeof(tBTA_HH_CBDATA);
      else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event))
        param_len = sizeof(tBTA_HH_DEV_INFO);
      else if (BTA_HH_API_ERR_EVT == event)
        param_len = 0;
      /* switch context to btif task context (copy full union size for convenience)
       */
      status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event,
                                     (char*)p_data, param_len, NULL);
    
      /* catch any failed context transfers */
      ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
    }

    其本质还是transfer 到btif 线程,执行btif_hh_upstreams_evt 函数,这边追踪了一下该事件的处理,只是打印了一些log:

        case BTA_HH_RMV_DEV_EVT:
          BTIF_TRACE_DEBUG("BTA_HH_RMV_DEV_EVT: status = %d, handle = %d",
                           p_data->dev_info.status, p_data->dev_info.handle);
          BTIF_TRACE_DEBUG("BTA_HH_RMV_DEV_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
                           p_data->dev_info.bda[0], p_data->dev_info.bda[1],
                           p_data->dev_info.bda[2], p_data->dev_info.bda[3],
                           p_data->dev_info.bda[4], p_data->dev_info.bda[5]);
          break;

    现在着重看一下bta_hh_le_remove_dev_bg_conn(p_cb) 的处理

    void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB* p_dev_cb) {
      if (p_dev_cb->in_bg_conn) {
        p_dev_cb->in_bg_conn = false;
        BTA_GATTC_CancelOpen(bta_hh_cb.gatt_if, p_dev_cb->addr, false);
      }
    
      /* deregister all notifications */
      bta_hh_le_deregister_input_notif(p_dev_cb);
    }
    void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
                              bool is_direct) {
      tBTA_GATTC_API_CANCEL_OPEN* p_buf = (tBTA_GATTC_API_CANCEL_OPEN*)osi_malloc(
          sizeof(tBTA_GATTC_API_CANCEL_OPEN));
    
      p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT;
      p_buf->client_if = client_if;
      p_buf->is_direct = is_direct;
      memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
    
      bta_sys_sendmsg(p_buf);
    }
    void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg) {
      uint16_t event = ((BT_HDR*)p_msg)->event;
      tBTA_GATTC_CLCB* p_clcb = NULL;
      tBTA_GATTC_RCB* p_clreg;
      tBTA_GATTC cb_data;
    
      if (p_msg->api_cancel_conn.is_direct) {
    ...
      } else {
        bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn);
      }
    }
    void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data) {
      tBTA_GATTC_RCB* p_clreg;
      tBTA_GATTC cb_data;
      cb_data.status = BTA_GATT_ERROR;
    
      /* remove the device from the bg connection mask */
      if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, false)) {
        if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, false)) {
          cb_data.status = BTA_GATT_OK;
        } else {
          APPL_TRACE_ERROR("bta_gattc_cancel_bk_conn failed");
        }
      }
      p_clreg = bta_gattc_cl_get_regcb(p_data->client_if);
    
      if (p_clreg && p_clreg->p_cback) {
        (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
      }
    }
    bool GATT_CancelConnect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct) {
      tGATT_REG* p_reg;
      tGATT_TCB* p_tcb;
      bool status = true;
      tGATT_IF temp_gatt_if;
      uint8_t start_idx, found_idx;
    
        if (!gatt_if) 
            ...
            else {
          status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
        }
      return status;
    }
    bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr) {
      tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
      bool status;
    
      if (p_tcb) gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
      status = gatt_update_auto_connect_dev(gatt_if, false, bd_addr);
      return status;
    }
    bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add, BD_ADDR bd_addr) {
    ...
      if (add) {
        ret = gatt_add_bg_dev_list(p_reg, bd_addr);
        if (ret && p_tcb != NULL) {
          /* if a connected device, update the link holding number */
          gatt_update_app_use_link_flag(gatt_if, p_tcb, true, true);
        }
      } else {
        ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr);
      }
      return ret;
    }
    bool gatt_remove_bg_dev_from_list(tGATT_REG* p_reg, BD_ADDR bd_addr) {
      tGATT_IF gatt_if = p_reg->gatt_if;
      tGATT_BG_CONN_DEV* p_dev = NULL;
      uint8_t i, j;
      bool ret = false;
    
      p_dev = gatt_find_bg_dev(bd_addr);
      if (p_dev == NULL) {
        return ret;
      }
    
      for (i = 0; i < GATT_MAX_APPS && (p_dev->gatt_if[i] > 0); i++) {
        if (p_dev->gatt_if[i] == gatt_if) {
          p_dev->gatt_if[i] = 0;
          /* move all element behind one forward */
          for (j = i + 1; j < GATT_MAX_APPS; j++)
            p_dev->gatt_if[j - 1] = p_dev->gatt_if[j];
    
          if (p_dev->gatt_if[0] == 0){//只有设备全部都断开了才会去做BTM_BleUpdateBgConnDev
            ret = BTM_BleUpdateBgConnDev(false, p_dev->remote_bda);
              }
          else
            ret = true;
    
          break;
        }
      }
    
      if (i != GATT_MAX_APPS && p_dev->gatt_if[0] == 0) {
        memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV));
      }
    
      return ret;
    }
    bool BTM_BleUpdateBgConnDev(bool add_remove, BD_ADDR remote_bda) {
      return btm_update_dev_to_white_list(add_remove, remote_bda);
    }
    bool btm_update_dev_to_white_list(bool to_add, BD_ADDR bd_addr) {
      tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
    
      if (to_add && p_cb->white_list_avail_size == 0) {
        BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
        return false;
      }
      if (to_add)
        background_connection_add((bt_bdaddr_t*)bd_addr);
      else{
        background_connection_remove((bt_bdaddr_t*)bd_addr);
      }
      btm_suspend_wl_activity(p_cb->wl_state);
      btm_enq_wl_dev_operation(to_add, bd_addr);
      btm_resume_wl_activity(p_cb->wl_state);
      return true;
    }

    删除 里面的值: background_connection_remove

    static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) {
      btm_ble_resume_bg_conn();
      if (wl_state & BTM_BLE_WL_ADV) {
        btm_ble_start_adv();
      }
    }
    bool btm_ble_resume_bg_conn(void) {
      tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
      if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) {
        return btm_ble_start_auto_conn(true);//如果background 里面还存在设备,那么就会回连
      }
      return false;
    }

    这个解除绑定的流程 暂时是分析到这里。

     

  • 相关阅读:
    supervisord golang 实现试用
    Prisma 2.0 ga
    fpm-cookery fpm 的包装工具
    rejoiner 基于grpc 以及其他protobuf 源生成统一graphql schema 框架
    topngx 一个不错的nginx 日志分析工具
    hasura graphql-engine v1.3 beta 发布
    openresty+graylog 记录proxy 请求以及响应日志
    基于纯真ip库以及openresty 模仿实现类似搜狐ip获取区域的服务
    zombie 试用
    tabnine 一个智能强大的代码插件
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9193864.html
Copyright © 2020-2023  润新知