Bluedroid 函數分析:BTA_GATTC_Open

進行GATT 通訊,首先要打開GATT 的通道。下面咱們分析BTA_GATTC_Open 這個函數:html

這個函數在bta_gattc_api.c 文件中定義,這個是一個接口文件,裏面沒有作真正的open的動做,最終仍是要將open 的事件傳遞到BTE層面:api

 

/*******************************************************************************
**
** Function         BTA_GATTC_Open
**
** Description      Open a direct connection or add a background auto connection
**                  bd address
**
** Parameters       client_if: server interface.
**                  remote_bda: remote device BD address.
**                  is_direct: direct connection or background auto connection
**                  transport: Transport to be used for GATT connection (BREDR/LE)
**
** Returns          void
**
*******************************************************************************/
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;//發送事件到BTU task

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


        bta_sys_sendmsg(p_buf);
    }
    return;
}

 

接下來咱們看看BTA_GATTC_API_OPEN_EVT 的處理:服務器

/*******************************************************************************
**
** 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;
...

 

套路都同樣,繼續看:app

/*******************************************************************************
**
** 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);

    if (p_clreg != NULL)
    {
        if (p_msg->api_conn.is_direct)
        {
            if ((p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if,
                                                    p_msg->api_conn.remote_bda,
                                                    p_msg->api_conn.transport)) != NULL)
            {
                bta_gattc_sm_execute(p_clcb, event, p_msg);
            }
...

咱們看到,目前仍是在BTA 層面,可是他最終會進入到狀態機來處理這個event,狀態機的實現,都相似,咱們以前也屢次提到:函數

/*******************************************************************************
**
** Function         bta_gattc_sm_execute
**
** Description      State machine event handling function for GATTC
**
**
** Returns          BOOLEAN  : TRUE if queued client request buffer can be immediately released
**                                        else FALSE
**
*******************************************************************************/
BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATTC_ST_TBL     state_table;
    UINT8               action;
    int                 i;
    BOOLEAN             rt = TRUE;

    /* look up the state table for the current state */
    state_table = bta_gattc_st_tbl[p_clcb->state];

    event &= 0x00FF;

    /* set next state */
    p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];

    /* execute action functions */
    for (i = 0; i < BTA_GATTC_ACTIONS; i++)
    {
        if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
        {
            (*bta_gattc_action[action])(p_clcb, p_data);
            if (p_clcb->p_q_cmd == p_data) {
                /* buffer is queued, don't free in the bta dispatcher.
                 * we free it ourselves when a completion event is received.
                 */
                rt = FALSE;
            }
        }
        else
        {
            break;
        }
    }

    return rt;
}

 

根據當前的狀態,而後找到狀態轉換表,根據event 來查找當前應該執行的action,根據action 找到具體要執行的函數。ui

我這裏分析的case,是BLe 設備剛配對完來進行GATT 流程的執行,這個時候的GATTC的state是idle:this

對應的action = BTA_GATTC_OPEN,下一個狀態是BTA_GATTC_W4_CONN_ST ,spa

執行的函數是bta_gattc_open:設計

/*******************************************************************************
**
** Function         bta_gattc_open
**
** Description      Process API connection function.
**
** Returns          void
**
*******************************************************************************/
void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATTC_DATA gattc_data;
    /* open/hold a connection */
    if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda,
                      TRUE, p_data->api_conn.transport))//關鍵函數
    {
        APPL_TRACE_ERROR("Connection open failure");

        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data);
    }
    else
    {
        /* a connected remote device */
        if (GATT_GetConnIdIfConnected(p_clcb->p_rcb->client_if,
                                      p_data->api_conn.remote_bda,
                                      &p_clcb->bta_conn_id,
                                      p_data->api_conn.transport))
        {
            gattc_data.int_conn.hdr.layer_specific = p_clcb->bta_conn_id;

            bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);//下一個階段的流程
        }
        /* else wait for the callback event */
    }
}

 

上面的函數主要是 GATT_Connect ,這個函數主要是在L2cap 層面分配一個GATT的通道,其channel id 是4,code

下面繼續看:

/*******************************************************************************
**
** Function         gatt_connect
**
** Description      This function is called to initiate a connection to a peer device.
**
** Parameter        rem_bda: remote device address to connect to.
**
** Returns          TRUE if connection is started, otherwise return FALSE.
**
*******************************************************************************/
BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb, tBT_TRANSPORT transport)
{
    BOOLEAN             gatt_ret = FALSE;

    if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN)
        gatt_set_ch_state(p_tcb, GATT_CH_CONN);

    if (transport == BT_TRANSPORT_LE)
    {
        p_tcb->att_lcid = L2CAP_ATT_CID;
        gatt_ret = L2CA_ConnectFixedChnl (L2CAP_ATT_CID, rem_bda);//在l2cap層分配channel
    }
    else
    {
        if ((p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda)) != 0)
            gatt_ret = TRUE;
    }

    return gatt_ret;
}

 

在bta_gattc_open 中還作了以下的事情,繼續分析

gattc_data.int_conn.hdr.layer_specific = p_clcb->bta_conn_id;
bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);

 其繼續進入到狀態機中來執行新的任務:BTA_GATTC_INT_CONN_EVT

當前的狀態是BTA_GATTC_W4_CONN_ST,根據狀態機 ,當前須要執行的action 是:

/* BTA_GATTC_INT_CONN_EVT           */   {BTA_GATTC_CONN,               BTA_GATTC_CONN_ST},

 

