必务先看“BLE(2/6):连接之BluetoothDevice.connectGatt”,看过它才能清楚Android BLE何时调用btif_gattc_open。
在BluetoothDevice.connectGatt,如果mService.registerClient成功,会以参数status=GATT_SUCCESS回调BluetoothGatt的onClientRegistered,当中会发起连接请求:mService.clientConnect(mClientIf, mDevice.getAddress(), !mAutoConnect)。clientConnect会调用JNI函数gattClientConnectNative,后者进一步调用BLE HAL中的btif_gattc_open。
- 会完成bta层的4个状态变迁:BTA_GATTC_IDLE_ST(st_idle) -> BTA_GATTC_W4_CONN_ST(st_w4_conn(wait for connection)) -> BTA_GATTC_DISCOVER_ST(st_connected) -> BTA_GATTC_CONN_ST(st_discovery)。初始状态为st_idle。建立L2CAP连接后,进入st_w4_conn。L2CAP连接建立后开始搜索服务,进入st_discover。discover需要一点时间,完成后进入st_connected,表明GATT连接已经建立,指示ble center已经清楚ble peripheral中GATT数据库的service。
- 三个主要任务。1)L2CA_ConnectFixedChnl()。在l2cap层分配channel,通道ID是L2CAP_ATT_CID(4)。2)bta_gattc_start_discover()。从ble peripheral获取service、characteristic等数据。3)bta_gattc_send_open_cback()。调用JNI注册的回调函数:btgattc_open_cb、btgattc_configure_mtu_cb。
- discover和后面的send_open_cback不是同步执行,即不是discover执行完了才会执行send_open_cback。discover向ble其它线程投递任务后,所在线程就立即执行send_open_cback。在完成时刻上,往往send_open_cback要早于discover。
类似btif_gattc_register_app,btif_gattc_open也是调用do_in_jni_thread,让在bt_jni_thread线程序列化执行对应函数btif_gattc_open_impl
<aosp>/system/bt/btif/src/btif_gatt_client.cc ------ static bt_status_t btif_gattc_open(int client_if, const RawAddress& bd_addr, bool is_direct, int transport, bool opportunistic, int initiating_phys) { CHECK_BTGATT_INIT(); // Closure will own this value and free it. return do_in_jni_thread(Bind(&btif_gattc_open_impl, client_if, bd_addr, is_direct, transport, opportunistic, initiating_phys)); } <aosp>/system/bt/btif/src/btif_gatt_client.cc ------ void btif_gattc_open_impl(int client_if, RawAddress address, bool is_direct, int transport_p, bool opportunistic, int initiating_phys) { // Ensure device is in inquiry database tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC; int device_type = 0; tBT_TRANSPORT transport = (tBT_TRANSPORT)BT_TRANSPORT_LE; if (btif_get_address_type(address, &addr_type) && btif_get_device_type(address, &device_type) && device_type != BT_DEVICE_TYPE_BREDR) { BTA_DmAddBleDevice(address, addr_type, device_type); } // Check for background connections if (!is_direct) { ... } // Determine transport if (transport_p != BT_TRANSPORT_AUTO) { transport = transport_p; } else { switch (device_type) { case BT_DEVICE_TYPE_BREDR: transport = BT_TRANSPORT_BR_EDR; break; case BT_DEVICE_TYPE_BLE: transport = BT_TRANSPORT_LE; break; case BT_DEVICE_TYPE_DUMO: if (transport_p == BT_TRANSPORT_LE) transport = BT_TRANSPORT_LE; else transport = BT_TRANSPORT_BR_EDR; break; } } // Connect! BTIF_TRACE_DEBUG("%s Transport=%d, device type=%d, phy=%d", __func__, transport, device_type, initiating_phys); BTA_GATTC_Open(client_if, address, is_direct, transport, opportunistic, initiating_phys); }
btif_gattc_open_impl首先要决定transport,传输有两种,一种是传统蓝牙的BR_EDR,另一种是LE。
- BT_DEVICE_TYPE_BREDR。只支持传统蓝牙,用BR_EDR。
- BT_DEVICE_TYPE_BLE。只支持LE,用LE。
- BT_DEVICE_TYPE_DUMO。同时支持BR_DR、LE。用传统的BREDR。“case BT_DEVICE_TYPE_DUMO”时,虽然有“if (transport_p == BT_TRANSPORT_LE)”,但之前已剔除“if (transport_p != BT_TRANSPORT_AUTO)”,这判断应该总是false。
根据这判断规则,遇到两种都支持的双模peripheral,要想使用LE的话,app得填上BT_TRANSPORT_LE,不能使用BT_TRANSPORT_AUTO。决定出transport后,调用BTA_GATTC_Open。
<aosp>/system/bt/bta/gatt/bta_gattc_api.cc ------ void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda, bool is_direct, tBT_TRANSPORT transport, bool opportunistic, uint8_t initiating_phys) { tBTA_GATTC_API_OPEN* p_buf = (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN)); p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT; p_buf->client_if = client_if; p_buf->is_direct = is_direct; p_buf->transport = transport; p_buf->initiating_phys = initiating_phys; p_buf->opportunistic = opportunistic; p_buf->remote_bda = remote_bda; bta_sys_sendmsg(p_buf); }
构造一个tBTA_GATTC_API_OPEN结构,以它为参数调用bta_sys_sendmsg。针对BTA_GATTC_API_OPEN_EVT这个消息码,对应处理函数是bta_gattc_hdl_event,bta_sys_sendmsg功能就是在bt_main_thread执行bta_gattc_hdl_event(p_buf)。接下查看event=BTA_GATTC_API_OPEN_EVT时的bta_gattc_hdl_event。
<aosp>/system/bt/bta/gatt/bta_gattc_main.c ------ bool bta_gattc_hdl_event(BT_HDR_RIGID* p_msg) { tBTA_GATTC_CLCB* p_clcb = NULL; bool rt = true; switch (p_msg->event) { case BTA_GATTC_API_OPEN_EVT: bta_gattc_process_api_open((tBTA_GATTC_DATA*)p_msg); break; ... } return rt; }
继续看bta_gattc_process_api_open。
<aosp>/system/bt/bta/gatt/bta_gattc_act.c ------ void bta_gattc_process_api_open(const tBTA_GATTC_DATA* p_msg) { uint16_t event = ((BT_HDR_RIGID*)p_msg)->event; tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if); if (!p_msg->api_conn.is_direct) { bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg); return; } tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_alloc_clcb( p_msg->api_conn.client_if, p_msg->api_conn.remote_bda, p_msg->api_conn.transport); if (p_clcb != NULL) { bta_gattc_sm_execute(p_clcb, event, p_msg); } else { ... } }
首先使用bta_gattc_find_alloc_clcb分配出此次连接对应的tBTA_GATTC_CLCB对象,以它为参数调用BTA层状态机来处理这个event
bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event, const tBTA_GATTC_DATA* p_data) { tBTA_GATTC_ST_TBL state_table; uint8_t action; int i; bool rt = true; tBTA_GATTC_STATE in_state = p_clcb->state; uint16_t in_event = event; /* look up the state table for the current state */ state_table = bta_gattc_st_tbl[p_clcb->state]; event &= 0x00FF; /* set next state */ // 操作1/2:写在状态表中的“next state”赋值给p_clcb->state。 // 若后面没强制改变state,经过bta_gattc_sm_execute后,p_clcb->state值就是写在状态表中的“next state”。 p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE]; /* execute action functions */ for (i = 0; i < BTA_GATTC_ACTIONS; i++) { action = state_table[event][i]; if (action != BTA_GATTC_IGNORE) { // 操作2/2:在状态表中的“next state”状态下,执行写在状态表中的“action”。 (*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; }
bta_gattc_sm_execute是bta层的状态机函数。它依次执行两种操作。
- 写在状态表中的“next state”赋值给p_clcb->state。
- 在状态表中的“next state”状态下,执行写在状态表中的“action”
很显然,和其它层的状态机一样,要理解它首先要知道该层的状态表。
<aosp>/system/bt/bta/gatt/bta_gattc_main.c ------ const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] = { bta_gattc_st_idle, bta_gattc_st_w4_conn, bta_gattc_st_connected, bta_gattc_st_discover };
bta有4个状态:st_idle、st_wait for connection、st_connected和st_discovery。初始状态为st_idle。建立L2CAP连接后,进入st_w4_conn。L2CAP连接建立后开始搜索服务,进入st_discover。discover需要一点时间,完成后进入st_connected,表明GATT连接已经建立,指示ble center已经清楚ble peripheral中GATT数据库的service。
基于当前状态(p_clcb->state),bta_gattc_sm_execute找到状态转换表(state_table = bta_gattc_st_tbl[p_clcb->state]),根据event来查找当前应该执行的action(state_table[event][i]),根据action找到具体要执行的函数(bta_gattc_action[action])。状态转换表是一个二维数组,event是y维度上的索引,x依次是action、next_state。
针对此刻的状态转换,bta的state是idle,意味着状态表是bta_gattc_st_idle,收到BTA_GATTC_API_OPEN_EVT事件,查表可知action是BTA_GATTC_OPEN,下一个状态是BTA_GATTC_W4_CONN_ST。action是BTA_GATTC_OPEN时执行的函数是bta_gattc_open。
<aosp>/system/bt/bta/gatt/bta_gattc_act.c ------ void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { tBTA_GATTC_DATA gattc_data; // bta_gattc_open有两个任务,一是GATT_Connect,在L2CAP分配一个GATT的信道。 /* 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, p_data->api_conn.opportunistic, p_data->api_conn.initiating_phys)) { LOG(ERROR) << "Connection open failure"; bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data); return; } /* 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)) { // 成功分配信道 // bta_gattc_open第二个任务:bta状态机处理BTA_GATTC_INT_CONN_EVT事件。 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。
<aosp>\system\bt\stack\gatt\gatt_api.cc ------ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct, tBT_TRANSPORT transport, bool opportunistic, uint8_t initiating_phys) { /* Make sure app is registered */ tGATT_REG* p_reg = gatt_get_regcb(gatt_if); ... bool ret; if (is_direct) { LOG_DEBUG("Starting direct connect gatt_if=%u address=%s", gatt_if, bd_addr.ToString().c_str()); ret = gatt_act_connect(p_reg, bd_addr, transport, initiating_phys); } else { ... } tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport); // background connections don't necessarily create tcb if (p_tcb && ret) gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, !is_direct); return ret; } <aosp>/system/bt/stack/gatt/gatt_main.cc ------ bool gatt_act_connect(tGATT_REG* p_reg, const RawAddress& bd_addr, tBT_TRANSPORT transport, int8_t initiating_phys) { tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport); if (p_tcb != NULL) { ... return true; } p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport); if (!p_tcb) { LOG(ERROR) << "Max TCB for gatt_if [ " << +p_reg->gatt_if << "] reached."; return false; } if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys, p_reg->gatt_if)) { LOG(ERROR) << "gatt_connect failed"; fixed_queue_free(p_tcb->pending_ind_q, NULL); *p_tcb = tGATT_TCB(); return false; } return true; } <aosp>/system/bt/stack/gatt/gatt_main.cc ------ bool gatt_connect(const RawAddress& rem_bda, tGATT_TCB* p_tcb, tBT_TRANSPORT transport, uint8_t initiating_phys, tGATT_IF gatt_if) { 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 = L2CA_ConnectReq2(BT_PSM_ATT, rem_bda, BTM_SEC_NONE); return p_tcb->att_lcid != 0; } // Already connected, mark the link as used if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) { gatt_update_app_use_link_flag(gatt_if, p_tcb, true, true); return true; } p_tcb->att_lcid = L2CAP_ATT_CID; return acl_create_le_connection_with_id(gatt_if, rem_bda); }
除在L2CAP分配通道,bta_gattc_open第二件事是让bta进入BTA_GATTC_DISCOVER_ST状态。让重复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的state是w4_conn,意味着状态表是bta_gattc_st_w4_conn,收到BTA_GATTC_INT_CONN_EVT事件,查表可知action是BTA_GATTC_CONN,表中写的下一个状态是BTA_GATTC_CONN_ST(实际不是,后面会解释)。action是BTA_GATTC_CONN时执行的函数是bta_gattc_conn。
看到函数名字,我们有点疑惑,刚刚的gatt_connect不是已经做了gatt connect的动作,这里怎么还有连接的操作?其实这是一个回调函数,正如其注释写的那样:“receive connection callback from stack”
<aosp>/system/bt/bta/gatt/bta_gattc_act.cc ------ void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { tGATT_IF gatt_if; if (p_data != NULL) { VLOG(1) << __func__ << ": conn_id=" << loghex(p_data->hdr.layer_specific); p_clcb->bta_conn_id = p_data->int_conn.hdr.layer_specific; // 获取对应的gatt_if GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda, &p_clcb->transport); } 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->gatt_database.IsEmpty() || p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) { if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) { p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD; // 尝试打开cache文件,像/data/misc/bluetooth/gatt_cache_cc4b731d7f1d, // 如果已配对过该peripheral,上次读取gatt数据库后,会生成这个cache, if (bta_gattc_cache_load(p_clcb->p_srcb)) { // 成功加载了cache文件,用cache文件中的gatt数据库,这次就没有发现阶段了 p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS); } else { // 打开cache文件失败。 // ios、adndroid手机作为center的app,通常没有配对过程,也就没有cache文件,进这入口 p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC; /* cache load failure, start discovery */ bta_gattc_start_discover(p_clcb, NULL); } } else /* cache is building */ p_clcb->state = BTA_GATTC_DISCOVER_ST; } else { /* a pending service handle change indication */ ... } if (p_clcb->p_rcb) { /* there is no RM for GATT */ if (p_clcb->transport == BT_TRANSPORT_BR_EDR) bta_sys_conn_open(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda); // 回调bt-JNI层的函数 bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_SUCCESS, p_clcb->bda, p_clcb->bta_conn_id, p_clcb->transport, p_clcb->p_srcb->mtu); } }
这里先说下GATTC状态机状态p_clcb->state,对没有cache文件场景,像ios、adndroid手机作为center的app,执行bta_gattc_conn后,状态不是bta_gattc_st_w4_conn结构写的“next”:BTA_GATTC_CONN_ST,而是BTA_GATTC_DISCOVER_ST。具体在bta_gattc_start_discover()会调用bta_gattc_set_discover_st,内中会把状态BTA_GATTC_CONN_ST改为BTA_GATTC_DISCOVER_ST。
<aosp>/system/bt/bta/gatt/bta_gattc_act.cc ------ void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) { uint8_t i; for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) { if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) { bta_gattc_cb.clcb[i].status = GATT_SUCCESS; // 状态由BTA_GATTC_CONN_ST改为BTA_GATTC_DISCOVER_ST bta_gattc_cb.clcb[i].state = BTA_GATTC_DISCOVER_ST; bta_gattc_cb.clcb[i].request_during_discovery = BTA_GATTC_DISCOVER_REQ_NONE; } }
为什么bt协议栈把进入bta_gattc_conn时的状态设为BTA_GATTC_CONN_ST?——我是这么理解的,一些场景的确此时已经可以是BTA_GATTC_CONN_ST,像存在一个有效的cache文件,读这文件就成生成gatt数据库了。而一旦判断出必须访问peripheral才能生成gatt数据库,那就统一调用bta_gattc_start_discover,在那里改为正确的BTA_GATTC_DISCOVER_ST。
p_clcb->p_srcb将存储着从peripheral读到的gatt数据库,p_clcb->p_srcb->state指示着状态。初始状态BTA_GATTC_SERV_IDLE,构建出数据库后,状态是BTA_GATTC_SERV_SAVE。一旦此次连接被close,p_clcb->p_srcb->gatt_database会被清空,状态复位回BTA_GATTC_SERV_IDLE。
总之,bta_gattc_conn主要做了两件事:
- bta_gattc_start_discover(...)。启动从peripheral获取gatt数库据,像service、characteristic。
- bta_gattc_send_open_cback(...)。调用JNI注册的回调函数。
“bt协议栈:connectGatt之bta_gattc_start_discover”会细说discover流程,这里只要知道它的功能是从ble peripheral获取gatt数据库,它和后面的send_open_cback不是同步的,即不是discover执行完了才会执行send_open_cback。discover向ble其它线程转投任务后,所在线程就立即执行send_open_cback。在完成时间上,往往send_open_cback要比discover先完成。
先搁置discover,继续看bta_gattc_send_open_cback。
<aosp>/system/bt/bta/gatt/bta_gattc_utils.cc ------ void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg, tGATT_STATUS status, const RawAddress& remote_bda, uint16_t conn_id, tBT_TRANSPORT transport, uint16_t 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; cb_data.open.remote_bda = remote_bda; (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data); } }
p_clreg->p_cback是个函数指针,指向bta_gattc_cback。bta_gattc_cback功能:在bt_jni_thread线程执行btif_gattc_upstreams_evt(event, p_data),参数event、p_data分别是传给bta_gattc_cback的第一、第二个参数。
<aosp>/system/bt/btif/src/btif_gatt_client.cc ------ static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) { tBTA_GATTC* p_data = (tBTA_GATTC*)p_param; switch (event) { ... case BTA_GATTC_OPEN_EVT: { DVLOG(1) << "BTA_GATTC_OPEN_EVT " << p_data->open.remote_bda; HAL_CBACK(bt_gatt_callbacks, client->open_cb, p_data->open.conn_id, p_data->open.status, p_data->open.client_if, p_data->open.remote_bda); if (GATT_DEF_BLE_MTU_SIZE != p_data->open.mtu && p_data->open.mtu) { HAL_CBACK(bt_gatt_callbacks, client->configure_mtu_cb, p_data->open.conn_id, p_data->open.status, p_data->open.mtu); } if (p_data->open.status == GATT_SUCCESS) btif_gatt_check_encrypted_link(p_data->open.remote_bda, p_data->open.transport); break; } case BTA_GATTC_CLOSE_EVT: { HAL_CBACK(bt_gatt_callbacks, client->close_cb, p_data->close.conn_id, p_data->close.status, p_data->close.client_if, p_data->close.remote_bda); break; } ... default: LOG_ERROR("Unhandled event (%d)!", event); break; } }
除直观认为的回调open_cb外,要是设置的mtu不是默认的GATT_DEF_BLE_MTU_SIZE(23),还会回调configure_mtu_cb。它们分别对应bt-JNI的btgattc_open_cb、btgattc_configure_mtu_cb。
针对btgattc_open_cb,它将一路向上回调:GattService.onConnected --> BluetoothGatt.onClientConnectionState --> app层的onConnectionStateChange。