Android藍(lán)牙協(xié)議棧fluoride(三) - 系統(tǒng)管理

關(guān)鍵線程

在整個(gè)協(xié)議棧中一共分三個(gè)主要線程:bt_jni_workqueue、bt_workqueue/btu message loop蹈矮、hci_thread注服。從名稱可以看出它們分別處理著各層的事務(wù):

  • bt_jni_workqueue:處理bt interface層的事務(wù)
  • bt_workqueue/btu message loop:處理bt application/profile舆驶、bt host的事務(wù)
  • hci_thread:處理hci層的事務(wù)

這樣實(shí)現(xiàn)的好處是調(diào)用方不會(huì)因調(diào)用方法阻塞而長(zhǎng)期阻塞拓轻,各個(gè)模塊在自己的線程中處理自己的事務(wù),完成后通過事件通知到調(diào)用方批幌。每個(gè)線程中有一個(gè)message loop础锐,線程中一直在RunLoop中運(yùn)行,需要將某個(gè)函數(shù)推送到線程運(yùn)行時(shí)可以通過調(diào)用message_loop_->task_runner()->PostTask()荧缘。

bt_jni_workqueue

該線程負(fù)責(zé)處理bt interface層的事務(wù)皆警,對(duì)于上層JNI調(diào)用協(xié)議棧的interface時(shí),將調(diào)用方法past到該線程運(yùn)行截粗,同樣的對(duì)下層的上報(bào)事件等也將事件past到該線程中處理信姓,然后由該線程向更上層上報(bào)鸵隧,它提供了以下幾個(gè)接口:

bt_status_t do_in_jni_thread(const base::Closure& task);
bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
                             const base::Closure& task)
bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
                                  char* p_params, int param_len,
                                  tBTIF_COPY_CBACK* p_copy_cback)
void btif_thread_post(thread_fn func, void* context);

例如:JNI初始化協(xié)議棧時(shí),在bt_workqueue線程中調(diào)用btif_transfer_contextbtif_init_ok函數(shù)past到bt_jni_workqueue線程執(zhí)行意推。

// Inform the bt jni thread initialization is ok.
  message_loop_->task_runner()->PostTask(
      FROM_HERE, base::Bind(base::IgnoreResult(&btif_transfer_context),
                            btif_init_ok, 0, nullptr, 0, nullptr));

bt_workqueue/btu message loop

這個(gè)線程是整個(gè)協(xié)議棧中核心線程豆瘫,profile、host中的處理都是在該線程中菊值,它提供以下幾個(gè)接口:

void bta_sys_sendmsg(void* p_msg);
bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
                             const base::Closure& task);

協(xié)議棧中實(shí)現(xiàn)了一個(gè)事件驅(qū)動(dòng)器外驱,各個(gè)模塊向驅(qū)動(dòng)器注冊(cè)事件以及事件的處理函數(shù),事件發(fā)生時(shí)調(diào)用bta_sys_sendmsg將其發(fā)送給驅(qū)動(dòng)器進(jìn)行處理腻窒。每個(gè)模塊通過宏#define BTA_SYS_EVT_START(id) ((id) << 8)生成自己模塊中的事件昵宇,即每個(gè)模塊中的事件數(shù)量不能超過255,收到事件時(shí)根據(jù)事件解析出該事件屬于哪個(gè)模塊id = (uint8_t)(p_msg->event >> 8);儿子,然后找到對(duì)應(yīng)模塊的處理函數(shù)進(jìn)行處理瓦哎。

hci_thread

hci層的線程主要是處理上層向下發(fā)送HCI 包的事務(wù),收到HCI數(shù)據(jù)包時(shí)直接將其上報(bào)到了bt_workqueue線程中。

此處只是介紹hci_thread線程工作方式惫周,具體的處理邏輯在后續(xù)HCI模塊時(shí)詳細(xì)介紹。

// 下發(fā)數(shù)據(jù)包
transmit_command()
 -> enqueue_command()
  -> message_loop_->task_runner()->PostTask(FROM_HERE, std::move(callback)) //此處還在bt_workqueue線程中
   -> event_command_ready() // hci_thread 線程執(zhí)行
    -> packet_fragmenter->fragment_and_dispatch()

// 收到數(shù)據(jù)包
hci_event_received()
 -> send_data_upwards.Run(from_here, packet) // send_data_upwards在初始化時(shí)由上層注冊(cè)
  -> post_to_hci_message_loop() // bte_main_boot_entry函數(shù)中調(diào)用set_data_cb函數(shù)注冊(cè)注冊(cè)到send_data_upwards
   -> btu_hci_msg_process() // bt_workqueue 線程執(zhí)行

狀態(tài)機(jī)

在協(xié)議棧中,有大量的狀態(tài)機(jī)腕够,具體實(shí)現(xiàn)如下:



