BlueDroid HFP 源码分析笔记(1)

BlueDroid 代码分析

对部分代码一眼无法知道运行结果的地方备注。

HPF Connect

可以理解为闭包吧!将参数和方法打包在一起传入队列中等待执行。最终执行的就是 connect_init(),参数就是bd_addr, connect_init。

static bt_status_t connect(RawAddress* bd_addr) {
  return btif_queue_connect(UUID_SERVCLASS_HF_HANDSFREE, bd_addr, connect_int);
}

这里的用到BlueDroid中最常用的消息传递方式,malloc出结构体后。赋值event和layer_specific。
然后通过bta_sys_sendmsg发送event到bta_sys_main.cc bta_sys_event中进行处理。

void BTA_HfClientOpen(const RawAddress& bd_addr, tBTA_SEC sec_mask,
                      uint16_t* p_handle) {
  APPL_TRACE_DEBUG("%s", __func__);
  tBTA_HF_CLIENT_API_OPEN* p_buf =
      (tBTA_HF_CLIENT_API_OPEN*)osi_malloc(sizeof(tBTA_HF_CLIENT_API_OPEN));

  if (!bta_hf_client_allocate_handle(bd_addr, p_handle)) {
    APPL_TRACE_ERROR("%s: could not allocate handle", __func__);
    return;
  }

  p_buf->hdr.event = BTA_HF_CLIENT_API_OPEN_EVT; //BTA_HF_CLIENT_API_OPEN_EVT = 27 << 8:
  p_buf->hdr.layer_specific = *p_handle;
  p_buf->bd_addr = bd_addr;
  p_buf->sec_mask = sec_mask;

  bta_sys_sendmsg(p_buf);
}

enum {
  /* these events are handled by the state machine */
  BTA_HF_CLIENT_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HS), // BTA_ID_HS 27
  BTA_HF_CLIENT_API_CLOSE_EVT,
  BTA_HF_CLIENT_API_AUDIO_OPEN_EVT,
  BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT,
  BTA_HF_CLIENT_RFC_OPEN_EVT,
  BTA_HF_CLIENT_RFC_CLOSE_EVT,
  BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT,
  BTA_HF_CLIENT_RFC_DATA_EVT,
  BTA_HF_CLIENT_DISC_ACP_RES_EVT,
  BTA_HF_CLIENT_DISC_INT_RES_EVT,
  BTA_HF_CLIENT_DISC_OK_EVT,
  BTA_HF_CLIENT_DISC_FAIL_EVT,
  BTA_HF_CLIENT_SCO_OPEN_EVT,
  BTA_HF_CLIENT_SCO_CLOSE_EVT,
  BTA_HF_CLIENT_SEND_AT_CMD_EVT,
  BTA_HF_CLIENT_MAX_EVT,

  /* these events are handled outside of the state machine */
  BTA_HF_CLIENT_API_ENABLE_EVT,
  BTA_HF_CLIENT_API_DISABLE_EVT
};


//记住这三个结构体,都包含有一个BT_HDR 的结构提。这结构体中包含一些共同的信息
/* data type for BTA_HF_CLIENT_API_OPEN_EVT */
typedef struct {
  BT_HDR hdr;
  RawAddress bd_addr;
  uint16_t* handle;
  tBTA_SEC sec_mask;
} tBTA_HF_CLIENT_API_OPEN;

/* data type for BTA_HF_CLIENT_DISC_RESULT_EVT */
typedef struct {
  BT_HDR hdr;
  uint16_t status;
} tBTA_HF_CLIENT_DISC_RESULT;

/* data type for RFCOMM events */
typedef struct {
  BT_HDR hdr;
  uint16_t port_handle;
} tBTA_HF_CLIENT_RFC;

/* generic purpose data type for other events */
typedef struct {
  BT_HDR hdr;
  bool bool_val;
  uint8_t uint8_val;
  uint32_t uint32_val1;
  uint32_t uint32_val2;
  char str[BTA_HF_CLIENT_NUMBER_LEN + 1];
} tBTA_HF_CLIENT_DATA_VAL;

//注意这是一个联合体!!! 后面会知道这个联合体的用处。
/* union of all event datatypes */
typedef union {
  BT_HDR hdr;
  tBTA_HF_CLIENT_API_OPEN api_open;
  tBTA_HF_CLIENT_DISC_RESULT disc_result;
  tBTA_HF_CLIENT_RFC rfc;
  tBTA_HF_CLIENT_DATA_VAL val;

} tBTA_HF_CLIENT_DATA;

这个方法就是处理event。传进来的参数已经是BT_HDR *,因为这个方法是通用的处理。不止HFP会发送消息到这里进行处理。其他的profile也会发送消息过来,所以需要一个共同的结构体。

  • id = (uint8_t)(p_msg->event >> 8);
    获取的id是右移8位,为什么要这样了。是因为BTA_HF_CLIENT_API_OPEN_EVT就是在 BTA_ID_HS的基础上左移8位,同时这个值又被enum包括,这样后续的值再右移8位后得到的值仍然是BTA_ID_HS。既保证了Event的不同,同时保证这些Event指向同一个ID。

  • (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg)
    从上面我们知道id等于BTA_ID_HS,那就从数组中去除对应register进行处理,使用BTA_ID_HS进行注册的是在bta_hf_client_main.cc bta_hf_client_api_enable()方法中。最终调用 bta_hf_client_hdl_event()。
    这个过程还是比较绕的。

//bta_sys_main.cc
void bta_sys_event(BT_HDR* p_msg) {
  uint8_t id;
  bool freebuf = true;

  APPL_TRACE_EVENT("%s: Event 0x%x", __func__, p_msg->event);

  /* get subsystem id from event */
  id = (uint8_t)(p_msg->event >> 8);

  /* verify id and call subsystem event handler */
  if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) {
    freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
  } else {
    APPL_TRACE_WARNING("%s: Received unregistered event id %d", __func__, id);
  }

  if (freebuf) {
    osi_free(p_msg);
  }
}
// 2 BTA_HF_CLIENT_API_OPEN_EVT = BTA_ID_HS << 8; 这样后续的值通过右移恢复都会得到同样的值BTA_ID_HS
enum {
  /* these events are handled by the state machine */
  BTA_HF_CLIENT_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HS), // BTA_ID_HS 27
  BTA_HF_CLIENT_API_CLOSE_EVT,
  BTA_HF_CLIENT_API_AUDIO_OPEN_EVT,
  BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT,
  BTA_HF_CLIENT_RFC_OPEN_EVT,
  BTA_HF_CLIENT_RFC_CLOSE_EVT,
  BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT,
  BTA_HF_CLIENT_RFC_DATA_EVT,
  BTA_HF_CLIENT_DISC_ACP_RES_EVT,
  BTA_HF_CLIENT_DISC_INT_RES_EVT,
  BTA_HF_CLIENT_DISC_OK_EVT,
  BTA_HF_CLIENT_DISC_FAIL_EVT,
  BTA_HF_CLIENT_SCO_OPEN_EVT,
  BTA_HF_CLIENT_SCO_CLOSE_EVT,
  BTA_HF_CLIENT_SEND_AT_CMD_EVT,
  BTA_HF_CLIENT_MAX_EVT,

  /* these events are handled outside of the state machine */
  BTA_HF_CLIENT_API_ENABLE_EVT,
  BTA_HF_CLIENT_API_DISABLE_EVT
};

//这个方法是在通过 init方法调用的,里面初始化的bta_hf_client_cb_arr 这个重要的结构体。
tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback,
                                     tBTA_SEC sec_mask,
                                     tBTA_HF_CLIENT_FEAT features,
                                     const char* p_service_name) {
  ...
  
  /* register with BTA system manager */
  bta_sys_register(BTA_ID_HS, &bta_hf_client_reg);
  
  ...
  return BTA_SUCCESS;
}

小结
  1. 看到 bta_sys_sendmsg(p_buf);
  2. 找到Event 对应的id.
  3. 找到对应id注册到bta_sys_main中的处理方法
  4. 直接跳转对应的处理方法。

状态机的切换

下面的代码会比较绕,一眼看过还是需要回头在细细品味一下的。我直接在代码中添加注释了。

