为什么不回连——被disconnect的蓝牙HOGP Device

本文探讨了蓝牙HOGP Device在被master端removebond后无法回连的问题。分析了master在removebond操作中执行的步骤,解释了此过程导致设备无法重新连接的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么不回连——被removebond的蓝牙HOGP Device

为什么device那边产生了disconnect,master这边就允许其回连;而master这边将device removebond掉,device就不能回连了呢?

今天我们来看看,master在removebondt的过程中到底做了些什么。

        前面一篇博客说道,bluedroid中的蓝牙HOGP设备在因省电而disconnect后,master可以允许其快速回连,省去中间发杂的smp(安全管理)、gatt搜索和hid搜索的过程。当时提到过,master这边的host将对端HOGP device加入到了四个全局结构数组中,从而这个device才可以快速回连;而当master主动解除device的配对后,device就不可以回连了。这样看来,master端的host在removebond的过程中必然对这几个全局变量做了些什么。因此,我们就来看看host对这几个变量做了什么。
先是settings中解除配对时,bluedroid对上层的接口——remove_bond,它执行的流程大概是这样的:
==>btif_dm_remove_bond
==>btif_dm_cb_remove_bond
==>bta_dm_remove_device——这一步展开
/*******************************************************************************
**
** 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;
    int i;
    tBTA_DM_SEC sec_event;

#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
    /* need to remove all pending background connection before unpair */
    BTA_GATTC_CancelOpen(0, p_dev->bd_addr, FALSE);    //step 1,删除部分关于whitelist的记录
#endif

    if (BTM_IsAclConnectionUp(p_dev->bd_addr))
    {
        /* Take the link down first, and mark the device for removal when disconnected */
        btm_remove_acl( p_dev->bd_addr) ;    //step 2,发送hci cmd——disconnect

        for(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))
            break;
        }

        if(i < bta_dm_cb.device_list.count)
        {
            bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;    //step 3,删除所有记录(gatt cache、hid cache等)的标志
        }
    }
    else    /* Ok to remove the device in application layer */
    {
        BTM_SecDeleteDevice(p_dev->bd_addr);
#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
        /* remove all cached GATT information */
        BTA_GATTC_Refresh(p_dev->bd_addr);
#endif

        if( bta_dm_cb.p_sec_cback )
        {
            bdcpy(sec_event.link_down.bd_addr, p_dev->bd_addr);
            /* No connection, set status to success (acl disc code not valid) */
            sec_event.link_down.status = HCI_SUCCESS;
            bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event);
        }
    }
}
        这里分为三步,第一步是BTA_GATTC_CancelOpen(0, p_dev->bd_addr, FALSE),它打算将设备从“whitelist”中删除。之所以称为“打算”,一是因为它根本没成功,而是删除也是host端关于whitelist的记录,也就是前面提到的四个全局数组(其实是一个全局结构的四个成员数组)。下面把每个全局数组的delete流程过一遍(按照删除的顺序),其中有一个重点看下,因为它可能导致从“whitelist”中删除失败。
==>bta_gattc_process_api_open_cancel
    ==>bta_gattc_cancel_bk_conn
        ==>(1) bta_gattc_mark_bg_conn——bta_gattc_cb.bg_track中记录删除
        ==>(2) GATT_CancelConnect
            ==>gatt_remove_bg_dev_for_app
                ==>gatt_update_auto_connect_dev
                    ==>gatt_remove_bg_dev_from_list
                        ==>(1) btm_update_bg_conn_list——btm_cb.ble_ctr_cb.bg_dev_list中的记录被删除
                        ==>(2) btm_update_dev_to_white_list——STOP HERE!Let's see what happened.
/*******************************************************************************
**
** Function         btm_update_dev_to_white_list
**
** Description      This function adds a device into white list.
*******************************************************************************/
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, UINT8 attr)
{
    /* look up the sec device record, and find the address */
    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
    BOOLEAN     started = FALSE;
    UINT8       wl_state = p_cb->wl_state;

    BTM_TRACE_DEBUG3("to_add(%d), attr(%d), wl_state(%d)", to_add, attr, wl_state);
    if ((to_add && p_cb->num_empty_filter == 0) ||
        (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries))
    {
        BTM_TRACE_ERROR1("WL full or empty, unable to update to WL. num_entry available: %d",
                          p_cb->num_empty_filter);
        return started;
    }

    btm_suspend_wl_activity(wl_state);

    /* enq pending WL device operation */
    btm_enq_wl_dev_operation(to_add, bd_addr, attr);

    btm_resume_wl_activity(wl_state);

    return started;
}
本来呢,这一步是要将btm_cb.ble_ctr_cb.wl_op_q中的记录清理一下的,具体是在btm_enq_wl_dev_operation这里。但是呢,你会发现它怎么也走不到那儿去!why?
它被前面的判断卡住,直接返回了!让我们来看看这个判断中关于删除设备记录的情况:
!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries
这to_add还好说,为0表示删除设备记录;这后面这么长的两位。。。什么情况?这要回到蓝牙初始化时,host向controller发的一条hci cmd——HCI_LE_Read_White_List_Size的处理函数:
/*******************************************************************************
**
** Function         btm_read_white_list_size_complete
**
** Description      This function read the current white list size.
*******************************************************************************/
void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len)
{
    UINT8       status;

     BTM_TRACE_DEBUG0("btm_read_white_list_size_complete ");
    STREAM_TO_UINT8  (status, p);

    if (status == HCI_SUCCESS)
    {
        STREAM_TO_UINT8(btm_cb.ble_ctr_cb.max_filter_entries, p);
        btm_cb.ble_ctr_cb.num_empty_filter = btm_cb.ble_ctr_cb.max_filter_entries;//相同的值!
    }

    btm_get_ble_buffer_size();
}
看到了么,读取了controller的whitelist size之后,host将两个变量设置为相同的值!
那么,它们会不会变化呢?后者是个“max”,肯定是不会变的;而前者在以下情况会发生改变:
1)设备被成功添加到whitelist中——btm_cb.ble_ctr_cb.num_empty_filter--;
2)设备被成功地从whitelist中删除——btm_cb.ble_ctr_cb.num_empty_filter++;
        那么问题来了,如果device还没有被添加到whitelist中(更不用说删除了),两者的值是一样的,这样就刚好符合前面在btm_update_dev_to_white_list中的判断条件——打印一句log就不干了!这样做是不合理的,但是可能没出大问题,所以就一直都留着了。另一方面,即使曾经被添加到whitelist中过(也就是回连过),通过这里的判断也不会有什么不同。在添加到whitelist中的时候,host早已将这个device从btm_cb.ble_ctr_cb.wl_op_q中删除。这样看来,whitelist是只有增没有减啊!这一来不晓得后面回连的HOGP device会不会把controller的whitelist填满(填满了host自己也不知道,它统计的数量不正确!);二来是被disconnect掉的设备还有回连的机会(host也没那么挫,只是device有回连的可能,可能而已!),一旦连上就会不停地发空packet,但是不会连profile(why?),不过省电这事儿就别想了。
        说道这里,removebond准备工作的第一步就算是完成了。不过似乎还有一个数组——gatt_cb.bgconn_dev中的记录还没有删除。没错,在发送disconnect前,这个全局数组中的记录并没有被删除。。看名字就知道是gatt的接口,因此它当中device的删除也会等到gatt被层的连接被断掉。具体是在收到disconnect complete event后,gatt的connection处理函数执行过程中,调用bta_gattc_close来实现的。第二步很直接,它会直接调用btsnd_hcic_disconnect (hci_handle, HCI_ERR_PEER_USER),告诉对方disconnect的reason是HCI_ERR_PEER_USER,所以你就甭想回连了,我们这边不接受。第三步是一句设置,不过这简单的一句却决定了后面清除gatt_cache、hid cache和link key等一系列操作!因此,removeBond基本上就宣告该所有关于device的记录均将被清除,不留痕迹。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值