connectGatt(4/4):bta_gattc_start_discover

必务先看“BLE(3/6):连接之btif_gattc_open”,看过它才能清楚Android BLE何时调用bta_gattc_start_discover。

bta_gattc_conn主要做了两件事:

  1. bta_gattc_start_discover(...)。从ble peripheral获取service、characteristic数据。
  2. bta_gattc_send_open_cback(...)。调用JNI注册的回调函数。 

为能更直观理解,本文引入一个gatt实例。

[Service]
UUID: 0x1801
PRIMARY SERVICE
  [Unknown Characteristic]
  UUID: 0x2a05
  Properties: INDICATE
---
[Service]
UUID: 0x1800
PRIMARY SERVICE
  [Unknown Characteristic]
  UUID: 0x2a00
  Properties: READ

  [Unknown Characteristic]
  UUID: 0x2a01
  Properties: READ

  [Unknown Characteristic]
  UUID: 0x2aa6
  Properties: READ
---
[Service]
UUID: 0x5356
PRIMARY SERVICE
  [Unknown Characteristic]
  UUID: 0xfd02
  Properties: READ

  [Unknown Characteristic]
  UUID: 0xfd03
  Properties: NOTIFY
  Descriptors
    [Client Characteristic Configuration]
    UUID: 0x2902
    Properties: NOTIFY

  [Unknown Characteristic]
  UUID: 0xfd01
  Properties: READ, WRITE, NOTIFY

对应这gatt,当发现结束后,bta_gattc_explore_srvc_finished(...)中bta_gattc_display_cache_server()输出的logcat。

<================Start Server Cache =============>
Service: handle=0x0001, end_handle=0x0005, uuid=00001801-0000-1000-8000-00805f9b34fb
    Characteristic: declaration_handle=0x0002, value_handle=0x0003, uuid=00002a05-0000-1000-8000-00805f9b34fb, prop=0x20
Service: handle=0x0014, end_handle=0x001c, uuid=00001800-0000-1000-8000-00805f9b34fb
    Characteristic: declaration_handle=0x0015, value_handle=0x0016, uuid=00002a00-0000-1000-8000-00805f9b34fb, prop=0x02
    Characteristic: declaration_handle=0x0017, value_handle=0x0018, uuid=00002a01-0000-1000-8000-00805f9b34fb, prop=0x02
    Characteristic: declaration_handle=0x0019, value_handle=0x001a, uuid=00002aa6-0000-1000-8000-00805f9b34fb, prop=0x02
Service: handle=0x0028, end_handle=0xffff, uuid=00005356-0000-1000-8000-00805f9b34fb
    Characteristic: declaration_handle=0x0029, value_handle=0x002a, uuid=0000fd02-0000-1000-8000-00805f9b34fb, prop=0x02
    Characteristic: declaration_handle=0x002b, value_handle=0x002c, uuid=0000fd03-0000-1000-8000-00805f9b34fb, prop=0x10
        Descriptor: handle=0x002d, uuid=00002902-0000-1000-8000-00805f9b34fb
    Characteristic: declaration_handle=0x002e, value_handle=0x002f, uuid=0000fd01-0000-1000-8000-00805f9b34fb, prop=0x1a
<================End Server Cache =============>
  • 进入discover时的bta状态是BTA_GATTC_DISCOVER_ST,经过discover后,进入BTA_GATTC_CONN_ST。
  • discover任务是从ble peripheral获取service、characteristic、descriptor,存储在BLE HAL内存:p_clcb->p_srcb。过程中不会回调JNI函数。
  • discover流程。1)一次req/resp搜索出所有primary service,然后对每个service依次进行单一service发现流程。2)单一service发现。一次Req/Resp搜索include service;然后一次Req/Resp搜出所有Characteristic;对每个char,一次Req/Resp搜出Descriptors。
  • 执行完一步操作后,往往会调用gatt_end_operation。该函数的主要功能是触发下一步操作,而这是通过回调bta_gattc_disc_cmpl_cback。
  • 会把discover到的gatt db存储到cache文件,像/data/misc/bluetooth/gatt_cache_cc4b731d7f1d,前提是配对了该peripheral,即条件“btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)”返回true。以目前常见的手机连接ble peripernal,是不配对的,即不会生成cache文件。