每個(gè)模塊可能有N個(gè)事件,對(duì)應(yīng)event 1~event index N晓避,可能有M個(gè)狀態(tài)交排,每個(gè)事件在各個(gè)狀態(tài)都有兩個(gè)action(最多兩個(gè),也可能只有一個(gè)扑媚,或者一個(gè)都沒有)腰湾,執(zhí)行完action之后會(huì)切換到下一個(gè)狀態(tài)。實(shí)際上bt_workqueue中的事件驅(qū)動(dòng)器是結(jié)合狀態(tài)機(jī)來(lái)實(shí)現(xiàn)的疆股,其處理邏輯如下:

bool xxx_sm_execute(BT_HDR* p_msg) {
  // 根據(jù)當(dāng)前狀態(tài)獲取當(dāng)前狀態(tài)下事件的action列表
  state_table = bta_sys_st_tbl[bta_sys_cb.state];
  // 切換到下一個(gè)狀態(tài)
  bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE];
  // 執(zhí)行action
  for (i = 0; i < BTA_SYS_ACTIONS; i++) {
    action = state_table[p_msg->event & 0x00ff][i];
      (*bta_sys_action[action])((tBTA_SYS_HW_MSG*)p_msg);
  }
}

結(jié)合事件驅(qū)動(dòng)之后费坊,其邏輯關(guān)系如下圖:


實(shí)際上,在事件驅(qū)動(dòng)中每個(gè)模塊對(duì)應(yīng)一個(gè)處理函數(shù)xxx_sm_execute旬痹,在這個(gè)函數(shù)中進(jìn)入狀態(tài)機(jī)中根據(jù)每個(gè)狀態(tài)來(lái)決定事件真正的處理函數(shù)附井。

系統(tǒng)管理

核心數(shù)據(jù)結(jié)構(gòu)

以下結(jié)構(gòu)體是系統(tǒng)管理中核心的數(shù)據(jù)結(jié)構(gòu):

typedef struct {
  // 記錄各個(gè)模塊的事件回調(diào)函數(shù)
  tBTA_SYS_REG* reg[BTA_ID_MAX];
  bool is_reg[BTA_ID_MAX];
  // 系統(tǒng)管理器的狀態(tài)
  tBTA_SYS_HW_STATE state;
  // 系統(tǒng)狀態(tài)變化時(shí)的回調(diào)函數(shù)
  tBTA_SYS_HW_CBACK* sys_hw_cback[BTA_SYS_MAX_HW_MODULES];

  // 角色管理的回調(diào),DM中注冊(cè)
  tBTA_SYS_CONN_CBACK* prm_cb;
  // 功耗管理的回調(diào)两残,DM中注冊(cè)
  tBTA_SYS_CONN_CBACK* ppm_cb;
  // 連接策略變化的回調(diào)永毅,dm中注冊(cè)
  tBTA_SYS_CONN_CBACK* p_policy_cb;
  // sco連接狀態(tài)變化的回調(diào), audio/video模塊中注冊(cè)
  tBTA_SYS_CONN_CBACK* p_sco_cb;
  // 角色變化回調(diào)人弓, audio/video模塊中注冊(cè)
  tBTA_SYS_CONN_CBACK* p_role_cb;
} tBTA_SYS_CB;
  • 注冊(cè)事件處理函數(shù)沼死, 后續(xù)通過bta_sys_sendmsg函數(shù)發(fā)出事件:
// 注冊(cè)各個(gè)模塊的事件
void bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg) {
  bta_sys_cb.reg[id] = (tBTA_SYS_REG*)p_reg;
  bta_sys_cb.is_reg[id] = true;
}

// 處理事件
void bta_sys_event(BT_HDR* p_msg) {
  // 從事件中獲取模塊
  id = (uint8_t)(p_msg->event >> 8);

  //通過模塊id獲取到模塊的事件處理函數(shù),并執(zhí)行事件處理
  freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
}

狀態(tài)機(jī)中也提到崔赌,每個(gè)模塊的事件處理函數(shù)只有一個(gè)意蛀,在模塊內(nèi)根據(jù)狀態(tài)再做具體的事件處理耸别。如:

// 系統(tǒng)管理
static const tBTA_SYS_REG bta_sys_hw_reg = {bta_sys_sm_execute, NULL};
// SDP 
static const tBTA_SYS_REG bta_sdp_reg = {bta_sdp_sm_execute, NULL};
// 設(shè)備管理
static const tBTA_SYS_REG bta_dm_search_reg = {bta_dm_search_sm_execute, bta_dm_search_sm_disable};
// 等等。县钥。太雨。

狀態(tài)轉(zhuǎn)換

系統(tǒng)管理中有4個(gè)狀態(tài),6個(gè)事件魁蒜,狀態(tài)轉(zhuǎn)換如下:


系統(tǒng)管理中的狀態(tài)對(duì)應(yīng)的事件處理列表如下(僅舉例):

