connectGatt(3/4):btif_gattc_open

必务先看“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层的状态机函数。它依次执行两种操作。

  1. 写在状态表中的“next state”赋值给p_clcb->state。
  2. 在状态表中的“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主要做了两件事:

  1. bta_gattc_start_discover(...)。启动从peripheral获取gatt数库据,像service、characteristic。
  2. 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。

全部评论: 0

    写评论: