BluetoothGatt中的writeCharacteristic的实现在GattService中,如下:
void writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq, byte[] value) {
gattClientWriteCharacteristicNative(connId, handle, writeType, authReq, value);
}
这个gattClientWriteCharacteristicNative的实现在com_android_bluetooth_gatt.cpp中,
static void gattClientWriteCharacteristicNative(JNIEnv* env, jobject object,
jint conn_id, jint handle, jint write_type, jint auth_req, jbyteArray value) {
......
sGattIf->client->write_characteristic(conn_id, handle, write_type, auth_req,
std::move(vect_val));
}
这个sGattIf的client是定义在btif_gatt_client.c中的btgattClientInterface,这里调到了btif_gattc_write_char函数,
static bt_status_t btif_gattc_write_char(int conn_id, btgatt_srvc_id_t* srvc_id,
btgatt_gatt_id_t* char_id, int write_type,
int len, int auth_req, char* p_value)
{
btif_gattc_cb_t btif_cb;
btif_cb.conn_id = (uint16_t) conn_id;
btif_cb.auth_req = (uint8_t) auth_req;
btif_cb.write_type = (uint8_t) write_type;
btif_cb.len = len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len;
memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_gatt_id_t));
memcpy(btif_cb.value, p_value, btif_cb.len);
return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_WRITE_CHAR,
(char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}
这里发送到butif task中,由btgattc_handle_event处理,事件为BTIF_GATTC_WRITE_CHAR,如下:
case BTIF_GATTC_WRITE_CHAR:
btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id);
btif_to_bta_gatt_id(&in_char_id.char_id, &p_cb->char_id);
BTA_GATTC_WriteCharValue(p_cb->conn_id, &in_char_id,
p_cb->write_type,
p_cb->len,
p_cb->value,
p_cb->auth_req);
break;
再来看看BTA_GATTC_WriteCharValue的实现,如下:
void BTA_GATTC_WriteCharValue ( UINT16 conn_id,
tBTA_GATTC_CHAR_ID *p_char_id,
tBTA_GATTC_WRITE_TYPE write_type,
UINT16 len,
UINT8 *p_value,
tBTA_GATT_AUTH_REQ auth_req)
{
tBTA_GATTC_API_WRITE *p_buf;
if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL)
{
memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len);
p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
p_buf->hdr.layer_specific = conn_id;
p_buf->auth_req = auth_req;
memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));
p_buf->write_type = write_type;
p_buf->len = len;
if (p_value && len > 0)
{
p_buf->p_value = (UINT8 *)(p_buf + 1);
memcpy(p_buf->p_value, p_value, len);
}
bta_sys_sendmsg(p_buf);
}
return;
}
这里看来真正的写是在btu_task中,这里发送的事件为BTA_GATTC_API_WRITE_EVT。如下:
enum
{
BTA_GATTC_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_GATTC),
BTA_GATTC_INT_OPEN_FAIL_EVT,
BTA_GATTC_API_CANCEL_OPEN_EVT,
BTA_GATTC_INT_CANCEL_OPEN_OK_EVT,
BTA_GATTC_API_READ_EVT,
BTA_GATTC_API_WRITE_EVT,
......
};
可见这些事件都属于BTA_ID_GATTC的子系统,所以在btu_task中的事件处理函数为bta_gattc_main.c中的bta_gattc_hdl_event。奇怪的是在这个函数中没找到这个事件的处理分支,而是走到了默认处理逻辑中,如下:
tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);
if (p_clcb != NULL)
{
rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg);
}
这里的意思是先通过layer_specific找到p_clcb,再进状态机。这个layer_specific其实就是connection id,是clientIf和address生成的一个连接id。在我们write character之前已经初始化gatt过了,所以这里肯定注册过对应的clcb,我们直接进入状态机好了,这个bta_gattc_sm_execute定义在bta_gattc_main.c中,如下:
BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC_ST_TBL state_table;
UINT8 action;
int i;
BOOLEAN rt = TRUE;
/* look up the state table for the current state */
state_table = bta_gattc_st_tbl[p_clcb->state];
event &= 0x00FF;
/* set next state */
p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
/* execute action functions */
for (i = 0; i < BTA_GATTC_ACTIONS; i++)
{
if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
{
(*bta_gattc_action[action])(p_clcb, p_data);
if (p_clcb->p_q_cmd == p_data) {
/* buffer is queued, don't free in the bta dispatcher.
* we free it ourselves when a completion event is received.
*/
rt = FALSE;
}
}
else
{
break;
}
}
return rt;
}
这个状态机逻辑是先根据当前状态获取到对应的状态表,再根据发过来的事件获取当前状态下该事件的处理函数,同时将状态切到对应的下一个状态。这个状态机的表bta_gattc_st_tbl如下:
/* state table */
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
};
对应的状态为:
enum
{
BTA_GATTC_IDLE_ST = 0, /* Idle */
BTA_GATTC_W4_CONN_ST, /* Wait for connection - (optional) */
BTA_GATTC_CONN_ST, /* connected state */
BTA_GATTC_DISCOVER_ST /* discover is in progress */
};
假如当前状态是已连接,那么对应的状态表为bta_gattc_st_connected,如下:
/* state table for open state */
static const UINT8 bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] =
{
/* Event Action 1 Next state */
/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_READ, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_CFG_MTU, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_SEARCH, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_READ_MULTI, BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST},
/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_OP_CMPL, BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
/* ===> for cache loading, saving */
/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_CACHE_OPEN, BTA_GATTC_DISCOVER_ST},
/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST},
/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}
};
我们的事件是BTA_GATTC_API_WRITE_EVT,取低8位,为5,所以对应的是BTA_GATTC_WRITE,下一个状态为BTA_GATTC_CONN_ST。我们看BTA_GATTC_WRITE对应的函数,到bta_gattc_action中查,在bta_gattc_main.c中:
/* action function list */
const tBTA_GATTC_ACTION bta_gattc_action[] =
{
bta_gattc_open,
bta_gattc_open_fail,
bta_gattc_open_error,
bta_gattc_cancel_open,
bta_gattc_cancel_open_ok,
bta_gattc_cancel_open_error,
bta_gattc_conn,
bta_gattc_start_discover,
bta_gattc_disc_cmpl,
bta_gattc_q_cmd,
bta_gattc_close,
bta_gattc_close_fail,
bta_gattc_read,
bta_gattc_write,
......
};
为bta_gattc_write函数,在bta_gattc_act.c中,如下:
void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
UINT16 handle = 0;
tGATT_VALUE attr = {0};
tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATT_STATUS status = BTA_GATT_OK;
if (bta_gattc_enqueue(p_clcb, p_data))
{
if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
&p_data->api_write.srvc_id,
&p_data->api_write.char_id,
p_data->api_write.p_descr_type)) == 0)
{
status = BTA_GATT_ERROR;
}
else
{
attr.handle= handle;
attr.offset = p_data->api_write.offset;
attr.len = p_data->api_write.len;
attr.auth_req = p_data->api_write.auth_req;
if (p_data->api_write.p_value)
memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);
status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
}
/* write fail */
if (status != BTA_GATT_OK)
{
memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
op_cmpl.status = status;
op_cmpl.op_code = GATTC_OPTYPE_WRITE;
op_cmpl.p_cmpl = NULL;
bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
}
}
}
这里首先调用bta_gattc_enqueue将请求放入队列,如果成功就校验要写的character是否有效,如果有效,则调用GATTC_Write真正的写了。
先看这个bta_gattc_enqueue的逻辑,如下:
BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) {
if (p_clcb->p_q_cmd == NULL) {
p_clcb->p_q_cmd = p_data;
} else {
APPL_TRACE_ERROR("already has a pending command!!");
/* skip the callback now. ----- need to send callback ? */
}
return (p_clcb->p_q_cmd != NULL) ? TRUE : FALSE;
}
这里逻辑很简单,不是什么队列,就是相当于一个单例,一次只能有一个命令在执行。如果之前的结果还没完又来一个命令,则这里直接返回了,连回调都收不到,所以我们所有GATT操作要串行化。
我们看GATTC_Write函数的实现,在gatt_api.c中,如下:
tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
{
tGATT_STATUS status = GATT_SUCCESS;
tGATT_CLCB *p_clcb;
tGATT_VALUE *p;
tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
UINT8 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 ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
{
p_clcb->operation = GATTC_OPTYPE_WRITE;
p_clcb->op_subtype = type;
p_clcb->auth_req = p_write->auth_req;
if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
{
memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
p = (tGATT_VALUE *)p_clcb->p_attr_buf;
if (type == GATT_WRITE_PREPARE)
{
p_clcb->start_offset = p_write->offset;
p->offset = 0;
}
if (gatt_security_check_start(p_clcb) == FALSE)
{
status = GATT_NO_RESOURCES;
}
}
else
{
status = GATT_NO_RESOURCES;
}
if (status == GATT_NO_RESOURCES)
gatt_clcb_dealloc(p_clcb);
}
else
{
status = GATT_NO_RESOURCES;
}
return status;
}
这里出现了一堆错误GATT_NO_RESOURCES,值为128,平时貌似没见过,所以我们这里不关心,继续看gatt_security_check_start,这里主要是做安全检查,检查通过才会真正开始写,在gatt_auth.c中,如下:
BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
{
tGATT_TCB *p_tcb = p_clcb->p_tcb;
tGATT_SEC_ACTION gatt_sec_act;
tBTM_BLE_SEC_ACT btm_ble_sec_act;
BOOLEAN status = TRUE;
tBTM_STATUS btm_status;
tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb);
gatt_sec_act = gatt_determine_sec_act(p_clcb);
if (sec_act_old == GATT_SEC_NONE)
gatt_set_sec_act(p_tcb, gatt_sec_act);
switch (gatt_sec_act )
{
......
default:
gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
break;
}
if (status == FALSE)
{
gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
}
return status;
}
由于我们写无需权限验证,所以这里gatt_determine_sec_act返回的就是GATT_SET_OK,所以走到了default分支的gatt_sec_check_complete,如下:
void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act)
{
if (p_clcb && p_clcb->p_tcb && GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb))
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
if (!sec_check_ok)
{
gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
}
else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
{
gatt_act_write(p_clcb, sec_act);
}
else if (p_clcb->operation == GATTC_OPTYPE_READ)
{
gatt_act_read(p_clcb, p_clcb->counter);
}
}
这里终于准备写了,走到的是gatt_act_write,在gatt_cl.c中,如下:
void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act)
{
tGATT_TCB *p_tcb = p_clcb->p_tcb;
UINT8 rt = GATT_SUCCESS, op_code = 0;
tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
if (p_attr)
{
switch (p_clcb->op_subtype)
{
......
case GATT_WRITE:
if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
{
p_clcb->s_handle = p_attr->handle;
rt = gatt_send_write_msg(p_tcb,
p_clcb->clcb_idx,
GATT_REQ_WRITE,
p_attr->handle,
p_attr->len,
0,
p_attr->value);
}
else /* prepare write for long attribute */
{
gatt_send_prepare_write(p_tcb, p_clcb);
}
break;
......
default:
rt = GATT_INTERNAL_ERROR;
GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
break;
}
}
else
rt = GATT_INTERNAL_ERROR;
......
}
这里我们看普通写,如果要写的长度小,就直接走gatt_send_write_msg,否则走gatt_send_prepare_write,其实最后都是调的gatt_send_write_msg,如下:
UINT8 gatt_send_write_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code,
UINT16 handle, UINT16 len,
UINT16 offset, UINT8 *p_data)
{
tGATT_CL_MSG msg;
msg.attr_value.handle = handle;
msg.attr_value.len = len;
msg.attr_value.offset = offset;
memcpy (msg.attr_value.value, p_data, len);
/* write by handle */
return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
}
这里逻辑很简单,继续往下走,在att_protocol.c中:
tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
{
tGATT_STATUS status = GATT_NO_RESOURCES;
BT_HDR *p_cmd = NULL;
UINT16 offset = 0, handle;
if (p_tcb != NULL)
{
switch (op_code)
{
......
case GATT_REQ_PREPARE_WRITE:
offset = p_msg->attr_value.offset;
/* fall through */
case GATT_REQ_WRITE:
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
{
p_cmd = attp_build_value_cmd (p_tcb->payload_size,
op_code, p_msg->attr_value.handle,
offset,
p_msg->attr_value.len,
p_msg->attr_value.value);
}
else
status = GATT_ILLEGAL_PARAMETER;
break;
......
default:
break;
}
if (p_cmd != NULL)
status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
}
return status;
}
由于我们的op_code是GATT_REQ_WRITE,所以这里先通过attp_build_value_cmd封装好了cmd,然后调用attp_cl_send_cmd发送出去。之所以这么做是因为这个任务也许不能马上执行,所以需要丢到一个队列中。这个cmd就相当于队列中的一个task。我们看这个cmd是怎么丢到队列中的:
tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
{
tGATT_STATUS att_ret = GATT_SUCCESS;
if (p_tcb != NULL)
{
cmd_code &= ~GATT_AUTH_SIGN_MASK;
/* no pending request or value confirmation */
if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
cmd_code == GATT_HANDLE_VALUE_CONF)
{
att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
{
/* do not enq cmd if handle value confirmation or set request */
if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
{
gatt_start_rsp_timer (clcb_idx);
gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
}
}
else
att_ret = GATT_INTERNAL_ERROR;
}
else
{
att_ret = GATT_CMD_STARTED;
gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
}
}
else
att_ret = GATT_ERROR;
return att_ret;
}
这里的意思是如果当前没有别的待处理的请求的话就直接调用attp_send_msg_to_l2cap给请求丢到L2CAP层处理了,否则加到等待队列中。如果是丢到L2CAP层的请求则还要通过gatt_start_rsp_timer 启动一个定时器来检查回调。
到这里还有两个问题没有讨论到,一个是L2CAP层怎么处理写设备请求的,另一个是GKI层定时器的处理逻辑,这些会留给下文。