// 每個(gè)狀態(tài)對(duì)應(yīng)的事件處理以及狀態(tài)轉(zhuǎn)換
const uint8_t bta_sys_hw_off[][BTA_SYS_NUM_COLS] = {
/* Action 1               Action 2        Next State */
 {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING},
 {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING},
 {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
 {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF},
 {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF},
 {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}};
 
const uint8_t bta_sys_hw_on[][BTA_SYS_NUM_COLS] = {
/* Action 1              Action 2        Next State */
 {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
 {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
 {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
 {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
 {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
 {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}};

// action的函數(shù)列表囊扳, 對(duì)應(yīng)到各個(gè)事件
const tBTA_SYS_ACTION bta_sys_action[] = {
    /* device manager local device API events - cf bta_sys.h for events */
    bta_sys_hw_api_enable,        /* 0  BTA_SYS_HW_API_ENABLE_EVT    */
    bta_sys_hw_evt_enabled,       /* 1  BTA_SYS_HW_EVT_ENABLED_EVT */
    bta_sys_hw_evt_stack_enabled, /* 2  BTA_SYS_HW_EVT_STACK_ENABLED_EVT */
    bta_sys_hw_api_disable,       /* 3  BTA_SYS_HW_API_DISABLE_EVT     */
    bta_sys_hw_evt_disabled,      /* 4  BTA_SYS_HW_EVT_DISABLED_EVT  */
    bta_sys_hw_error              /* 5   BTA_SYS_HW_ERROR_EVT  */
};

其中BTA_SYS_IGNORE表示無(wú)action,遇到時(shí)直接跳過兜看。

事件處理

  • BTA_SYS_HW_API_ENABLE_EVT
    BTA_SYS_HW_API_ENABLE_EVT的處理函數(shù)是bta_sys_hw_api_enable锥咸,它的流程如下:如果state不等于HW_ON,發(fā)出BTA_SYS_EVT_ENABLED_EVT事件细移,否則調(diào)用DM設(shè)置的回調(diào)函數(shù)將BTA_SYS_HW_ON_EVT事件上報(bào)的DM搏予。

  • BTA_SYS_HW_EVT_ENABLED_EVT
    BTA_SYS_HW_EVT_ENABLED_EVT事件的處理函數(shù)是bta_sys_hw_evt_enabled,該函數(shù)中調(diào)用BTM_DeviceReset復(fù)位bt controller弧轧。

  • BTA_SYS_HW_EVT_STACK_ENABLED_EVT
    BTA_SYS_HW_EVT_STACK_ENABLED_EVT事件的處理函數(shù)是bta_sys_hw_evt_stack_enabled雪侥,該函數(shù)將BTA_SYS_HW_ON_EVT事件通過tBTA_SYS_CB::sys_hw_cback上報(bào)給DM。

  • BTA_SYS_HW_API_DISABLE_EVT
    BTA_SYS_HW_API_DISABLE_EVT事件的處理函數(shù)是bta_sys_hw_api_disable精绎,首先調(diào)用各個(gè)模塊注冊(cè)的disable函數(shù)(在注冊(cè)事件處理函數(shù)時(shí)同時(shí)注冊(cè)的)速缨, 然后切換到hw stoping狀態(tài),并發(fā)出BTA_SYS_EVT_DISABLED_EVT代乃。

  • BTA_SYS_HW_EVT_DISABLED_EVT
    BTA_SYS_HW_EVT_DISABLED_EVT事件的處理函數(shù)是bta_sys_hw_evt_disabled旬牲,該函數(shù)將BTA_SYS_HW_OFF_EVT事件通過tBTA_SYS_CB::sys_hw_cback上報(bào)給DM。

  • BTA_SYS_HW_ERROR_EVT
    BTA_SYS_HW_ERROR_EVT事件的處理函數(shù)是bta_sys_hw_error搁吓,該函數(shù)將BTA_SYS_HW_ERROR_EVT事件通過tBTA_SYS_CB::sys_hw_cback上報(bào)給DM原茅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市堕仔,隨后出現(xiàn)的幾起案子擂橘,更是在濱河造成了極大的恐慌,老刑警劉巖摩骨,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件通贞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡仿吞,警方通過查閱死者的電腦和手機(jī)滑频,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)唤冈,“玉大人峡迷,你說我怎么就攤上這事。” “怎么了绘搞?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵彤避,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我夯辖,道長(zhǎng)琉预,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任蒿褂,我火速辦了婚禮圆米,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘啄栓。我一直安慰自己娄帖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布昙楚。 她就那樣靜靜地躺著近速,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堪旧。 梳的紋絲不亂的頭發(fā)上削葱,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音淳梦,去河邊找鬼析砸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谭跨,可吹牛的內(nèi)容都是我干的干厚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼螃宙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了所坯?” 一聲冷哼從身側(cè)響起谆扎,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芹助,沒想到半個(gè)月后堂湖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡状土,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年无蜂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒙谓。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斥季,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情酣倾,我是刑警寧澤舵揭,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站躁锡,受9級(jí)特大地震影響午绳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜映之,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一拦焚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杠输,春花似錦赎败、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至峡钓,卻和暖如春妓笙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背能岩。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工寞宫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拉鹃。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓辈赋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親膏燕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钥屈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容