bluedroid中的start discovery代码流程

    之前看到某位大神的博客android -- 蓝牙 bluetooth (三)搜索蓝牙,介绍了Android中蓝牙的搜索过程,从framework到service,再到JNI、bluetooth stack,大致的流程讲得很清楚。这里我了解了一下Android4.4中bluetooth stack中的代码流程,总结如下。

    在JNI层中调用startDiscoveryNative函数,最终指向stack层bluetoothInterface(bluetooth.c)结构的成员函数start_discovery,这便是stack层的入口。在btif_dm_start_discovery(btif_dm.c)函数中设置了discovery的相关参数,并调用BTA_DmSearch(&inq_params, services, bte_search_devices_evt)来执行。这个函数的内容如下:

void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{

    tBTA_DM_API_SEARCH    *p_msg;

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

        p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
        memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
        p_msg->services = services;
        p_msg->p_cback = p_cback;
        p_msg->rs_res  = BTA_DM_RS_NONE;
        bta_sys_sendmsg(p_msg);
    }

}
可以看到,该函数构造了一个消息p_msg,设置了事件类型以及回调函数。在这里,回调函数即前面的bte_search_devices_evt,它处理搜索的结果,并最终通过JNI提供的callback返回给上层。这个消息被发送到btu_task,由bta模块处理,代码如下:

BTA_API void bta_sys_event(BT_HDR *p_msg)
{
    UINT8       id;
    BOOLEAN     freebuf = TRUE;

    APPL_TRACE_EVENT1("BTA got event 0x%x", p_msg->event);

    /* 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);
    }
    else
    {
        APPL_TRACE_WARNING1("BTA got unregistered event id %d", id);
    }

    if (freebuf)
    {
        GKI_freebuf(p_msg);
    }

}
其内容很简单,就是暗中event的id来调相应的函数来处理。对于search过程来说,他的处理函数早在蓝牙初始化中调用函数 BTA_EnableBluetooth中注册:

bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg );
从而,代码转入bta_dm_search_reg的成员函数bta_dm_search_sm_execute。它的实现跟上面的bta_sys_event很类似,根据不同的state来调用相应状态下的函数。代码如下:

BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg)
{
    tBTA_DM_ST_TBL      state_table;
    UINT8               action;
    int                 i;

    APPL_TRACE_EVENT2("bta_dm_search_sm_execute state:%d, event:0x%x",
        bta_dm_search_cb.state, p_msg->event);

    /* look up the state table for the current state */
    state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];

    bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];


    /* execute action functions */
    for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++)
    {
        if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE)
        {
            (*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg);
        }
        else
        {
            break;
        }
    }
    return TRUE;
}
刚进入这个函数时,由于bta_dm_search_cb.state为0,故state_table为 bta_dm_search_idle_st_table;由于前面在BTA_DmSearch中设置的event为BTA_DM_API_SEARCH_EVT(0x0200),从而第一个真正的执行函数为bta_dm_search_start。它的关键部分如下:

void bta_dm_search_start (tBTA_DM_MSG *p_data)
{
    ......
    /* save search params */
    bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
    bta_dm_search_cb.services = p_data->search.services;

    ......
    result.status = BTM_StartInquiry(   (tBTM_INQ_PARMS*)&p_data->search.inq_params,
                        bta_dm_inq_results_cb,
                        (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);

    ......
}
在第一部分,它注册了search的回调函数给全局变量bta_dm_search_cb的成员;同时,它在第二部分调用BTM_StartInquiry去执行inquiry(扯了这么多其实还没到真正发HCI command的地方)。同样的,将函数BTM_StartInquiry的关键部分贴在下面:

*******************************************************************************/
tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
                              tBTM_CMPL_CB *p_cmpl_cb)
{
    tBTM_STATUS  status = BTM_CMD_STARTED;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
    ......

    /* Initialize the inquiry variables */
    p_inq->state = BTM_INQ_ACTIVE_STATE;
    p_inq->p_inq_cmpl_cb = p_cmpl_cb;
    p_inq->p_inq_results_cb = p_results_cb;
    p_inq->inq_cmpl_info.num_resp = 0;         /* Clear the results counter */
    p_inq->inq_active = p_inqparms->mode;

   
    ......
}
很简单,它再次设置了bta_dm_search_cb的一些成员,最重要的即扫描结果的回调函数p_results_cb(即bta_dm_inq_results_cb)和扫描完成(超时或者收到results的数目超过设定)的处理函数 p_cmpl_cb(即bta_dm_inq_cmpl_cb)。这样,在收到inquiry的results后便有相应的处理函数。在设置完这些参数后,函数后半段便要开始执行扫描了,最终通过btu_hcif_send_cmd将BR\EDR或者LE扫描的HCI指令发送给controller。同时,它还会对上层进行通知,告知执行已经执行,现在的状态是discovery_started。而当收到扫描的report时,调用callback函数上报device_found。只有当用于通过UI选择与某一个设备进行配对时,才会进入后面的配对鉴权、加密等过程,这些留待以后慢慢学习。









你可能感兴趣的:(bluedroid)