对示例,1 + (2+1) + (2+3) + (2+3) = 14,须14个packet req/resp。以下是每次req/resp对应的功能,最后一列是gatt_client_handle_server_rsp中执行的函数。

  1. 搜出3个service,每个service有s_handle、e_handle、uuid。gatt_client_handle_server_rsp中执行的是gatt_process_error_rsp。
  2. [#0单一service发现]搜索include service,结果没有。gatt_process_error_rsp。
  3. [#0单一service发现]搜索所有Characteristic,有1个。gatt_process_read_by_type_rsp。
  4. [#0单一service发现]搜索#0号Char中的descriptor,结果没有。gatt_process_read_by_type_rsp。
  5. [#1单一service发现]搜索include service,结果没有。gatt_process_error_rsp。
  6. [#1单一service发现]搜索所有Characteristic,有3个。gatt_process_read_by_type_rsp。
  7. [#1单一service发现]搜索#0号Char中的descriptor,结果没有。gatt_process_error_rsp。
  8. [#1单一service发现]搜索#1号Char中的descriptor,结果没有。gatt_process_error_rsp。
  9. [#1单一service发现]搜索#2号Char中的descriptor,结果没有。gatt_process_error_rsp。
  10. [#2单一service发现]搜索include service,结果没有。gatt_process_error_rsp。
  11. [#2单一service发现]搜索所有Characteristic,有3个。gatt_process_read_by_type_rsp。
  12. [#2单一service发现]搜索#0号Char中的descriptor,结果没有。gatt_process_error_rsp。
  13. [#2单一service发现]搜索#1号Char中的descriptor,有一个。gatt_process_read_info_rsp
  14. [#2单一service发现]搜索#2号Char中的descriptor,结果没有。gatt_process_error_rsp。

接下开始bta_gattc_start_discover过程解析。

<aosp>/system/bt/bta/gatt/bta_gattc_act.cc
------
void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
                              UNUSED_ATTR const tBTA_GATTC_DATA* 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) {
      /* set all srcb related clcb into discovery ST */
      // 复位一些标记位和数据, 包括把p_clcb->state改为BTA_GATTC_DISCOVER_ST
      bta_gattc_set_discover_st(p_clcb->p_srcb);

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

      /* read db hash if db hash characteristic exists */
      if (bta_gattc_is_robust_caching_enabled() &&
          p_clcb->p_srcb->srvc_hdl_db_hash && bta_gattc_read_db_hash(p_clcb)) {
        LOG(INFO) << __func__
                  << ": pending service discovery, read db hash first";
        p_clcb->p_srcb->srvc_hdl_db_hash = false;
        return;
      }
      // 开始搜索工作(Start primary service discovery)
      bta_gattc_start_discover_internal(p_clcb);
    } else {
      LOG(ERROR) << "unknown device, can not start discovery";
    }
  }
  /* pending operation, wait until it finishes */
  else {
    p_clcb->auto_update = BTA_GATTC_DISC_WAITING;

    if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE)
      p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */
  }
}

void bta_gattc_start_discover_internal(tBTA_GATTC_CLCB* p_clcb) {
  if (p_clcb->transport == BT_TRANSPORT_LE)
    L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, false);

  bta_gattc_init_cache(p_clcb->p_srcb);
  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 != GATT_SUCCESS) {
    LOG(ERROR) << "discovery on server failed";
    bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
  } else
    p_clcb->disc_active = true;
}

bta_gattc_start_discover --> bta_gattc_start_discover_internal --> bta_gattc_discover_pri_service,我们看到其最终执行了bta_gattc_discover_pri_service ,其中参数disc_type是GATT_DISC_SRVC_ALL,表示搜索所有的service。

<aosp>/system/bt/bta/gatt/bta_gattc_cache.cc
------
tGATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
                                            tBTA_GATTC_SERV* p_server_cb,
                                            tGATT_DISC_TYPE disc_type) {
  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
  if (!p_clcb) return GATT_ERROR;

  if (p_clcb->transport == BT_TRANSPORT_LE) {
    // 此时disc_type: GATT_DISC_SRVC_ALL
    return GATTC_Discover(conn_id, disc_type, 0x0001, 0xFFFF);
  }

  // only for Classic transport
  return bta_gattc_sdp_service_disc(conn_id, p_server_cb);
}

执行GATTC_Discover:This function is called to do a discovery procedure on ATT server

<aosp>/system/bt/stack/gatt/gatt_api.cc
------
tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
                            uint16_t start_handle, uint16_t end_handle) {
  return GATTC_Discover(conn_id, disc_type, start_handle, end_handle,
                        Uuid::kEmpty);
}

4参数版本调用5参数时,第5个参数传Uuid::kEmpty。
tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
                            uint16_t start_handle, uint16_t end_handle,
                            const Uuid& uuid) {
  tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
  uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
  tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
  tGATT_REG* p_reg = gatt_get_regcb(gatt_if);

  ...
  if (gatt_is_clcb_allocated(conn_id)) {
    LOG(ERROR) << __func__ << "GATT_BUSY conn_id = " << +conn_id;
    return GATT_BUSY;
  }

  tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
  ...
  // 这个opcode 并非ATT协议里面的opcode,只是代码实现的一种抽象表达,常用于在GATT rsp的处理中做逻辑判断
  p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
  // 这个实际对应于ATT的各种opcode
  p_clcb->op_subtype = disc_type;
  p_clcb->s_handle = start_handle;
  p_clcb->e_handle = end_handle;
  p_clcb->uuid = uuid;

  // 执行discovery行为,一层一层组包
  gatt_act_discovery(p_clcb);
  return GATT_SUCCESS;
}

<aosp>/system/bt/stack/gatt/gatt_cl.cc
------
void gatt_act_discovery(tGATT_CLCB* p_clcb) {
  uint8_t op_code = disc_type_to_att_opcode[p_clcb->op_subtype];

  if (p_clcb->s_handle > p_clcb->e_handle || p_clcb->s_handle == 0) {
    LOG_DEBUG("Completed GATT discovery of all handle ranges");
    gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
    return;
  }

  tGATT_CL_MSG cl_req;
  memset(&cl_req, 0, sizeof(tGATT_CL_MSG));

  cl_req.browse.s_handle = p_clcb->s_handle;
  cl_req.browse.e_handle = p_clcb->e_handle;

  if (disc_type_to_uuid[p_clcb->op_subtype] != 0) {
    cl_req.browse.uuid =
        bluetooth::Uuid::From16Bit(disc_type_to_uuid[p_clcb->op_subtype]);
  }

  if (p_clcb->op_subtype ==
      GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
  {
    ...
  }

  tGATT_STATUS st = attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, op_code, &cl_req);
  if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) {
    LOG_WARN("Unable to send ATT message");
    gatt_end_operation(p_clcb, GATT_ERROR, NULL);
  }
}

gatt_act_discovery向ble peripheral发起一次发现操作。参数指定了要发现是什么内容。最后会通过L2cap 的ATT通道下发下去。发送请求、接收应答流程参考“BLE(5/6):HCI”。这里只要明白,接收到应答后,ble协议栈会调用gatt_client_handle_server_rsp。

为描述方便,“DISCOVERY && SRVC_ALL”表示“p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_SRVC_ALL”,即正处在发现阶段,目的是获取该peripherl有哪些service。

<aosp>/system/bt/stack/gatt/gatt_cl.c
------
void gatt_client_handle_server_rsp(tGATT_TCB& tcb, uint16_t cid,
                                   uint8_t op_code, uint16_t len,
                                   uint8_t* p_data) {
  uint16_t payload_size = gatt_tcb_get_payload_size_rx(tcb, cid);  

  uint8_t cmd_code = 0;
  tGATT_CLCB* p_clcb = gatt_cmd_dequeue(tcb, cid, &cmd_code);
  uint8_t rsp_code = gatt_cmd_to_rsp_code(cmd_code);
  
  gatt_stop_rsp_timer(p_clcb);
  p_clcb->retry_count = 0;

  /* the size of the message may not be bigger than the local max PDU size*/
  /* The message has to be smaller than the agreed MTU, len does not count
   * op_code */
  if (len >= payload_size) {
    ...
  } else {
    switch (op_code) {
      case GATT_RSP_ERROR:
        gatt_process_error_rsp(tcb, p_clcb, op_code, len, p_data);
        break;

      case GATT_RSP_MTU: /* 2 bytes mtu */
        gatt_process_mtu_rsp(tcb, p_clcb, len, p_data);
        break;

      case GATT_RSP_FIND_INFO:
        gatt_process_read_info_rsp(tcb, p_clcb, op_code, len, p_data);
        break;

      case GATT_RSP_READ_BY_TYPE:
      case GATT_RSP_READ_BY_GRP_TYPE:
        // “DISCOVERY && SRVC_ALL”时,op_code==GATT_RSP_READ_BY_GRP_TYPE,进这入口
        gatt_process_read_by_type_rsp(tcb, p_clcb, op_code, len, p_data);
        break;

      case GATT_RSP_READ:
      case GATT_RSP_READ_BLOB:
      case GATT_RSP_READ_MULTI:
      case GATT_RSP_READ_MULTI_VAR:
        gatt_process_read_rsp(tcb, p_clcb, op_code, len, p_data);
        break;

      case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
        gatt_process_find_type_value_rsp(tcb, p_clcb, len, p_data);
        break;

      case GATT_RSP_WRITE:
        gatt_process_handle_rsp(p_clcb);
        break;

      case GATT_RSP_PREPARE_WRITE:
        gatt_process_prep_write_rsp(tcb, p_clcb, op_code, len, p_data);
        break;

      case GATT_RSP_EXEC_WRITE:
        gatt_end_operation(p_clcb, p_clcb->status, NULL);
        break;

      default:
        LOG(ERROR) << __func__ << ": Unknown opcode = " << std::hex << op_code;
        break;
    }
  }

  gatt_cl_send_next_cmd_inq(tcb);
}
图1 该peripherl有哪些service时的应答

图1显示了该peripherl有哪些service时的应答,5c:39:53:5b:5f:94是peripheral地址,22:22:13:ca:0d:00是center地址。注意当中“Opcode: Read By Group Type Response (0x11)”,对应gatt_client_handle_server_rsp中代码“op_code==GATT_RSP_READ_BY_GRP_TYPE”,于是执行gatt_process_read_by_type_rsp。

<aosp>/system/bt/stack/gatt/gatt_cl.c
------
void gatt_process_read_by_type_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
                                   uint8_t op_code, uint16_t len,
                                   uint8_t* p_data) {
  tGATT_DISC_RES result;
  tGATT_DISC_VALUE record_value;
  uint8_t *p = p_data, value_len, handle_len = 2;
  uint16_t handle = 0;

  // 第一个字节是表示后面有多少字节的length,对应图1中“00 11 06”中06
  STREAM_TO_UINT8(value_len, p);
  uint16_t payload_size = gatt_tcb_get_payload_size_rx(tcb, p_clcb->cid);
  ...

  while (len >= (handle_len + value_len)) {
    // 假设peripheral有三个service,那“DISCOVERY && SRVC_ALL”时,此while将循环三次。
    // 每个rsp,前两个字节都有handle。对“DISCOVERY && SRVC_ALL”,它就是s_handle。
    STREAM_TO_UINT16(handle, p);

    memset(&result, 0, sizeof(tGATT_DISC_RES));
    memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));

    result.handle = handle;
    result.type =
        bluetooth::Uuid::From16Bit(disc_type_to_uuid[p_clcb->op_subtype]);

    /* discover all services */
    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
        p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
        op_code == GATT_RSP_READ_BY_GRP_TYPE) {
      // 发现阶段。目的是获取该peripherl有哪些service,此处的两个字节是e_handle。
      STREAM_TO_UINT16(handle, p);

      if (!GATT_HANDLE_IS_VALID(handle)) {
        gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
        return;
      } else {
        // 读出的e_handle存储到record_value.group_value.e_handle。
        // record_value.group_value.service_type则存储着此个service的uuid。
        record_value.group_value.e_handle = handle;
        if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type,
                                      value_len, &p)) {
          LOG(ERROR) << "discover all service response parsing failure";
          break;
        }
      }
    }
    /* discover included service */
    else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
             p_clcb->op_subtype == GATT_DISC_INC_SRVC) {
      。。。
    }
    /* read by type */
    else if (p_clcb->operation == GATTC_OPTYPE_READ &&
             p_clcb->op_subtype == GATT_READ_BY_TYPE) {
      ...
    } else /* discover characterisitic */
    {
      // 单一service发现流程、从该service读取所含的characterisitic。
      // p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_READ_CHAR_VALUE
      STREAM_TO_UINT8(record_value.dclr_value.char_prop, p);
      STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
      if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) {
        gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
        return;
      }
      if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid,
                                    (uint16_t)(value_len - 3), &p)) {
        gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
        /* invalid format, and skip the result */
        return;
      }

      /* UUID not matching */
      if (!p_clcb->uuid.IsEmpty() &&
          !record_value.dclr_value.char_uuid.IsEmpty() &&
          record_value.dclr_value.char_uuid != p_clcb->uuid) {
        len -= (value_len + 2);
        continue; /* skip the result, and look for next one */
      }

      if (p_clcb->operation == GATTC_OPTYPE_READ)
      /* UUID match for read characteristic value */
      {
        /* only read the first matching UUID characteristic value, and
          discard the rest results */
        p_clcb->s_handle = record_value.dclr_value.val_handle;
        p_clcb->op_subtype |= 0x80;
        gatt_act_read(p_clcb, 0);
        return;
      }
    }
    len -= (value_len + handle_len);

    /* result is (handle, 16bits UUID) pairs */
    memcpy(&result.value, &record_value, sizeof(result.value));

    /* send callback if is discover procedure */
    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb) {
      // 把此得发现到的部分内容汇集到gatt db。
      // p_clcb->p_reg->app_cb.p_disc_res_cb这个函数指针指向bta_gattc_cache.c中实现的bta_gattc_disc_res_cback
      (*p_clcb->p_reg->app_cb.p_disc_res_cb)(
          p_clcb->conn_id, static_cast<tGATT_DISC_TYPE>(p_clcb->op_subtype), &result);
    }
  }

  // “GATTC_OPTYPE_DISCOVERY && GATT_DISC_SRVC_ALL”时,handle是最后一个service时的e_handle,
  // 它的值总是65535,加1后65536,由于s_handle是16位,65536会被归到0。
  p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);

  if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
    /* initiate another request */
    // 继续进行发现,直到err response
    gatt_act_discovery(p_clcb);
  } else /* read characteristic value */
  {
    gatt_act_read(p_clcb, 0);
  }
}

在发现阶段(p_clcb->operation == GATTC_OPTYPE_DISCOVERY),gatt_process_read_by_type_rsp可归纳为依次执行两个任务。

  1. 一个用于解析收到应答内容的while循环。每解析出一部分,就回调p_clcb->p_reg->app_cb.p_disc_res_cb,把这部分数据汇集到gatt数据库。
  2. 调用gatt_act_discovery(p_clcb)。触发后绪发现过程。

先说gatt_process_read_by_type_rsp第一个任务。每解析出一部分,像图1中的第一条“Attribute Data, Handle: 0x0001, ...”,就会调用p_disc_res_cb指向的回调函数,这个函数指针指向bta_gattc_cache.c中实现的bta_gattc_disc_res_cback。

<aosp>/system/bt/bta/gatt/bta_gattc_cache.cc
------
void bta_gattc_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
                              tGATT_DISC_RES* p_data) {
  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
  tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);

  if (!p_srvc_cb || !p_clcb || p_clcb->state != BTA_GATTC_DISCOVER_ST) return;

  switch (disc_type) {
    case GATT_DISC_SRVC_ALL:
    case GATT_DISC_SRVC_BY_UUID:
      // “GATTC_OPTYPE_DISCOVERY && GATT_DISC_SRVC_ALL”时,进这入口。
      p_srvc_cb->pending_discovery.AddService(
          p_data->handle, p_data->value.group_value.e_handle,
          p_data->value.group_value.service_type, true);
      break;

    case GATT_DISC_INC_SRVC:
      p_srvc_cb->pending_discovery.AddIncludedService(
          p_data->handle, p_data->value.incl_service.service_type,
          p_data->value.incl_service.s_handle,
          p_data->value.incl_service.e_handle);
      break;

    case GATT_DISC_CHAR:
      p_srvc_cb->pending_discovery.AddCharacteristic(
          p_data->handle, p_data->value.dclr_value.val_handle,
          p_data->value.dclr_value.char_uuid,
          p_data->value.dclr_value.char_prop);
      break;

    case GATT_DISC_CHAR_DSCPT:
      p_srvc_cb->pending_discovery.AddDescriptor(p_data->handle, p_data->type);
      break;

    case GATT_DISC_MAX:
    default:
      LOG_ERROR("Received illegal discovery item");
      break;
  }
}

p_srvc_cb->pending_discovery类型是gatt::DatabaseBuilder,就是此次发现要生成的最终gatt数据库。AddService方法是向该数据库添加一个service,换句话说,把此次发现到的部分数据补充到gatt数据库。注意:只是补充到p_srvc_cb->pending_discovery这个变量,不会写到cache文件,要读出整个gatt数据库后才写入。

说完补充gatt数据库,让看gatt_process_read_by_type_rsp第二个任务,执行gatt_act_discovery(p_clcb)。上面已贴过这函数,并且说了功能是调用attp_send_cl_msg,把参数p_clcb指定的要发现什么内容,通过L2cap的ATT通道发向peripheral。这里有个问题,此时p_clcb存储的还是发现所有servier这个任务(disc_type==GATT_DISC_SRVC_ALL),这个发现任务已经成功执行,难道还要再次执行?——当然不会,这就要看gatt_act_discovery一个“隐藏”功能,当“p_clcb->s_handle == 0”时,执行的是调用gatt_end_operation。

<aosp>/system/bt/stack/gatt/gatt_cl.cc
------
void gatt_act_discovery(tGATT_CLCB* p_clcb) {
  uint8_t op_code = disc_type_to_att_opcode[p_clcb->op_subtype];

  if (p_clcb->s_handle > p_clcb->e_handle || p_clcb->s_handle == 0) {
    LOG_DEBUG("Completed GATT discovery of all handle ranges");
    gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
    return;
  }
  ...
}

