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

  • 相关阅读:
    linux 解压tgz 文件指令
    shell 脚本没有执行权限 报错 bash: ./myshell.sh: Permission denied
    linux 启动solr 报错 Your Max Processes Limit is currently 31202. It should be set to 65000 to avoid operational disruption.
    远程查询批量导入数据
    修改 MZTreeView 赋权节点父节点选中子节点自动选中的问题
    关于乱码的问题解决记录
    我的网站优化之路
    对设计及重构的一点反思
    我的五年岁月
    奔三的路上
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9366091.html
Copyright © 2011-2022 走看看