//注意此处传进来的参数是tBTA_HF_CLIENT_DATA * 联合体,这是因为 tBTA_HF_CLIENT_API_OPEN
//tBTA_HF_CLIENT_DISC_RESULT tBTA_HF_CLIENT_RFC  tBTA_HF_CLIENT_DATA_VAL 都会在这里进行处理
void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) {
  //p_data->hdr.layer_specific 是 handle = 1,此处的结构体是tBTA_HF_CLIENT_CB 
  //(ps:CB control bolck 千万不要联想是callback)
  tBTA_HF_CLIENT_CB* client_cb =
      bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
  if (client_cb == NULL) {
    APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
                     p_data->hdr.layer_specific);
    return;
  }

  tBTA_HF_CLIENT_ST_TBL state_table;
  uint8_t action;
  int i;
  //BTA_HF_CLIENT_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HS) ===> 
  uint16_t in_event = event;
  //client_cb-> 初始状态是 0
  uint8_t in_state = client_cb->state;

  /* Ignore displaying of AT results when not connected (Ignored in state
   * machine) */
  if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) {
    APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)",
                     client_cb->state,
                     bta_hf_client_state_str(client_cb->state), event,
                     bta_hf_client_evt_str(event));
  }
  //!!! 经过与操作后 event就是值是从0开始,后续的值就是从0的基础上加1。
  event &= 0x00FF;
  if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) {
    APPL_TRACE_ERROR("HF Client evt out of range, ignoring...");
    return;
  }

  //bta_hf_client_st_tbl是一组状态表。 (ps:st_tbl state_table)
  //client_cb->state 当前是0, 对应状态表:bta_hf_client_st_init 
  /* look up the state table for the current state */
  state_table = bta_hf_client_st_tbl[client_cb->state];

  /* set next state */
  //通过bta_hf_client_st_init 对应下一个状态。  event = 0, BTA_HF_CLIENT_NEXT_STATE = 2
  //就是第一行的最后一个参数就是下一个状态。
  //   Event              Action 1                 Action 2                 Next State
  // API_OPEN_EVT | {BTA_HF_CLIENT_START_OPEN, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST},
  //client_cb->state = BTA_HF_CLIENT_OPENING_ST; (1)
  client_cb->state = state_table[event][BTA_HF_CLIENT_NEXT_STATE];

  /* execute action functions */
  // bta_hf_client_action 是一个action 函数指针 数组
  // action = state_table[event][i]; 就是通过查表找对对应action 执行,
  // 此处的action BTA_HF_CLIENT_START_OPEN 2 
  // 执行bta_hf_client_act.cc bta_hf_client_start_open 方法
  for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++) {
    action = state_table[event][i];
    if (action != BTA_HF_CLIENT_IGNORE) {
      (*bta_hf_client_action[action])(p_data);
    } else {
      break;
    }
  }

  //当前的client_cb->state 为BTA_HF_CLIENT_OPENING_ST,虽然与前一个状态不同。但是不会执行下面的方法。
  /* If the state has changed then notify the app of the corresponding change */
  if (in_state != client_cb->state) {
    VLOG(1) << __func__ << ": notifying state change to " << in_state << " -> "
            << client_cb->state << " device " << client_cb->peer_addr;
    tBTA_HF_CLIENT evt;
    memset(&evt, 0, sizeof(evt));
    evt.bd_addr = client_cb->peer_addr;
    if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
      bta_hf_client_app_callback(BTA_HF_CLIENT_CLOSE_EVT, &evt);
    } else if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) {
      evt.open.handle = client_cb->handle;
      bta_hf_client_app_callback(BTA_HF_CLIENT_OPEN_EVT, &evt);
    }
  }

  /* if the next state is INIT then release the cb for future use */
  /* If the collision timer is scheduled, don't release the cb */
  if ((client_cb->state == BTA_HF_CLIENT_INIT_ST) &&
      (!alarm_is_scheduled(client_cb->collision_timer))) {
    APPL_TRACE_DEBUG("%s: marking CB handle %d to false", __func__,
                     client_cb->handle);
    client_cb->is_allocated = false;
  }
  ...
}

/* state table */
const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = {
    bta_hf_client_st_init, 
    bta_hf_client_st_opening, 
    bta_hf_client_st_open,
    bta_hf_client_st_closing};