在gatt_process_read_by_type_rsp,“GATTC_OPTYPE_DISCOVERY && GATT_DISC_SRVC_ALL”时,handle是最后一个service时的e_handle,它的值总是65535,加1后65536,由于s_handle是16位,65536会被归到0。于是满足了“p_clcb->s_handle == 0”条件,执行的是调用gatt_end_operation。

<aosp>/system/bt/stack/gatt/gatt_utils.c
------
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;
  tGATTC_OPTYPE op = p_clcb->operation;
  tGATT_DISC_TYPE 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_t conn_id;
  uint8_t operation;

  memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));

  if (p_cmpl_cb != NULL && p_clcb->operation != 0) {
    ...

    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
      disc_type = static_cast<tGATT_DISC_TYPE>(p_clcb->op_subtype);
    }
  }

  osi_free_and_reset((void**)&p_clcb->p_attr_buf);

  operation = p_clcb->operation;
  conn_id = p_clcb->conn_id;
  gatt_stop_rsp_timer(p_clcb);

  gatt_clcb_dealloc(p_clcb);

  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);
  else
    LOG(WARNING) << __func__
                 << StringPrintf(
                        ": not sent out op=%d p_disc_cmpl_cb:%p p_cmpl_cb:%p",
                        operation, p_disc_cmpl_cb, p_cmpl_cb);
}

gatt_end_operation用于结束一次发现,并启动下一次发现。在发现阶段(op == GATTC_OPTYPE_DISCOVERY),它会调用p_clcb->p_reg->app_cb.p_disc_cmpl_cb,这个函数指针指向bta_gattc_disc_cmpl_cback。正是在这函数,会调用GATTC_Discover,从而改变p_clcb的operation、op_subtype、s_handle、e_handle、uuid,并把发现请求发现peripheral。

<aosp>/system/bt/bta/gatt/bta_gattc_cache.cc
------
void bta_gattc_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
                               tGATT_STATUS status) {
  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
  tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);

  if (p_clcb && (status != GATT_SUCCESS || p_clcb->status != GATT_SUCCESS)) {
    ...

    bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL);
    return;
  }

  if (!p_srvc_cb) return;

  switch (disc_type) {
    case GATT_DISC_SRVC_ALL:
    case GATT_DISC_SRVC_BY_UUID:
// definition of all services are discovered, now it's time to discover
// their content
#if (BTA_GATT_DEBUG == TRUE)
      bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
#endif
      // 已搜索出pri services,接下搜索第一个service的incldue service
      bta_gattc_explore_next_service(conn_id, p_srvc_cb);
      break;

    case GATT_DISC_INC_SRVC: {
      auto& service = p_srvc_cb->pending_discovery.CurrentlyExploredService();
      /* start discovering characteristic */
      // 已搜索出该service的include service,接着搜索该service的chara
      GATTC_Discover(conn_id, GATT_DISC_CHAR, service.first, service.second);
      break;
    }

    case GATT_DISC_CHAR: {
#if (BTA_GATT_DEBUG == TRUE)
      bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
#endif
      // 已搜索出该service的chara,接下搜索第一个chara的characteristic descriptor,
      // 如果搜索失败,那么搜索下一个char dsp
      bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
      break;
    }

    case GATT_DISC_CHAR_DSCPT:
      /* start discovering next characteristic for char descriptor */
      // 已搜索出该chara的descriptor,接着搜索下一个chara的char descriptor,
      // 如果全部搜索完成,那么搜索下一个服务
      bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
      break;
    case GATT_DISC_MAX:
    default:
      LOG_ERROR("Received illegal discovery item");
      break;
  }
}

“DISCOVERY && SRVC_ALL”时,首先执行bta_gattc_display_explore_record,这是一个调试辅助函数,logcat出的service,以下是一个示例

I/bt_stack: <================Start Explore Queue =============>
I/bt_stack: Service: handle=0x0001, end_handle=0x0005, uuid=00001801-0000-1000-8000-00805f9b34fb
I/bt_stack: Service: handle=0x0014, end_handle=0x001c, uuid=00001800-0000-1000-8000-00805f9b34fb
I/bt_stack: Service: handle=0x0028, end_handle=0xffff, uuid=00005356-0000-1000-8000-00805f9b34fb
I/bt_stack: <================ End Explore Queue =============>

logcat后,执行bta_gattc_explore_next_service:start exploring next service, or finish discovery if no more services left。留意下它最后会调用bta_gattc_explore_srvc_finished,当已发现整个gatt数据库后,便会执行到它。

<aosp>/system/bt/bta/gatt/bta_gattc_cache.cc
static void bta_gattc_explore_next_service(uint16_t conn_id,
                                           tBTA_GATTC_SERV* p_srvc_cb) {
  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);

  if (p_srvc_cb->pending_discovery.StartNextServiceExploration()) {
    const auto& service =
        p_srvc_cb->pending_discovery.CurrentlyExploredService();
    VLOG(1) << "Start service discovery";

    /* start discovering included services */
    // seriver.first是0x1(s_handle),service.second是0x5(e_handle)
    GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, service.first, service.second);
    return;
  }
  // No more services to discover

  // As part of service discovery, read the values of "Characteristic Extended
  // Properties" descriptor
  const auto& descriptors =
      p_srvc_cb->pending_discovery.DescriptorHandlesToRead();
  if (!descriptors.empty()) {
    ......

    // asynchronous continuation in bta_gattc_op_cmpl_during_discovery
    return;
  }

  bta_gattc_explore_srvc_finished(conn_id, p_srvc_cb);
}

首先调用pending_discovery.StartNextServiceExploration(),判断gatt数据库内是否还有未完成发现的service,有未完成的就返回true,否则false。

<aosp>/system/bt/bta/gatt/database_builder.cc
------
bool DatabaseBuilder::StartNextServiceExploration() {
  while (!services_to_discover.empty()) {
    auto handle_range = services_to_discover.begin();
    pending_service = *handle_range;
    services_to_discover.erase(handle_range);

    // Empty service declaration, nothing to explore, skip to next.
    if (pending_service.first == pending_service.second) continue;

    pending_characteristic = HANDLE_MIN;
    return true;
  }
  return false;
}

判断逻辑主要用了个变量:std::set<std::pair<uint16_t, uint16_t>> services_to_discover;

  1. 之前的bta_gattc_disc_res_cback中AddService,会执行services_to_discover.insert({handle, end_handle}),handle是s_handle。
  2. StartNextServiceExploration从services_to_discover取出service,这是一个等待进一步发现的service。把它赋给pending_server,并把该service从services_to_discover删除。
  3. 已发现完整个pending_server,继续调用这里的StartNextServiceExploration,让第二个service成为pending_server。
  4. 持续工作,当示例的3个service都发现结束后,那时services_to_discover已经空了,StartNextServiceExploration返回false,表示已发现完所有service。

pending_discovery.CurrentlyExploredService()返回的就是那个从services_to_discover移出、等待进一步发现的pending_server。对应到此时示例,那就是(handle=0x0001, end_handle=0x0005)的service。

得到待发现的pending_server后,这将开始新一轮单一service发现流程,这个流程首先是搜索include服务。分析到这里,贴上完整的gatt发现流程。 

  1.     搜索出所有pri service,然后对每个service依次进行单一service发现流程。(一对请求应答)
  2.     单一Service发现流程。先搜索include service;然后搜出所有UUID: Characteristic;对每个char,搜Descriptor。

GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, ...),这将开始新一轮单一service发现流程中的第一步:搜索include service。上面已分析过GATTC_Discover,于于收到GATT_DISC_INC_SRVC对应应答后怎么处理,后绪的发现chara,chara内的descriptor,这里不再深入了。

搜完最后一个service的最后一个descriptor后会发生什么?——还是会调用bta_gattc_explore_next_service,此时StartNextServiceExploration返回false,后面pending_discovery.DescriptorHandlesToRead()返回空,会执行bta_gattc_explore_srvc_finished。

<aosp>/system/bt/bta/gatt/bta_gattc_cache.cc
------
static void bta_gattc_explore_srvc_finished(uint16_t conn_id,
                                            tBTA_GATTC_SERV* p_srvc_cb) {
  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
  
  /* no service found at all, the end of server discovery*/
  LOG(INFO) << __func__ << ": service discovery finished";

  p_srvc_cb->gatt_database = p_srvc_cb->pending_discovery.Build();

#if (BTA_GATT_DEBUG == TRUE)
  bta_gattc_display_cache_server(p_srvc_cb->gatt_database);
#endif
  /* save cache to NV */
  p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;

  if (btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)) {
    bta_gattc_cache_write(p_clcb->p_srcb->server_bda,
                          p_clcb->p_srcb->gatt_database.Serialize());
  }

  // After success, reset the count.
  if (bta_gattc_is_robust_caching_enabled()) {
    LOG(INFO) << __func__
              << ": service discovery succeed, reset count to zero, conn_id="
              << loghex(conn_id);
    p_srvc_cb->srvc_disc_count = 0;
  }

  bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS);
}

