必务先看“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。