必务先看“BLE(3/6):连接之btif_gattc_open”,看过它才能清楚Android BLE何时调用bta_gattc_start_discover。
bta_gattc_conn主要做了两件事:
- bta_gattc_start_discover(...)。从ble peripheral获取service、characteristic数据。
- 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中执行的函数。
- 搜出3个service,每个service有s_handle、e_handle、uuid。gatt_client_handle_server_rsp中执行的是gatt_process_error_rsp。
- [#0单一service发现]搜索include service,结果没有。gatt_process_error_rsp。
- [#0单一service发现]搜索所有Characteristic,有1个。gatt_process_read_by_type_rsp。
- [#0单一service发现]搜索#0号Char中的descriptor,结果没有。gatt_process_read_by_type_rsp。
- [#1单一service发现]搜索include service,结果没有。gatt_process_error_rsp。
- [#1单一service发现]搜索所有Characteristic,有3个。gatt_process_read_by_type_rsp。
- [#1单一service发现]搜索#0号Char中的descriptor,结果没有。gatt_process_error_rsp。
- [#1单一service发现]搜索#1号Char中的descriptor,结果没有。gatt_process_error_rsp。
- [#1单一service发现]搜索#2号Char中的descriptor,结果没有。gatt_process_error_rsp。
- [#2单一service发现]搜索include service,结果没有。gatt_process_error_rsp。
- [#2单一service发现]搜索所有Characteristic,有3个。gatt_process_read_by_type_rsp。
- [#2单一service发现]搜索#0号Char中的descriptor,结果没有。gatt_process_error_rsp。
- [#2单一service发现]搜索#1号Char中的descriptor,有一个。gatt_process_read_info_rsp。
- [#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时的应答,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可归纳为依次执行两个任务。
- 一个用于解析收到应答内容的while循环。每解析出一部分,就回调p_clcb->p_reg->app_cb.p_disc_res_cb,把这部分数据汇集到gatt数据库。
- 调用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;
- 之前的bta_gattc_disc_res_cback中AddService,会执行services_to_discover.insert({handle, end_handle}),handle是s_handle。
- StartNextServiceExploration从services_to_discover取出service,这是一个等待进一步发现的service。把它赋给pending_server,并把该service从services_to_discover删除。
- 已发现完整个pending_server,继续调用这里的StartNextServiceExploration,让第二个service成为pending_server。
- 持续工作,当示例的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发现流程。
- 搜索出所有pri service,然后对每个service依次进行单一service发现流程。(一对请求应答)
- 单一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依次执行三个任务。
- p_srvc_cb->gatt_database = p_srvc_cb->pending_discovery.Build()。pending_discovery存储着发现过程中生成的gatt数据库,调用Build()生成要用于后绪操作的gatt_database,Database。在Build(),同时会清空pending_discovery。
- 判断该periperhal是否配对过,如果是,调用bta_gattc_cache_write存储cache到文件。对通常的ios、android连接,是没有配对过的。cache文件名示例:/data/misc/bluetooth/gatt_cache_cc4b731d7f1d,文件名中的cc4b731d7f1d是mac地址。
- 调用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。