zoukankan      html  css  js  c++  java
  • Bluedroid 函数分析:BTA_GATTC_Open

    进行GATT 通信,首先要打开GATT 的通道。下面我们分析BTA_GATTC_Open 这个函数:

    这个函数在bta_gattc_api.c 文件中定义,这个是一个接口文件,里面没有做真正的open的动作,最终还是要将open 的事件传递到BTE层面:

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

    套路都一样,继续看:

    /*******************************************************************************
    **
    ** 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 找到具体要执行的函数。

    我这里分析的case,是BLe 设备刚配对完来进行GATT 流程的执行,这个时候的GATTC的state是idle:

    对应的action = BTA_GATTC_OPEN,下一个状态是BTA_GATTC_W4_CONN_ST ,

    执行的函数是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,

    下面继续看:

    /*******************************************************************************
    **
    ** 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的搜索的过程就完全结束了。

  • 相关阅读:
    ubuntu问题集锦
    得把这个事情坚持下来
    海贼王有啥好看的?
    虚拟机网络连不上怎么办?
    耍耍Windows Live Writer
    Jquey模糊选择
    JS网址正则验证
    PowerDesigner 同步Name到Comment 及 同步 Comment 到Name
    进程调用系统默认和邮件客户端并附加指定文件
    Form.DialogResult 属性
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9366091.html
Copyright © 2011-2022 走看看