对connectGatt导致的bta_gattc_disc_cmpl,参数p_srvc_cb和p_clcb->p_srcb是一样的,指向同一个tBTA_GATTC_SERV。bta_gattc_explore_srvc_finished依次执行三个任务。

  1. p_srvc_cb->gatt_database = p_srvc_cb->pending_discovery.Build()。pending_discovery存储着发现过程中生成的gatt数据库,调用Build()生成要用于后绪操作的gatt_database,Database。在Build(),同时会清空pending_discovery。
  2. 判断该periperhal是否配对过,如果是,调用bta_gattc_cache_write存储cache到文件。对通常的ios、android连接,是没有配对过的。cache文件名示例:/data/misc/bluetooth/gatt_cache_cc4b731d7f1d,文件名中的cc4b731d7f1d是mac地址。
  3. 调用bta_gattc_reset_discover_st,执行状态机,状态最终变换BTA_GATTC_CONN_ST。

前两个较简单,让看下第三步bta_gattc_reset_discover_st。

<aosp>/system/bt/bta/gatt/bta_gattc_act.cc
------
void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb, tGATT_STATUS status) {
  for (uint8_t i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
    if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
      bta_gattc_cb.clcb[i].status = status;
      bta_gattc_sm_execute(&bta_gattc_cb.clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT,
                           NULL);
    }
  }
}

针对此刻的状态转换,bta的state是st_discovery,意味着状态表是bta_gattc_st_discover,收到BTA_GATTC_DISCOVER_CMPL_EVT事件,查表可知action是BTA_GATTC_DISC_CMPL,下一个状态是BTA_GATTC_CONN_ST。action是BTA_GATTC_OPEN时执行的函数是bta_gattc_disc_cmpl。

<aosp>/system/bt/bta/gatt/bta_gattc_act.cc
------
void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
                         UNUSED_ATTR const tBTA_GATTC_DATA* p_data) {
  const tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd;

  if (p_clcb->transport == BT_TRANSPORT_LE)
    L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, true);
  p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
  p_clcb->disc_active = false;

  if (p_clcb->p_srcb) {
    p_clcb->p_srcb->pending_discovery.Clear();
  }

  if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
    ...
  }
  /* get any queued command to proceed */
  else if (p_q_cmd != NULL) {
    // p_q_cmd往往是NULL。如果不是NULL,极可能是p_q_cmd->hdr.event==BTA_GATTC_API_SEARCH_EVT,
    // 意味着app调用了BluetoothGatt.discoverServices,此时如何处理参考“BLE(5/6):class BluetoothGatt”。
    p_clcb->p_q_cmd = NULL;
    /* execute pending operation of link block still present */
    if (L2CA_IsLinkEstablished(p_clcb->p_srcb->server_bda, p_clcb->transport)) {
      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) osi_free_and_reset((void**)&p_q_cmd);
  }

  if (p_clcb->p_rcb->p_cback) {
    tBTA_GATTC bta_gattc;
    bta_gattc.remote_bda = p_clcb->p_srcb->server_bda;
    (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SRVC_DISC_DONE_EVT, &bta_gattc);
  }
}

p_q_cmd往往是NULL,bta_gattc_start_discover就结束了。p_q_cmd什么时候不是NULL?——discover需要花点时间,它是连接(btif_gattc_open)的一部分,而在结束discover之前,app极可能已收到newState是 BluetoothProfile.STATE_CONNECTED的onConnectionStateChange,并调用了BluetoothGatt操作,像discoverServices()。一旦discover没完成就调用discoverServices(),执行bta_gattc_disc_cmpl时,p_q_cmd便就存储着discoverServices()。此时p_q_cmd->hdr.event==BTA_GATTC_API_SEARCH_EVT,这时要调用bta_gattc_sm_execute,启动收到BTA_GATTC_API_SEARCH_EVT事件时状态机。BTA_GATTC_CONN_ST状态下如何处理BTA_GATTC_API_SEARCH_EVT参考“BLE(5/6):class BluetoothGatt”中discoverServices时的bta_gattc_sm_execute。

全部评论: 0

    写评论: