蓝牙BLE设备主机重启回连流程分析

如果一个BLE设备已经与蓝牙中心设备连接上,那么当中心设备的断电重启,其依然会和配对过的BLE设备连接上,而不需要重新走配对的流程,这个过程叫做回连。

这篇文章就分析一下当中心设备断电重启之后,其与BLE设备的回连的流程。

当设备重启之后,蓝牙协议栈以及所有的上层的profile 都要重新进行初始化,之前的配对信息是保存在文件bt_config.conf中,蓝牙起来之后,会去加载这个文件,去解析曾经配对过的设备,对于已经配对过的设备,并且配对信息保持完整,那么就会对该设备发起回连。那么是什么时候进行对bt_config.conf文件的解析的工作的呢?

蓝牙初始化结束之后,会接着对于各个profile的初始化,当Hid host profile 打开完成之后会对bt_config.conf 文件进行解析并 加载相应的设备信息。我们这里从hid host 打开完成之后开始分析:

hid host 打开完成之后,会经过btif_hh_upstreams_evt 来上报消息:

static void btif_hh_upstreams_evt(UINT16 event, char* p_param)
{
    tBTA_HH *p_data = (tBTA_HH *)p_param;
    btif_hh_device_t *p_dev = NULL;
    int i;
    int len, tmplen;

    BTIF_TRACE_DEBUG("%s: event=%s", __FUNCTION__, dump_hh_event(event));

    switch (event)
    {
        case BTA_HH_ENABLE_EVT:
            BTIF_TRACE_DEBUG("%s: BTA_HH_ENABLE_EVT: status =%d",__FUNCTION__, p_data->status);
            if (p_data->status == BTA_HH_OK) {
                btif_hh_cb.status = BTIF_HH_ENABLED;
                BTIF_TRACE_DEBUG("%s--Loading added devices",__FUNCTION__);
                /* Add hid descriptors for already bonded hid devices*/
                btif_storage_load_bonded_hid_info();/*load hid information*/
            }
...

我们继续看btif_storage_load_bonded_hid_info 的实现:

/*******************************************************************************
**
** Function         btif_storage_load_bonded_hid_info
**
** Description      BTIF storage API - Loads hid info for all the bonded devices from NVRAM
**                  and adds those devices  to the BTA_HH.
**
** Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
**
*******************************************************************************/
bt_status_t btif_storage_load_bonded_hid_info(void)
{
    bt_bdaddr_t bd_addr;
    tBTA_HH_DEV_DSCP_INFO dscp_info;
    uint16_t attr_mask;
    uint8_t  sub_class;
    uint8_t  app_id;

    memset(&dscp_info, 0, sizeof(dscp_info));
    for (const btif_config_section_iter_t *iter = btif_config_section_begin(); iter != btif_config_section_end(); iter = btif_config_section_next(iter)) {
        const char *name = btif_config_section_name(iter);
        if (!string_is_bdaddr(name))
            continue;

        BTIF_TRACE_DEBUG("Remote device:%s", name);
        int value;
        if(btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS)//获取bonded devices信息
        {
            if(btif_config_get_int(name, "HidAttrMask", &value))//保存各种属性
            {
                attr_mask = (uint16_t)value;

                btif_config_get_int(name, "HidSubClass", &value);
                sub_class = (uint8_t)value;

                btif_config_get_int(name, "HidAppId", &value);
                app_id = (uint8_t)value;

                btif_config_get_int(name, "HidVendorId", &value);
                dscp_info.vendor_id = (uint16_t) value;

                btif_config_get_int(name, "HidProductId", &value);
                dscp_info.product_id = (uint16_t) value;

                btif_config_get_int(name, "HidVersion", &value);
                dscp_info.version = (uint8_t) value;

                btif_config_get_int(name, "HidCountryCode", &value);
                dscp_info.ctry_code = (uint8_t) value;

                value = 0;
                btif_config_get_int(name, "HidSSRMaxLatency", &value);
                dscp_info.ssr_max_latency = (uint16_t) value;

                value = 0;
                btif_config_get_int(name, "HidSSRMinTimeout", &value);
                dscp_info.ssr_min_tout = (uint16_t) value;

                size_t len = btif_config_get_bin_length(name, "HidDescriptor");
                if(len > 0)
                {
                    dscp_info.descriptor.dl_len = (uint16_t)len;
                    dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
                    btif_config_get_bin(name, "HidDescriptor", (uint8_t *)dscp_info.descriptor.dsc_list, &len);
                }
                string_to_bdaddr(name, &bd_addr);
                // add extracted information to BTA HH
                if (btif_hh_add_added_dev(bd_addr,attr_mask))//addd new devices to btif_hh_cb.added_devices
                {
                    BTA_HhAddDev(bd_addr.address, attr_mask, sub_class,
                            app_id, dscp_info);//add device to BTA_HH
                }
            }
        }
        else
        {
...
        }
    }

    return BT_STATUS_SUCCESS;
}

 

 上面的流程很简单,获取已经绑定的设备各种信息,主要有哪些信息呢?这里附上已经绑定设备的保存的信息(BLE):

[d0:09:09:dc:00:59]
DevClass = 1344
AddrType = 0
Name = RCU
DevType = 2
LE_KEY_PENC = 23e2e46363ca4ca562dadc625cc244a41f2225d81a0a8d1924e80110
LE_KEY_PID = 0000000000000000000000000000000000d00909dc0059
LE_KEY_PCSRK = 0000000043210c0c420203040505080708090c0101c674e3
LE_KEY_LENC = 09d6fa5537cb5859f7f9220613104ab0a2f11001
LE_KEY_LCSRK = 00000000a2f10122d4ecbea1a40287b6eb74c08767855ce2
LE_KEY_LID = 
Service = 00001812-0000-1000-8000-00805f9b34fb
HidReport = 4d2a0201001a4d2a0101011a4d2a0102020e4d2afd01031a4d2a5a01041a4d2a5a02050e
HidAttrMask = 0
HidSubClass = 0
HidAppId = 255
HidVendorId = 93
HidProductId = 2
HidVersion = 0
HidCountryCode = 0
HidSSRMaxLatency = 0
HidSSRMinTimeout = 0
HidDescriptor = 05010906a1018501050719e029e71500250175019508810295017508810195057501050819012905910295017503910195067508150025a40507190029a48100c005010902a10185020901a1000509190129031500250195037501810295017505810105010930093109381581257f750895038106c0c00612ff0a12ffa10185fd0901750895ff16000026ff00190029ff8100c00612ff0a12ffa101855a0901750895ff16000026ff00190029ff8100950875010508190129089102c0

 

上面的主要流程就是解析文件,确认某个设备的确是已经绑定好的设备,那么接下来就要走回连的流程,将该设备加入到白名单中,以及发起相应的连接流程,该流程的入口函数就是BTA_HhAddDev,下面我们继续分析该函数:

/*******************************************************************************
**
** Function         BTA_HhAddDev
**
** Description      Add a virtually cabled device into HID-Host device list
**                  to manage and assign a device handle for future API call,
**                  host applciation call this API at start-up to initialize its
**                  virtually cabled devices.
**
** Returns          void
**
*******************************************************************************/
void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, UINT8 sub_class,
                  UINT8 app_id, tBTA_HH_DEV_DSCP_INFO dscp_info)
{
    tBTA_HH_MAINT_DEV    *p_buf;
    UINT16  len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len;

    p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf(len);

    if (p_buf != NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV));

        p_buf->hdr.event            = BTA_HH_API_MAINT_DEV_EVT;//发送此event
        p_buf->sub_event            = BTA_HH_ADD_DEV_EVT;
        p_buf->hdr.layer_specific   = BTA_HH_INVALID_HANDLE;

        p_buf->attr_mask            = (UINT16) attr_mask;
        p_buf->sub_class            = sub_class;
        p_buf->app_id               = app_id;
        bdcpy(p_buf->bda, bda);

        memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO));
        if ( dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list)
        {
            p_buf->dscp_info.descriptor.dl_len =  dscp_info.descriptor.dl_len;
            p_buf->dscp_info.descriptor.dsc_list = (UINT8 *)(p_buf + 1);
            memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list, dscp_info.descriptor.dl_len);
        }
        else
        {
...
        }

        bta_sys_sendmsg(p_buf);//发送消息
    }
}

 

 向BTU task 发送了BTA_HH_API_MAINT_DEV_EVT,其中包含的数据部分 都是 上面从文件解析出来的。我们继续看BTA_HH_API_MAINT_DEV_EVT 的处理,关于bta_sys_sendmsg 消息传送机制,这里就不讲了。

简单看下消息流向:

/*******************************************************************************
**
** Function         bta_hh_hdl_event
**
** Description      HID host main event handling function.
**
**
** Returns          void
**
*******************************************************************************/
BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
{
    UINT8           index = BTA_HH_IDX_INVALID;
    tBTA_HH_DEV_CB *p_cb = NULL;

    switch (p_msg->event)
    {
...
        default:
            /* all events processed in state machine need to find corresponding
                CB before proceed */
            if (p_msg->event == BTA_HH_API_OPEN_EVT)
            {
                index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
            }
            else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)//add
            {
                /* if add device */
                if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
                {
                    index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);//find devive control block
                }
...
p_cb = &bta_hh_cb.kdev[index];
...
bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg);//进入状态机

 

 

我们看看状态机的轮转情况:

/*******************************************************************************
**
** Function         bta_hh_sm_execute
**
** Description      State machine event handling function for HID Host
**
**
** Returns          void
**
*******************************************************************************/
void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
{
    tBTA_HH_ST_TBL  state_table;
    UINT8           action;
    tBTA_HH         cback_data;
    tBTA_HH_EVT     cback_event = 0;

    memset(&cback_data, 0, sizeof(tBTA_HH));
...
{
...
        state_table = bta_hh_st_tbl[p_cb->state - 1];

        event &= 0xff;

        p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;

        if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
        {
            (*bta_hh_action[action])(p_cb, p_data);
        }
...
    }

return;
}

 

这里的状态机轮转也是 熟悉的套路,开始是 idle状态,bta_hh_st_idle

/* BTA_HH_API_MAINT_DEV_EVT */    {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST    },

 

事件处理之后还是idle 状态,执行的行为是BTA_HH_MAINT_DEV_ACT:

/*******************************************************************************
**
** Function         bta_hh_maint_dev_act
**
** Description      HID Host maintain device list.
**
**
** Returns          void
**
*******************************************************************************/
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                   dev_handle;

    dev_info.status = BTA_HH_ERR;
    dev_info.handle = BTA_HH_INVALID_HANDLE;

    switch (p_dev_info->sub_event)
    {
    case BTA_HH_ADD_DEV_EVT:    /* add a device */
        bdcpy(dev_info.bda, p_dev_info->bda);
        /* initialize callback data */
        if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
        {
#if (BTA_HH_LE_INCLUDED == TRUE)
            if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr))
            {
                dev_info.handle   = bta_hh_le_add_device(p_cb, p_dev_info);
                dev_info.status   = BTA_HH_OK;
            }
            else
#endif

            if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)\
                            == HID_SUCCESS)
            ... /*非LE部分处理*/
        }
...
(* bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH *)&dev_info);//bte_hh_evt--->btif_hh_upstreams_evt

 这里涉及到的回调函数就是bte_hh_evt,其实他最终还是调用btif_hh_upstreams_evt 来完成功能。我们看看其实现:

        case BTA_HH_ADD_DEV_EVT:
            BTIF_TRACE_WARNING("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d",p_data->dev_info.status, p_data->dev_info.handle);
            int i;
            for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
                if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address, p_data->dev_info.bda, 6) == 0) {
                    if (p_data->dev_info.status == BTA_HH_OK) {
                        btif_hh_cb.added_devices[i].dev_handle = p_data->dev_info.handle;/*其实就是保存dev_handle*/
                    }
                    else {
    /*错误处理*/
                    }
                    break;
                }
            }
            break;    

 

这个handle 就是我们上面看到的

 dev_info.handle   = bta_hh_le_add_device(p_cb, p_dev_info);

 

 我们继续看看其干了什么?

我们先看看他的注释怎么说:

/*******************************************************************************
**
** Function         bta_hh_le_add_device
**
** Description      Add a LE HID device as a known device, and also add the address
**                  into back ground connection WL for incoming connection.
**
** Returns          void
**
*******************************************************************************/

 

 添加 该设备地址到whitelist 里面,当设备科连接的时候,就会直接连接上。

UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info)
{
    p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
    bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;

    /* update DI information */
    bta_hh_update_di_info(p_cb,
                          p_dev_info->dscp_info.vendor_id,
                          p_dev_info->dscp_info.product_id,
                          p_dev_info->dscp_info.version,
                          p_dev_info->dscp_info.flag);/*更新设备消息,这些消息都是从bt_config.conf里面load的*/

    /* add to BTA device list */
    bta_hh_add_device_to_list(p_cb, p_cb->hid_handle,
                              p_dev_info->attr_mask,
                              &p_dev_info->dscp_info.descriptor,
                              p_dev_info->sub_class,
                              p_dev_info->dscp_info.ssr_max_latency,
                              p_dev_info->dscp_info.ssr_min_tout,
                              p_dev_info->app_id);//添加dscp_info 等消息到p_cb

    bta_hh_le_add_dev_bg_conn(p_cb, FALSE);/*add device to WL*/

    return p_cb->hid_handle;
}

 

 上面代码的核心就是 添加 设备到BG connection,我们具体看实现:

 

static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB *p_cb, BOOLEAN check_bond)
{
    UINT8           sec_flag=0;
    BOOLEAN         to_add = TRUE;

    if (check_bond)
    {
...
    }

    if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/
        !p_cb->in_bg_conn && to_add)
    {
        /* add device into BG connection to accept remote initiated connection */
        BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE, BTA_GATT_TRANSPORT_LE);//gatt_if for hogp 
        p_cb->in_bg_conn = TRUE;

        BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL);//send msg the auto type
    }
    return;
}

这里分为两个部分来分析:

  1.  BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE, BTA_GATT_TRANSPORT_LE);添加设备,并且标志为自动连接
  2. BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL); 开始回连的操作

我们先看BTA_GATTC_OPen的实现,之前其实有一篇文章讲这个,但是那篇文章主要分析是direct connect,而这里主要分析auto connect:

void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
                    BOOLEAN is_direct, tBTA_GATT_TRANSPORT transport)
{
    tBTA_GATTC_API_OPEN  *p_buf;

    if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL)
    {
        p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT;

        p_buf->client_if = client_if;
        p_buf->is_direct = is_direct;//false
        p_buf->transport = transport;//LE
        memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);


        bta_sys_sendmsg(p_buf);
    }
    return;
}

 

 看看event的处理:

/*******************************************************************************
**
** Function         bta_gattc_hdl_event
**
** Description      GATT client main event handling function.
**
**
** Returns          BOOLEAN
**
*******************************************************************************/
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
...
        case BTA_GATTC_API_OPEN_EVT:
            bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;
...

 

 看看 关于 auto connection的处理:

/*******************************************************************************
**
** Function         bta_gattc_process_api_open
**
** Description      process connect API request.
**
** Returns          void
**
*******************************************************************************/
void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg)
{
    UINT16 event = ((BT_HDR *)p_msg)->event;
    tBTA_GATTC_CLCB *p_clcb = NULL;
    tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);//r is register 
    UNUSED(p_cb);

    if (p_clreg != NULL)
    {
        if (p_msg->api_conn.is_direct)
        {
    /*直连的处理*/
        }
        else
        {
            bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);
        }
    }

}    

 

 我们只要是看看  background connection的情况:

/*******************************************************************************
**
** Function         bta_gattc_init_bk_conn
**
** Description      Process API Open for a background connection
**
** Returns          void
**
*******************************************************************************/
void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg)
{
    tBTA_GATT_STATUS         status = BTA_GATT_NO_RESOURCES;
    UINT16                   conn_id;
    tBTA_GATTC_CLCB         *p_clcb;
    tBTA_GATTC_DATA         gattc_data;

    if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE, FALSE))//标记
    {
        /* always call open to hold a connection */
        if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE, p_data->transport))//gatt 连接,auto connection
        {
            uint8_t *bda = (uint8_t *)p_data->remote_bda;
            status = BTA_GATT_ERROR;
        }
        else
        {
            status = BTA_GATT_OK;

            /* if is a connected remote device */
            if (GATT_GetConnIdIfConnected(p_data->client_if,
                                          p_data->remote_bda,
                                          &conn_id,
                                          p_data->transport))//走到这里一般只是下发hci的连接命令,并没有连接上
            {
                    /*l连接上的处理*/
            }
        }
    }
...
}
    

 

我们看看GATT_Connect 的处理:

/*******************************************************************************
**
** Function         GATT_Connect
**
** Description      This function initiate a connecttion to a remote device on GATT
**                  channel.
**
** Parameters       gatt_if: applicaiton interface
**                  bd_addr: peer device address.
**                  is_direct: is a direct conenection or a background auto connection
**
** Returns          TRUE if connection started; FALSE if connection start failure.
**
*******************************************************************************/
BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct, tBT_TRANSPORT transport)
{
    tGATT_REG    *p_reg;
    BOOLEAN status = FALSE;

    GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);

    /* Make sure app is registered */
    if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
    {
        GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
        return(FALSE);
    }

    if (is_direct)
        status = gatt_act_connect (p_reg, bd_addr, transport);
    else
    {
        if (transport == BT_TRANSPORT_LE)
        status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);//update auto connection 相关
        else
        {
            GATT_TRACE_ERROR("Unsupported transport for background connection");
        }
    }

    return status;

}

 

我们继续看:

/*******************************************************************************
**
** Function         gatt_update_auto_connect_dev
**
** Description      This function add or remove a device for background connection
**                  procedure.
**
** Parameters       gatt_if: Application ID.
**                  add: add peer device
**                  bd_addr: peer device address.
**
** Returns          TRUE if connection started; FALSE if connection start failure.
**
*******************************************************************************/
BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initator)
{
    BOOLEAN         ret = FALSE;
    tGATT_REG        *p_reg;
    tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);

    GATT_TRACE_API ("gatt_update_auto_connect_dev ");
    /* Make sure app is registered */
    if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
    {
        GATT_TRACE_ERROR("gatt_update_auto_connect_dev - gatt_if is not registered", gatt_if);
        return(FALSE);
    }

    if (add)
    {
        ret = gatt_add_bg_dev_list(p_reg, bd_addr, is_initator);/*加入到bg connection*/

        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, is_initator);
    }
    return ret;
}

 

 我们继续看gatt_add_bg_dev_list的实现:

/*******************************************************************************
**
** Function         gatt_add_bg_dev_list
**
** Description      add/remove device from the back ground connection device list
**
** Returns          TRUE if device added to the list; FALSE failed
**
*******************************************************************************/
BOOLEAN gatt_add_bg_dev_list(tGATT_REG *p_reg,  BD_ADDR bd_addr, BOOLEAN is_initator)
{
    tGATT_IF gatt_if =  p_reg->gatt_if;
    tGATT_BG_CONN_DEV   *p_dev = NULL;
    UINT8       i;
    BOOLEAN      ret = FALSE;

    if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
    {
        p_dev = gatt_alloc_bg_dev(bd_addr);
    }

    if (p_dev)
    {
        for (i = 0; i < GATT_MAX_APPS; i ++)
        {
            if (is_initator)
            {
                if (p_dev->gatt_if[i] == gatt_if)
                {
                    GATT_TRACE_ERROR("device already in iniator white list");
                    return TRUE;
                }
                else if (p_dev->gatt_if[i] == 0)
                {
                    p_dev->gatt_if[i] = gatt_if;
                    if (i == 0)
                        ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr);//update bg connection
                    else
                        ret = TRUE;
                    break;
                }
            }
            else
            {
             /*accept role 的处理*/
            }
        }
    }

    return ret;
}

 

我们接着看:

/*******************************************************************************
**
** Function         BTM_BleUpdateBgConnDev
**
** Description      This function is called to add or remove a device into/from
**                  background connection procedure. The background connection
*                   procedure is decided by the background connection type, it can be
*                   auto connection, or selective connection.
**
** Parameters       add_remove: TRUE to add; FALSE to remove.
**                  remote_bda: device address to add/remove.
**
** Returns          void
**
*******************************************************************************/
BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR   remote_bda)
{
    BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove);
    return btm_update_dev_to_white_list(add_remove, remote_bda);//add
}

我们继续分析btm_update_dev_to_white_list:

/*******************************************************************************
**
** Function         btm_update_dev_to_white_list
**
** Description      This function adds or removes a device into/from
**                  the white list.
**
*******************************************************************************/
BOOLEAN btm_update_dev_to_white_list(BOOLEAN 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);//add
    else
        background_connection_remove((bt_bdaddr_t*)bd_addr);//remove

    btm_suspend_wl_activity(p_cb->wl_state);//因为当前的WL没有行为,所以do nothing
    btm_enq_wl_dev_operation(to_add, bd_addr);//更新btm_cb.ble_ctr_cb.wl_op_q
    btm_resume_wl_activity(p_cb->wl_state);//恢复WL的行为
    return TRUE;
}

 

上面的逻辑很简单,就是把设备的地址add 到bg connection里面。然后更新whitelist的列表,然后重新调度WL的行为。我们先看看background_connection_add的实现:

static void background_connection_add(bt_bdaddr_t *address) {
  assert(address);
  background_connections_lazy_init();
  background_connection_t *connection = hash_map_get(background_connections, address);
  if (!connection) {
    connection = osi_calloc(sizeof(background_connection_t));
    connection->address = *address;
    hash_map_set(background_connections, &(connection->address), connection);
  }
}

 

组建了 key value 键值对放置 到 background connection里面。

我们在看看btm_resume_wl_activity 的实现:

/*******************************************************************************
**
** Function         btm_resume_wl_activity
**
** Description      This function is to resume white list related activity
**
** Returns          none.
**
*******************************************************************************/
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();
    }

}

 我们看btm_ble_resume_bg_conn的实现:

/*******************************************************************************
**
** Function         btm_ble_resume_bg_conn
**
** Description      This function is to resume a background auto connection
**                  procedure.
**
** Parameters       none.
**
** Returns          none.
**
*******************************************************************************/
BOOLEAN btm_ble_resume_bg_conn(void)
{
    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
    BOOLEAN ret = FALSE;
    if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE)
    {
        if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
            ret = btm_ble_start_auto_conn(TRUE);//开始auto connection
            
        if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
            ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback);
    }

    return ret;
}

 

我们继续往下看btm_ble_start_auto_conn实现:

/*******************************************************************************
**
** Function         btm_ble_start_auto_conn
**
** Description      This function is to start/stop auto connection procedure.
**
** Parameters       start: TRUE to start; FALSE to stop.
**
** Returns          void
**
*******************************************************************************/
BOOLEAN btm_ble_start_auto_conn(BOOLEAN start)
{
    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
    BD_ADDR dummy_bda = {0};
    BOOLEAN exec = TRUE;
    UINT16 scan_int;
    UINT16 scan_win;
    UINT8 own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
    UINT8 peer_addr_type = BLE_ADDR_PUBLIC;
     
    if (start)
    {
        if ( p_cb->conn_state == BLE_CONN_IDLE )
        {
            exec = btm_execute_wl_dev_operation();//btm_add_dev_to_controller-->btsnd_hcic_ble_add_white_list
        }

        if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending()
            && btm_ble_topology_check(BTM_BLE_STATE_INIT))
        {
            p_cb->wl_state  |= BTM_BLE_WL_INIT;
...
            scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ?
                                          BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int;
            scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ?
                                          BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win;
...

            if (!btsnd_hcic_ble_create_ll_conn (scan_int,  /* UINT16 scan_int      */
                                                scan_win,    /* UINT16 scan_win      */
                                                0x01,                   /* UINT8 white_list     */
                                                peer_addr_type,        /* UINT8 addr_type_peer */
                                                dummy_bda,              /* BD_ADDR bda_peer     */
                                                own_addr_type,          /* UINT8 addr_type_own */
                                                BTM_BLE_CONN_INT_MIN_DEF,   /* UINT16 conn_int_min  */
                                                BTM_BLE_CONN_INT_MAX_DEF,   /* UINT16 conn_int_max  */
                                                BTM_BLE_CONN_SLAVE_LATENCY_DEF,  /* UINT16 conn_latency  */
                                                BTM_BLE_CONN_TIMEOUT_DEF,        /* UINT16 conn_timeout  */
                                                0,                       /* UINT16 min_len       */
                                                0))                      /* UINT16 max_len       */
            {
                /* start auto connection failed */
                exec =  FALSE;
                p_cb->wl_state &= ~BTM_BLE_WL_INIT;
            }
            else
            {
                btm_ble_set_conn_st (BLE_BG_CONN);//set BLE connection state
            }
        }
        else
        {
            exec = FALSE;
        }
    }
 ...
    return exec;
}

 

上面执行的任务主要就是把设备加入到controller 的whitelist里面,然后下发LE connect 命令到controller,

我们简单看下btm_execute_wl_dev_operation:

/*******************************************************************************
**
** Function         btm_execute_wl_dev_operation
**
** Description      execute the pending whitelist device operation(loading or removing)
*******************************************************************************/
BOOLEAN btm_execute_wl_dev_operation(void)
{
    tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;//btm_enq_wl_dev_operation 更新btm_cb.ble_ctr_cb.wl_op_q 
    UINT8   i = 0;
    BOOLEAN rt = TRUE;

    for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++)
    {
        if (p_dev_op->in_use)
        {
            rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr);//下发HCI command
            memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP));
        }
        else
            break;
    }
    return rt;
}

 

好了,关于BTA_GATTC_Open  就分析到这里,下面我们看看第二点:

2.BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL)的流程:

void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback)
{
#if BLE_INCLUDED == TRUE
    tBTA_DM_API_BLE_SET_BG_CONN_TYPE    *p_msg;

    if ((p_msg = (tBTA_DM_API_BLE_SET_BG_CONN_TYPE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE))) != NULL)
    {
        memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE));

        p_msg->hdr.event        = BTA_DM_API_BLE_SET_BG_CONN_TYPE;
        p_msg->bg_conn_type     = bg_conn_type;
        p_msg->p_select_cback   = p_select_cback;

        bta_sys_sendmsg(p_msg);
    }
#endif
}

执行的函数是

void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data)
{
    BTM_BleSetBgConnType(p_data->ble_set_bd_conn_type.bg_conn_type,
                         p_data->ble_set_bd_conn_type.p_select_cback);
}

 

BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE   bg_conn_type,
                             tBTM_BLE_SEL_CBACK   *p_select_cback)
{
    BOOLEAN started = TRUE;

    BTM_TRACE_EVENT ("BTM_BleSetBgConnType ");
    if (!controller_get_interface()->supports_ble())
        return FALSE;

    if (btm_cb.ble_ctr_cb.bg_conn_type != bg_conn_type)
    {
        switch (bg_conn_type)
        {
            case BTM_BLE_CONN_AUTO:
                btm_ble_start_auto_conn(TRUE);
                break;

 

发现这里最终也会执行到btm_ble_start_auto_conn,流程和上面的流程一样,就不赘述。

关于BLE设备回连的问题就先分析到这里。

posted @ 2018-09-06 20:20  雪山飞燕  阅读(8587)  评论(1编辑  收藏  举报