/* action functions table, indexed with action enum */
const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = {
    /* BTA_HF_CLIENT_RFC_DO_CLOSE */ bta_hf_client_rfc_do_close,
    /* BTA_HF_CLIENT_START_CLOSE */ bta_hf_client_start_close,
    /* BTA_HF_CLIENT_START_OPEN */ bta_hf_client_start_open,
    /* BTA_HF_CLIENT_RFC_ACP_OPEN */ bta_hf_client_rfc_acp_open,
    /* BTA_HF_CLIENT_SCO_LISTEN */ NULL,
    /* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open,
    /* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close,
    /* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open,
    /* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close,
    /* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db,
    /* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail,
    /* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open,
    /* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail,
    /* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res,
    /* BTA_HF_CLIENT_RFC_DO_OPEN */ bta_hf_client_rfc_do_open,
    /* BTA_HF_CLIENT_DISC_FAIL */ bta_hf_client_disc_fail,
    /* BTA_HF_CLIENT_RFC_CLOSE */ bta_hf_client_rfc_close,
    /* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data,
    /* BTA_HF_CLIENT_DISC_ACP_RES */ bta_hf_client_disc_acp_res,
    /* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open,
    /* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd,
};
小结
  1. 不同的状态对应不同的 状态表(state table) 找到初始状态。
  2. Event &0x00FF后就是枚举表中的顺序,再将其转化成state table中的位置。
  3. 找到对应的列后,最后一个值就是下一个状态,第一个值对应是当前action。
  4. 根据action值(既数组中下标)去action 函数指针数组中找到对应的函数指针。

SDP Discover

在连接之前需要通过SDP发现对端的服务。SDP_ServiceSearchAttributeRequest2()最后的结果会回调给bta_hf_client_sdp_cback。然后又是发送Event到bta_sys_main.cc 的bta_sys_event中进行处理。
最后还是回到bta_hf_client_main.cc 的 bta_hf_client_sm_execute()方法中。

void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb) {
  Uuid uuid_list[1];
  uint16_t num_uuid = 1;
  uint16_t attr_list[4];
  uint8_t num_attr;
  bool db_inited = false;

  /* initiator; get proto list and features */
  if (client_cb->role == BTA_HF_CLIENT_INT) {
    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
    attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
    attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
    attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
    num_attr = 4;
    uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
  }
  /* acceptor; get features */
  else {
    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
    attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
    attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
    num_attr = 3;
    uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
  }

  /* allocate buffer for sdp database */
  client_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);

  /* set up service discovery database; attr happens to be attr_list len */
  db_inited = SDP_InitDiscoveryDb(client_cb->p_disc_db, BT_DEFAULT_BUFFER_SIZE,
                                  num_uuid, uuid_list, num_attr, attr_list);

  if (db_inited) {
    /*Service discovery not initiated */
    //会走到此方法中
    db_inited = SDP_ServiceSearchAttributeRequest2(
        client_cb->peer_addr, client_cb->p_disc_db, bta_hf_client_sdp_cback,
        (void*)client_cb);
  }

  if (!db_inited) {
    /*free discover db */
    osi_free_and_reset((void**)&client_cb->p_disc_db);
    /* sent failed event */
    tBTA_HF_CLIENT_DATA msg;
    msg.hdr.layer_specific = client_cb->handle;
    bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, &msg);
  }
}

static void bta_hf_client_sdp_cback(uint16_t status, void* data) {
  uint16_t event;
  //注意这里是tBTA_HF_CLIENT_DISC_RESULT 结构体 之前是tBTA_HF_CLIENT_API_OPEN
  tBTA_HF_CLIENT_DISC_RESULT* p_buf = (tBTA_HF_CLIENT_DISC_RESULT*)osi_malloc(
      sizeof(tBTA_HF_CLIENT_DISC_RESULT));

  APPL_TRACE_DEBUG("bta_hf_client_sdp_cback status:0x%x", status);
  tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data;

  /* set event according to int/acp */
  //role 是init
  if (client_cb->role == BTA_HF_CLIENT_ACP)
    event = BTA_HF_CLIENT_DISC_ACP_RES_EVT;
  else
    event = BTA_HF_CLIENT_DISC_INT_RES_EVT;

  p_buf->hdr.event = event;
  p_buf->hdr.layer_specific = client_cb->handle;
  p_buf->status = status;

  bta_sys_sendmsg(p_buf);
}

最后绕到bta_hf_client_main.cc方法中,我们来分析一波。

  1. 首先从API_OPEN 状态 BTA_HF_CLIENT_INIT_ST, 之后将状态迁移到 BTA_HF_CLIENT_OPENING_ST。对应的state_stable是 bta_hf_client_st_opening。

  2. BTA_HF_CLIENT_DISC_INT_RES_EVT 再枚举中排第9。在bta_hf_client_st_opening找到下标为9那一列:

    /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_DISC_INT_RES, BTA_HF_CLIENT_IGNORE,
                            BTA_HF_CLIENT_OPENING_ST},
  1. 找相应的action 值,以及下一个状态。 BTA_HF_CLIENT_DISC_INT_RES 为 13,下一个迁移状态仍然是 BTA_HF_CLIENT_OPENING_ST

  2. 根据上面的action值,在bta_hf_client_action 函数指针数组中找到对应下标的函数。
    最后找到

    /* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res,

接下就是Refcom connect, 两端建立连接。最关键的在于这个状态表迁移的逻辑。如果能够理解整个流程还是比较好理解的。

你可能感兴趣的:(Bluetooth,stack)