對應的函數是bta_gattc_conn,看到函數的名字,咱們有點疑惑,剛剛的gattc open不是已經作了gatt connect的動做嗎?這裏怎麼還有鏈接的操做?其實這個是一個回調函數,正如其註釋寫的那樣:「receive connection callback from stack」

/*******************************************************************************
**
** Function         bta_gattc_conn
**
** Description      receive connection callback from stack
**
** Returns          void
**
*******************************************************************************/
void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATTC_IF   gatt_if;

    if (p_data != NULL)
    {
        p_clcb->bta_conn_id  = p_data->int_conn.hdr.layer_specific;

        GATT_GetConnectionInfor(p_data->hdr.layer_specific,
                                &gatt_if, p_clcb->bda, &p_clcb->transport);//獲取對應的gatt_if
    }
        p_clcb->p_srcb->connected = TRUE;
        if (p_clcb->p_srcb->mtu == 0)
            p_clcb->p_srcb->mtu = GATT_DEF_BLE_MTU_SIZE;

        /* start database cache if needed */
        if (p_clcb->p_srcb->p_srvc_cache == NULL ||
            p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE)//在refresh的時候清掉了
        {
            if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE)
            {
                p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD;
                bta_gattc_sm_execute(p_clcb, BTA_GATTC_START_CACHE_EVT, NULL);//開始BTA_GATTC_START_CACHE_EVT,
            }
            else /* cache is building */
                p_clcb->state = BTA_GATTC_DISCOVER_ST;//說明正在進行*CACHE_EVT,
        }

        else
        {
...
        }

        if (p_clcb->p_rcb)
        {
...
        bta_gattc_send_open_cback(p_clcb->p_rcb,
                                  BTA_GATT_OK,
                                  p_clcb->bda,
                                  p_clcb->bta_conn_id,
                                  p_clcb->transport,
                                  p_clcb->p_srcb->mtu);//回調通告
        }
    }

 

 上面函數主要作了兩件事:

  1. bta_gattc_sm_execute(p_clcb, BTA_GATTC_START_CACHE_EVT, NULL);
  2. bta_gattc_send_open_cback(p_clcb->p_rcb,BTA_GATT_OK,p_clcb->bda,p_clcb->bta_conn_id,p_clcb->transport,p_clcb->p_srcb->mtu);

先看第一點:

  當前的狀態已經變成了BTA_GATTC_CONN_ST,處理的event是BTA_GATTC_START_CACHE_EVT,

/* BTA_GATTC_START_CACHE_EVT        */   {BTA_GATTC_CACHE_OPEN,         BTA_GATTC_DISCOVER_ST},

 

說明下一個狀態是 BTA_GATTC_DISCOVER_ST,action是BTA_GATTC_CACHE_OPEN 

執行的函數是: 

/*******************************************************************************
**
** Function         bta_gattc_cache_open
**
** Description      open a NV cache for loading
**
** Returns          void
**
*******************************************************************************/
void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    UNUSED(p_data);

    bta_gattc_set_discover_st(p_clcb->p_srcb);

    bta_gattc_co_cache_open(p_clcb->p_srcb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT,
                            p_clcb->bta_conn_id, FALSE);
}

 

 這個函數不作具體的分析,主要就是打開了cache文件,而且發送了BTA_GATTC_CI_CACHE_OPEN_EVT 這個事件,這裏注意,由於以前cache的文件已經在refresh的過程當中 刪除了,這裏open cache的行爲是失敗的

/* BTA_GATTC_CI_CACHE_OPEN_EVT      */   {BTA_GATTC_CI_OPEN,            BTA_GATTC_DISCOVER_ST},

 看看BTA_GATTC_CI_OPEN對應的函數:bta_gattc_ci_open:

/*******************************************************************************
**
** Function         bta_gattc_start_load
**
** Description      start cache loading by sending callout open cache
**
** Returns          None.
**
*******************************************************************************/
void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    if (p_clcb->p_srcb->state == BTA_GATTC_SERV_LOAD)
    {
        if (p_data->ci_open.status == BTA_GATT_OK)
        {
            p_clcb->p_srcb->attr_index = 0;
            bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda,
                                    BTA_GATTC_CI_CACHE_LOAD_EVT,
                                    p_clcb->p_srcb->attr_index,
                                    p_clcb->bta_conn_id);
        }
        else  //前面已經刪除cache,因此打開cache 是失敗的
        {
            p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC;//設置狀態
            /* cache open failure, start discovery */
            bta_gattc_start_discover(p_clcb, NULL);//開始discovery
        }
    }
    if (p_clcb->p_srcb->state == BTA_GATTC_SERV_SAVE)//這個應該是discovery 完成以後  纔會走的流程
    {
        if (p_data->ci_open.status == BTA_GATT_OK)
        {
            if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id))
            {
                p_data->ci_open.status = BTA_GATT_ERROR;
            }
        }
        if (p_data->ci_open.status != BTA_GATT_OK)
        {
            p_clcb->p_srcb->attr_index = 0;
            bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, p_clcb->bta_conn_id);
            bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);

        }
    }
}

 

咱們繼續看bta_gattc_start_discover 的實現:這裏其實對於bluedroid的實現感到奇怪,GATT open的函數,最後連同discovery的工做也一塊兒作了:

/*******************************************************************************
**
** Function         bta_gattc_start_discover
**
** Description      Start a discovery on server.
**
** Returns          None.
**
*******************************************************************************/
void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    UNUSED(p_data);

    if (((p_clcb->p_q_cmd == NULL || p_clcb->auto_update == BTA_GATTC_REQ_WAITING) &&
        p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) ||
        p_clcb->p_srcb->state == BTA_GATTC_SERV_DISC)
    /* no pending operation, start discovery right away */
    {
        p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE;

        if (p_clcb->p_srcb != NULL)//清一些標誌位和數據
        {
            /* clear the service change mask */
            p_clcb->p_srcb->srvc_hdl_chg = FALSE;
            p_clcb->p_srcb->update_count = 0;
            p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT;

            if (p_clcb->transport == BTA_TRANSPORT_LE)
                L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, FALSE);

            /* set all srcb related clcb into discovery ST */
            bta_gattc_set_discover_st(p_clcb->p_srcb);

            if ((p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb)) == BTA_GATT_OK)
            {
                p_clcb->status = bta_gattc_discover_pri_service(p_clcb->bta_conn_id,
                                                               p_clcb->p_srcb, GATT_DISC_SRVC_ALL);//開始正在的搜索工做
            }
            if (p_clcb->status != BTA_GATT_OK)
            {
                APPL_TRACE_ERROR("discovery on server failed");
                bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
            }
            else
                p_clcb->disc_active = TRUE;
        }
        else
        {
            APPL_TRACE_ERROR("unknown device, can not start discovery");
        }
    }
    /* pending operation, wait until it finishes */
    else
    {
...
    }

}

咱們看到 其最終執行了bta_gattc_discover_pri_service ,其中參數是GATT_DISC_SRVC_ALL,就是搜索全部的服務

 

/*******************************************************************************
**
** Function         bta_gattc_discover_pri_service
**
** Description      Start primary service discovery
**
** Returns          status of the operation.
**
*******************************************************************************/
tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb,
                                                    UINT8 disc_type)
{
    tBTA_GATTC_CLCB     *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
    tBTA_GATT_STATUS    status =  BTA_GATT_ERROR;

    if (p_clcb)
    {
        if (p_clcb->transport == BTA_TRANSPORT_LE)
            status = bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type);
        else
            status = bta_gattc_sdp_service_disc(conn_id, p_server_cb);
    }

    return status;
}

 

執行bta_gattc_discover_procedure  流程:

/*******************************************************************************
**
** Function         bta_gattc_discover_procedure
**
** Description      Start a particular type of discovery procedure on server.
**
** Returns          status of the operation.
**
*******************************************************************************/
tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb,
                                                   UINT8 disc_type)
{
    tGATT_DISC_PARAM param;
    BOOLEAN is_service = TRUE;

    memset(&param, 0, sizeof(tGATT_DISC_PARAM));

    if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID)//這兩種case 都是在全部服務裏面搜索
    {
        param.s_handle = 1;
        param.e_handle = 0xFFFF;
    }
    else
    {
        if (disc_type == GATT_DISC_CHAR_DSCPT)
            is_service = FALSE;

        bta_gattc_get_disc_range(p_server_cb, &param.s_handle, &param.e_handle, is_service);

        if (param.s_handle > param.e_handle)
        {
            return GATT_ERROR;
        }
    }
    return GATTC_Discover (conn_id, disc_type, &param);//調用GATT_discovery

}

 

最終也是調用到GATTC_Discovery 這個函數來執行

tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
                             tGATT_DISC_PARAM *p_param)
{
...
        p_clcb->operation  = GATTC_OPTYPE_DISCOVERY;
        p_clcb->op_subtype = disc_type;
        p_clcb->s_handle   = p_param->s_handle;
        p_clcb->e_handle   = p_param->e_handle;
        p_clcb->uuid       = p_param->service;

        gatt_act_discovery(p_clcb);    
...

 

這邊的流程就是和 https://www.cnblogs.com/libs-liu/p/9334908.html  中的流程差很少了。GATT服務器返回的response的處理流程也很簡單,就是保存,相應的鍵值對,而後進行下一輪的搜索:

/*******************************************************************************
**
** Function         gatt_process_read_by_type_rsp
**
** Description      This function is called to handle the read by type response.
**                  read by type can be used for discovery, or read by type or
**                  read characteristic value.
**
** Returns          void
**
*******************************************************************************/
void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
                                    UINT16 len, UINT8 *p_data)
{
    tGATT_DISC_RES      result;
    tGATT_DISC_VALUE    record_value;
    UINT8               *p = p_data, value_len, handle_len = 2;
    UINT16              handle = 0;
...
        /* send callback if is discover procedure */
        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb)
            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);//上報搜索的結果
    }

    p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);

    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
    {
        /* initiate another request */
        gatt_act_discovery(p_clcb) ;//繼續進行搜索,直到err response
    }

 

這裏簡單看一下,對於搜索結果的回調的處理:處理函數 是bta_gattc_disc_res_cback-->bta_gattc_add_srvc_to_list ,保存結果到p_srvc_cb ,這裏暫時還沒看見寫到cache 文件裏面,應該是之後纔會建立cache 文件並寫入。

這裏當 pri service 搜索完成以後,就會執行gatt_end_operation,這個函數主要執行的事情也是回調:

/*******************************************************************************
**
** Function         gatt_end_operation
**
** Description      This function ends a discovery, send callback and finalize
**                  some control value.
**
** Returns          16 bits uuid.
**
*******************************************************************************/
void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data)
{
    tGATT_CL_COMPLETE   cb_data;
    tGATT_CMPL_CBACK    *p_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_cmpl_cb : NULL;
    UINT8               op = p_clcb->operation, disc_type=GATT_DISC_MAX;
    tGATT_DISC_CMPL_CB  *p_disc_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_disc_cmpl_cb : NULL;
    UINT16              conn_id;
    UINT8               operation;
...
 if (p_disc_cmpl_cb && (op == GATTC_OPTYPE_DISCOVERY))
        (*p_disc_cmpl_cb)(conn_id, disc_type, status);//回調
    else if (p_cmpl_cb && op)
        (*p_cmpl_cb)(conn_id, op, status, &cb_data);
...

 

看看這個disc_cmpl的具體執行的操做:

void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status)
{
    tBTA_GATTC_SERV * p_srvc_cb;
    tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
...
    p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);

    if (p_srvc_cb != NULL)
    {
        switch (disc_type)
        {
            case GATT_DISC_SRVC_ALL:
            case GATT_DISC_SRVC_BY_UUID:
                bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx);//打印搜索的結構

                bta_gattc_explore_srvc(conn_id, p_srvc_cb);//繼續搜索
                break;

 這裏貼一下 log中關於service 的打印:

01-01 11:44:37.596 E/bt_btif ( 3816): <================Start Explore Queue =============>
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[1] uuid[0x1800] s_handle[1] e_handle[7] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[2] uuid[0x1812] s_handle[8] e_handle[46] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[3] uuid[0x1801] s_handle[47] e_handle[50] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[4] uuid[0x180f] s_handle[51] e_handle[54] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[5] uuid[0x180a] s_handle[55] e_handle[73] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[6] uuid[0x1813] s_handle[74] e_handle[79] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[7] uuid[0xa212] s_handle[80] e_handle[96] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816):      rec[8] uuid[0xa212] s_handle[97] e_handle[65535] is_primary[1]
01-01 11:44:37.596 E/bt_btif ( 3816): <================ End Explore Queue =============>

 

簡單看一下,bta_gattc_explore_srvc的實現:

/*******************************************************************************
**
** Function         bta_gattc_explore_srvc
**
** Description      process the service discovery complete event
**
** Returns          status
**
*******************************************************************************/
static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
{
    tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
    tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);

    APPL_TRACE_DEBUG("Start service discovery: srvc_idx = %d", p_srvc_cb->cur_srvc_idx);//打印出當前處於 搜索的階段

    p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc;

    /* start expore a service if there is service not been explored */
    if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc)//繼續搜索
    {
        /* add the first service into cache *///保存cache
        if (bta_gattc_add_srvc_to_cache (p_srvc_cb,
                                         p_rec->s_handle,
                                         p_rec->e_handle,
                                         &p_rec->uuid,
                                         p_rec->is_primary,
                                         p_rec->srvc_inst_id) == 0)
        {
            /* start discovering included services */
            bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb);//繼續搜索
            return;
        }
    }

 

/*******************************************************************************
**
** Function         bta_gattc_explore_srvc
**
** Description      process the service discovery complete event
**
** Returns          status
**
*******************************************************************************/
static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
{
    tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
    tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);

    APPL_TRACE_DEBUG("Start service discovery: srvc_idx = %d", p_srvc_cb->cur_srvc_idx);

    p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc;

    if (p_clcb == NULL)
    {
        APPL_TRACE_ERROR("unknown connection ID");
        return;
    }
    /* start expore a service if there is service not been explored */
    if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc)
    {
        /* add the first service into cache */
        if (bta_gattc_add_srvc_to_cache (p_srvc_cb,
                                         p_rec->s_handle,
                                         p_rec->e_handle,
                                         &p_rec->uuid,
                                         p_rec->is_primary,
                                         p_rec->srvc_inst_id) == 0)
        {
            /* start discovering included services */
            bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb);//繼續搜索include 的服務
            return;
        }
    }
    /* no service found at all, the end of server discovery*/
    LOG_WARN("%s no more services found", __func__);

#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
    bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
#endif
    /* save cache to NV */
    p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
    bta_gattc_co_cache_open(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT,
                            conn_id, TRUE);//最後會保存到cache 文件中
}

  發現他會繼續搜索 include的服務。分析到這裏,咱們能夠看到一個完成的服務的搜索的流程。 

 結合log,咱們能夠看出,搜索的流程是先 搜索全部的pri service,而後將這些service 分紅N個組,而後在每一個組裏面進行include 的搜索,以及後續的UUID: Characteristic以及其餘的服務的搜索。

下面咱們看看 如何從每個組中 依次進行include 以及特性的搜索的:

/*******************************************************************************
**
** Function         bta_gattc_start_disc_include_srvc
**
** Description      Start discovery for included service
**
** Returns          status of the operation.
**
*******************************************************************************/
tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
{
    return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC);
}

 

繼續看:

/*******************************************************************************
**
** Function         bta_gattc_discover_procedure
**
** Description      Start a particular type of discovery procedure on server.
**
** Returns          status of the operation.
**
*******************************************************************************/
tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb,
                                                   UINT8 disc_type)
{
    tGATT_DISC_PARAM param;
    BOOLEAN is_service = TRUE;

    memset(&param, 0, sizeof(tGATT_DISC_PARAM));

    if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID)
    {
        param.s_handle = 1;
        param.e_handle = 0xFFFF;
    }
    else
    {
        if (disc_type == GATT_DISC_CHAR_DSCPT)
            is_service = FALSE;

        bta_gattc_get_disc_range(p_server_cb, &param.s_handle, &param.e_handle, is_service);//從cache獲取搜索的範圍

        if (param.s_handle > param.e_handle)
        {
            return GATT_ERROR;
        }
    }
    return GATTC_Discover (conn_id, disc_type, &param);//開始搜索

}

 

這裏結合log 來分析,發現是error response,發現是沒有搜索到相關的include 的服務。沒有搜索到服務的最終的處理就是 gatt_end_operation(p_clcb, status, NULL);

這個以前也講過,最終執行:

    if (p_disc_cmpl_cb && (op == GATTC_OPTYPE_DISCOVERY))
        (*p_disc_cmpl_cb)(conn_id, disc_type, status);

 

 這裏能夠預想,它確定是 又去執行 搜索Characteristic的相關的特性去了,咱們繼續分析看是否是這樣:它執行的是bta_gattc_incl_srvc_disc_cmpl,這個函數:

static void bta_gattc_incl_srvc_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
{
    p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc;

    /* start discoverying characteristic */
    bta_gattc_start_disc_char(conn_id, p_srvc_cb);//搜索char
}

 

果真是去執行 搜索char的行爲。那麼咱們如今分析一下 p_disc_cmpl_cb 這個函數,其是註冊的discovery完成的回調函數bta_gattc_disc_cmpl_cback:

void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status)
{
    tBTA_GATTC_SERV * p_srvc_cb;
    tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
...
    p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);

    if (p_srvc_cb != NULL)
    {
        switch (disc_type)
        {
            case GATT_DISC_SRVC_ALL:
            case GATT_DISC_SRVC_BY_UUID:
#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
                bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx);
#endif
                bta_gattc_explore_srvc(conn_id, p_srvc_cb);//pri service搜索完成就去搜索incldue service,pri service 的一系列屬性對應於一個service
                break;

            case GATT_DISC_INC_SRVC:
                bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb);//include service搜索完成就去搜索characteristic
                break;

            case GATT_DISC_CHAR:
#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
                bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx);
#endif
                bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb);//char 搜索完成搜索characteristic descriptor,若是搜索搜索失敗,那麼搜索下一個char dsp
                break;

            case GATT_DISC_CHAR_DSCPT:
                bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);//接着搜索下一個char 的char dsp,若是所有搜索完成,那麼搜索下一個服務
                break;
        }
    }
}

 

那這個的搜索的過程,能夠用下面的圖來簡單說明:

 那分析到這裏其實,正在的搜索過程已經結束了。咱們能想到的事,這些搜索的結果應該是保存在某個文件裏面的,這裏咱們體會一下,bluedroid 對於代碼的設計,其是如何週轉的。

從log 中,最後搜索 char desp 確定會遇到error response,預示着搜索char desp 完成,而後會調用到bta_gattc_char_dscpt_disc_cmpl,這裏面會引導咱們去搜索下一個服務,那若是這裏就是最後一個 服務呢?那麼這個時候就要去保存搜索到結果到cache 裏面:

static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
{
    tBTA_GATTC_ATTR_REC *p_rec = NULL;

    if (-- p_srvc_cb->total_char > 0)
    {
...
        /* start discoverying next characteristic for char descriptor */
        bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
    }
    else
    /* all characteristic has been explored, start with next service if any */
    {
        APPL_TRACE_ERROR("all char has been explored");
        p_srvc_cb->cur_srvc_idx ++;
        bta_gattc_explore_srvc (conn_id, p_srvc_cb);//搜索下一個服務
    }

 

繼續看 :

/*******************************************************************************
**
** Function         bta_gattc_explore_srvc
**
** Description      process the service discovery complete event
**
** Returns          status
**
*******************************************************************************/
static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb)
{
    tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
    tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);

    APPL_TRACE_DEBUG("Start service discovery: srvc_idx = %d", p_srvc_cb->cur_srvc_idx);

    p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc;

    if (p_clcb == NULL)
    {
        APPL_TRACE_ERROR("unknown connection ID");
        return;
    }
    /* start expore a service if there is service not been explored */
    if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc)
    {
...
            bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb);//繼續搜索
            return;
     }
    /* no service found at all, the end of server discovery*/
    LOG_WARN("%s no more services found", __func__);

    bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
    /* save cache to NV */
    p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;//這裏設置了cache的狀態機的狀態
    bta_gattc_co_cache_open(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT,
                            conn_id, TRUE);//保存到文件中/data/misc/bluetooth/cache*
}

 

咱們繼續看看保存的過程:

void bta_gattc_co_cache_open(BD_ADDR server_bda, UINT16 evt, UINT16 conn_id, BOOLEAN to_save)
{
    /* open NV cache and send call in */
    tBTA_GATT_STATUS    status = BTA_GATT_OK;
    if (!btm_sec_is_a_bonded_dev(server_bda) || !cacheOpen(server_bda, to_save))
        status = BTA_GATT_ERROR;

    BTIF_TRACE_DEBUG("%s() - status=%d", __FUNCTION__, status);//這裏status = 0,由於要保存,因此打開cache 文件確定是成功的
    bta_gattc_ci_cache_open(server_bda, evt, status, conn_id);
}

 

上面的函數,咱們以前也分析過,只是前面那次打開會失敗,

void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status,
                             UINT16 conn_id)
{
    tBTA_GATTC_CI_EVT  *p_evt;
    UNUSED(server_bda);

    if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL)
    {
        p_evt->hdr.event = evt;//發送event:BTA_GATTC_CI_CACHE_OPEN_EVT
        p_evt->hdr.layer_specific = conn_id;

        p_evt->status = status;
        bta_sys_sendmsg(p_evt);
    }
}

 

這個流程前面也分析過好屢次了,會執行bta_gattc_sm_execute 的狀態機,當前的狀態機是bta_gattc_st_discover 

/* BTA_GATTC_CI_CACHE_OPEN_EVT      */   {BTA_GATTC_CI_OPEN,            BTA_GATTC_DISCOVER_ST},
/* BTA_GATTC_CI_CACHE_LOAD_EVT      */   {BTA_GATTC_CI_LOAD,            BTA_GATTC_DISCOVER_ST},
/* BTA_GATTC_CI_CACHE_SAVE_EVT      */   {BTA_GATTC_CI_SAVE,            BTA_GATTC_DISCOVER_ST}

 

看到上面的三個 item,咱們已經能想到,接下來的流程,確定是 依次執行BTA_GATTC_CI_OPEN---->BTA_GATTC_CI_LOAD--->BTA_GATTC_CI_SAVE,咱們接着分析:當前的action是BTA_GATTC_CI_OPEN:

/*******************************************************************************
**
** Function         bta_gattc_start_load
**
** Description      start cache loading by sending callout open cache
**
** Returns          None.
**
*******************************************************************************/
void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    APPL_TRACE_DEBUG("bta_gattc_ci_open conn_id=%d server state=%d" ,
                      p_clcb->bta_conn_id, p_clcb->p_srcb->state);
...
    if (p_clcb->p_srcb->state == BTA_GATTC_SERV_SAVE)
    {
        if (p_data->ci_open.status == BTA_GATT_OK)
        {
            if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id))//save
            {
                p_data->ci_open.status = BTA_GATT_ERROR;
            }
        }
...
    }

 

調用 bta_gattc_cache_save 來完成保存的工做。這裏並非一次保存全部的屬性,而是分屢次才保存完畢。這裏追蹤代碼,發現並無BTA_GATTC_CI_LOAD  這個action,流程是open 以後就輪詢着執行BTA_GATTC_CI_SAVE,直到所有保存完畢。那代碼邏輯是如何判斷它已經所有保存結束的呢?當所有保存了以後 ,再去執行保存 的任務的時候會出錯,那麼這個時候 就認爲是已經保存所有的屬性。看看這一段的處理邏輯:

void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{

    if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id))//保存完畢或者出錯
    {
        p_clcb->p_srcb->attr_index = 0;
        bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0);//關閉cache文件
        bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);//發送BTA_GATTC_DISCOVER_CMPL_EVT
    }
}

 

看看其實現:

/* BTA_GATTC_DISCOVER_CMPL_EVT      */   {BTA_GATTC_DISC_CMPL,          BTA_GATTC_CONN_ST},

 這裏須要注意的一點的是 下一個狀態是BTA_GATTC_CONN_ST,從discovery 的狀態 進入到 conn狀態

/*******************************************************************************
**
** Function         bta_gattc_disc_cmpl
**
** Description      discovery on server is finished
**
** Returns          None.
**
*******************************************************************************/
void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATTC_DATA *p_q_cmd = p_clcb->p_q_cmd;
    UNUSED(p_data);

#if BLE_INCLUDED == TRUE
    if(p_clcb->transport == BTA_TRANSPORT_LE)
        L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, TRUE);//enable update
#endif
    p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;//設置狀態是idle
    p_clcb->disc_active = FALSE;//設置標誌位

    if (p_clcb->status != GATT_SUCCESS)
    {
        /* clean up cache */
   ...
        }
    /* release pending attribute list buffer */
    utl_freebuf((void **)&p_clcb->p_srcb->p_srvc_list);

    if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING)
    {
        /* start discovery again */
        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
    }
    /* get any queued command to proceed */
    else if (p_q_cmd != NULL)//這裏是沒有來得及執行的命令
    {

p_clcb->p_q_cmd = NULL;

bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd);

/* if the command executed requeued the cmd, we don't
* want to free the underlying buffer that's being
* referenced by p_clcb->p_q_cmd
*/
if (p_q_cmd != p_clcb->p_q_cmd) {
utl_freebuf((void **)&p_q_cmd);
}


    }

 分析到這裏,咱們先暫停一下,分析另一個問題,以前咱們在gatt open結束以後執行了bta_gattc_conn,這裏有第二點,咱們一直沒有分析,咱們如今來分析一下

2. bta_gattc_send_open_cback(p_clcb->p_rcb,BTA_GATT_OK,p_clcb->bda,p_clcb->bta_conn_id,p_clcb->transport,p_clcb->p_srcb->mtu);

/*******************************************************************************
**
** Function         bta_gattc_send_open_cback
**
** Description      send open callback
**
** Returns
**
*******************************************************************************/
void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
                                BD_ADDR remote_bda, UINT16 conn_id,
                                tBTA_TRANSPORT transport, UINT16 mtu)
{
    tBTA_GATTC      cb_data;

    if (p_clreg->p_cback)
    {
        memset(&cb_data, 0, sizeof(tBTA_GATTC));

        cb_data.open.status = status;
        cb_data.open.client_if = p_clreg->client_if;
        cb_data.open.conn_id = conn_id;
        cb_data.open.mtu = mtu;
        cb_data.open.transport = transport;
        bdcpy(cb_data.open.remote_bda, remote_bda);

        (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data);//回調前面已經註冊
    }
}

 

這裏回調就是bta_dm_gattc_callback :

static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
{
    APPL_TRACE_DEBUG("bta_dm_gattc_callback event = %d", event);

    switch (event)
    {
        case BTA_GATTC_REG_EVT:
            APPL_TRACE_DEBUG("BTA_GATTC_REG_EVT client_if = %d",  p_data->reg_oper.client_if);
            if (p_data->reg_oper.status == BTA_GATT_OK)
                bta_dm_search_cb.client_if = p_data->reg_oper.client_if;
            else
                bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF;
            break;

        case BTA_GATTC_OPEN_EVT:
            bta_dm_proc_open_evt(&p_data->open);
            break;
...

 

繼續看:

/*******************************************************************************
**
** Function         bta_dm_proc_open_evt
**
** Description      process BTA_GATTC_OPEN_EVT in DM.
**
** Parameters:
**
*******************************************************************************/
void bta_dm_proc_open_evt(tBTA_GATTC_OPEN *p_data)
{
    UINT8           *p1;
    UINT8           *p2;

    p1 = bta_dm_search_cb.peer_bdaddr;
    p2 = p_data->remote_bda;
...
    bta_dm_search_cb.conn_id = p_data->conn_id;

    if (p_data->status == BTA_GATT_OK)
    {
        btm_dm_start_disc_gatt_services(p_data->conn_id);//start discovery
    }
    else
    {
        bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status);
    }
}

 

上面調用,btm_dm_start_disc_gatt_services 進行搜索,其實按照咱們上面的分析,GATT open 之後 就緊接着執行cache 的操做,對cache 進行fresh,那麼cache 被刪除打開cache (R)就會失敗,會觸發GATT的discovery,那也就是說其實bluedroid 如今已經在着手作discovery的工做了,如今又要進行discovery 的工做,還能再次開展嗎?咱們想想,其實應該是先queue 該命令,而後等上一次的GATT discovery 工做完成了,再繼續當前的工做。

咱們看看bluedroid 的處理:

static void btm_dm_start_disc_gatt_services (UINT16 conn_id)
{
    tBT_UUID    *p_uuid = bta_dm_search_cb.p_srvc_uuid +
                          bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search;

    p_uuid = bta_dm_search_cb.p_srvc_uuid +
             bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search;

    /* always search for all services */
    BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid);
}

 

繼續看:

void BTA_GATTC_ServiceSearchRequest (UINT16 conn_id, tBT_UUID *p_srvc_uuid)
{
    tBTA_GATTC_API_SEARCH  *p_buf;
    UINT16  len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID);

    if ((p_buf = (tBTA_GATTC_API_SEARCH *) GKI_getbuf(len)) != NULL)
    {
        memset(p_buf, 0, len);

        p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT;//發送GATT的event
        p_buf->hdr.layer_specific = conn_id;

        if (p_srvc_uuid)
        {
            p_buf->p_srvc_uuid = (tBT_UUID *)(p_buf + 1);
            memcpy(p_buf->p_srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID));
        }
        else
            p_buf->p_srvc_uuid = NULL;

        bta_sys_sendmsg(p_buf);
    }
    return;
}

 

看看該event是被如何處理的:

/* BTA_GATTC_API_SEARCH_EVT         */   {BTA_GATTC_Q_CMD,              BTA_GATTC_DISCOVER_ST},

 

如咱們預期,這個命令被queue住了,這就是 咱們上面爲何 在bta_gattc_disc_cmpl 的時候出現
 

    /* get any queued command to proceed */
    else if (p_q_cmd != NULL)
    {
        p_clcb->p_q_cmd = NULL;

        bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd);
        /* if the command executed requeued the cmd, we don't
         * want to free the underlying buffer that's being
         * referenced by p_clcb->p_q_cmd
         */
        if (p_q_cmd != p_clcb->p_q_cmd) {
            utl_freebuf((void **)&p_q_cmd);
        }
    }

 

 這個被queue住的命令(BTA_GATTC_API_SEARCH_EVT)得以繼續執行,根據上面的分析當前的狀態已是connection的狀態,那麼確定是不會再次被queue了,咱們看bluedroid的實現:

/* BTA_GATTC_API_SEARCH_EVT         */   {BTA_GATTC_SEARCH,             BTA_GATTC_CONN_ST},

 

 看真正執行的函數:

/*******************************************************************************
**
** Function         bta_gattc_search
**
** Description      start a search in the local server cache
**
** Returns          None.
**
*******************************************************************************/
void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATT_STATUS    status = GATT_INTERNAL_ERROR;
    tBTA_GATTC cb_data;

    if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache)
    {
        status = BTA_GATT_OK;
        /* search the local cache of a server device */
        bta_gattc_search_service(p_clcb, p_data->api_search.p_srvc_uuid);//這裏去查找cache
    }
    cb_data.search_cmpl.status  = status;//這裏發現只要有cache,那麼status就是ok的
    cb_data.search_cmpl.conn_id = p_clcb->bta_conn_id;

    /* end of search or no server cache available */
    ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT,  &cb_data);
}//執行回調

 

上面的search的流程實際上是 分爲兩部分,

  1. 到cache 裏面去查找。
  2. 找到了以後調用回調函數上報結果,設計的到的event :BTA_GATTC_SEARCH_RES_EVT 以及BTA_GATTC_SEARCH_CMPL_EVT

到cache 裏面查找的過程這裏不分析了,咱們直接看看上報的過程:

static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
{
    APPL_TRACE_DEBUG("bta_dm_gattc_callback event = %d", event);
...
    case BTA_GATTC_SEARCH_RES_EVT:
            bta_dm_gatt_disc_result(p_data->srvc_res.service_uuid.id);
            break;

        case BTA_GATTC_SEARCH_CMPL_EVT:
            if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)
                bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id, p_data->search_cmpl.status);
            break;

 

 這裏都是一層一層往上報的:bta_dm_gatt_disc_result:

/*******************************************************************************
**
** Function         bta_dm_gatt_disc_result
**
** Description      This function process the GATT service search result.
**
** Parameters:
**
*******************************************************************************/
static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id)
{
    tBTA_DM_SEARCH   result;
...
    if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)//彙報給上層
    {

        /* send result back to app now, one by one */
        bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
        BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1));
        result.disc_ble_res.bd_name[BD_NAME_LEN] = 0;
        memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID));

        bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);//進一步往上報
    }
}

 

 

又看到熟悉的上報函數:bta_dm_search_cb.p_search_cback  這裏搜索服務,其實執行的是bte_dm_search_services_evt:咱們看其對於搜索結果的處理:

        case BTA_DM_DISC_BLE_RES_EVT:
             BTIF_TRACE_DEBUG("%s:, services 0x%x)", __FUNCTION__,
                                p_data->disc_ble_res.service.uu.uuid16);
             bt_uuid_t  uuid;
             int i = 0;
             int j = 15;
             if (p_data->disc_ble_res.service.uu.uuid16 == UUID_SERVCLASS_LE_HID)//判斷是不是hogp:#define UUID_SERVCLASS_LE_HID   0x1812     /*  HID over LE */
             {
                BTIF_TRACE_DEBUG("%s: Found HOGP UUID",__FUNCTION__);
                bt_property_t prop;
                bt_bdaddr_t bd_addr;
                char temp[256];
                bt_status_t ret;

                bta_gatt_convert_uuid16_to_uuid128(uuid.uu,p_data->disc_ble_res.service.uu.uuid16);

                while(i < j )
                {
                    unsigned char c = uuid.uu[j];
                    uuid.uu[j] = uuid.uu[i];
                    uuid.uu[i] = c;
                    i++;
                    j--;
                }

                uuid_to_string_legacy(&uuid, temp);
                LOG_INFO("%s uuid:%s", __func__, temp);

                bdcpy(bd_addr.address, p_data->disc_ble_res.bd_addr);
                prop.type = BT_PROPERTY_UUIDS;
                prop.val = uuid.uu;
                prop.len = MAX_UUID_SIZE;

                /* Also write this to the NVRAM *///這裏只是把hogp的uuid 寫到config裏面了
                ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
                ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);

                /* Send the event to the BTIF */
                HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
                                 BT_STATUS_SUCCESS, &bd_addr, 1, &prop);//傳遞給JNI

            }

 

這裏對於 BTA_DM_DISC_BLE_RES_EVT處理,咱們知道了其最主要的功能是將hogp的uuid 保存到bt_config.conf裏面了,而且經過HAL_CBACK 通知到JNI層。

咱們繼續看BTA_GATTC_SEARCH_CMPL_EVT的狀況:這裏發現這一塊 Google 原生的bluedroid 是沒有實現的,是留給廠商本身實現的,那咱們就分析我手上代碼的一個實現實例:

case BTA_DM_DISC_CMPL_EVT:
            /* fixme */
        {
            bt_bdaddr_t bd_addr;
            bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
            tBT_DEVICE_TYPE device_type;
            tBLE_ADDR_TYPE addr_type;
            BTM_ReadDevInfo(p_data->disc_res.bd_addr,&device_type,&addr_type);
            BOOLEAN is_hid = check_cod_hid(&bd_addr,COD_HID_MAJOR);//判斷是不是hid,這個cod就是根據bt_config.conf中的device class
            if(is_hid && device_type == BT_DEVICE_TYPE_BLE)
            {
                if((pairing_cb.state == BT_BOND_STATE_BONDING) && (bdcmp(p_data->disc_res.bd_addr, pairing_cb.bd_addr) == 0))
                {
                    if((p_data->disc_res.result == BTA_SUCCESS))
                    {
                         bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);通報狀態
                    }
                    else
                    {
                          btif_dm_remove_ble_bonding_keys();//若是服務發現失敗,那麼刪除link key
                          bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);//而且上報 未綁定狀態
                    }
                }
            }
       }

 

這段代碼也是很容易懂的,簡單看一下bond_state_changed 吧:

static void bond_state_changed(bt_status_t status, bt_bdaddr_t *bd_addr, bt_bond_state_t state)
{
...
    HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, bd_addr, state);//上報bond狀態
    if (state == BT_BOND_STATE_BONDING)
    {
        pairing_cb.state = state;
        bdcpy(pairing_cb.bd_addr, bd_addr->address);
    } else {
        if (!pairing_cb.sdp_attempts)
            memset(&pairing_cb, 0, sizeof(pairing_cb));//清除pairing_cb
        else
            BTIF_TRACE_DEBUG("%s: BR-EDR service discovery active", __func__);
    }
}

 

 那到這裏,上報了 bond狀態以後, GATT的搜索的過程就徹底結束了。

相關文章
相關標籤/搜索