Android藍芽原始碼分析——BTA層訊息分發
這裡BTA是Bluetooth Application的縮寫,從上層下來的請求都要經過這個BTA層,通過傳送訊息的方式將請求丟到BTA層中處理。這個傳送訊息的函式定義在bta_sys_main.c中,如下:
void bta_sys_sendmsg(void *p_msg)
{
GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg);
}
我們在進入GKI_send_msg前,先搞清楚bta_sys_cb,這貨定義在bta_sys_main.c中,如下:
/* system manager control block definition */
tBTA_SYS _CB bta_sys_cb;
這個bta_sys_cb是BTA層的總體Control Block。資料結構定義在bta_sys_int.h中,如下:
/* system manager control block */
typedef struct
{
tBTA_SYS_REG *reg[BTA_ID_MAX]; /* registration structures */
BOOLEAN is_reg[BTA_ID_MAX]; /* registration structures */
......
} tBTA_SYS_CB;
這裡值得注意的是reg,這是個陣列,陣列型別是tBTA_SYS_REG,裡面是BTA下面的各個子系統的回撥,最多有BTA_ID_MAX個。我們看看tBTA_SYS_REG的定義:
/* registration structure */
typedef struct
{
tBTA_SYS_EVT_HDLR *evt_hdlr;
tBTA_SYS_DISABLE *disable;
} tBTA_SYS_REG;
/* event handler function type */
typedef BOOLEAN (tBTA_SYS_EVT_HDLR)(BT_HDR *p_msg);
/* disable function type */
typedef void (tBTA_SYS_DISABLE)(void);
原來就是兩個函式,一個是關於事件處理的,一個是關於disable的。就是說BTA下面的各個子系統都有自己的事件處理邏輯和disable邏輯。
我們再看看有哪些子系統,各子系統ID定義如下:
/* SW sub-systems */
#define BTA_ID_SYS 0 /* system manager */
/* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */
#define BTA_ID_DM 1 /* device manager */
#define BTA_ID_DM_SEARCH 2 /* device manager search */
#define BTA_ID_DM_SEC 3 /* device manager security */
#define BTA_ID_DG 4 /* data gateway */
#define BTA_ID_AG 5 /* audio gateway */
#define BTA_ID_OPC 6 /* object push client */
#define BTA_ID_OPS 7 /* object push server */
#define BTA_ID_FTS 8 /* file transfer server */
#define BTA_ID_CT 9 /* cordless telephony terminal */
#define BTA_ID_FTC 10 /* file transfer client */
#define BTA_ID_SS 11 /* synchronization server */
#define BTA_ID_PR 12 /* Printer client */
#define BTA_ID_BIC 13 /* Basic Imaging Client */
#define BTA_ID_PAN 14 /* Personal Area Networking */
#define BTA_ID_BIS 15 /* Basic Imaging Server */
#define BTA_ID_ACC 16 /* Advanced Camera Client */
#define BTA_ID_SC 17 /* SIM Card Access server */
#define BTA_ID_AV 18 /* Advanced audio/video */
#define BTA_ID_AVK 19 /* Audio/video sink */
#define BTA_ID_HD 20 /* HID Device */
#define BTA_ID_CG 21 /* Cordless Gateway */
#define BTA_ID_BP 22 /* Basic Printing Client */
#define BTA_ID_HH 23 /* Human Interface Device Host */
#define BTA_ID_PBS 24 /* Phone Book Access Server */
#define BTA_ID_PBC 25 /* Phone Book Access Client */
#define BTA_ID_JV 26 /* Java */
#define BTA_ID_HS 27 /* Headset */
#define BTA_ID_MSE 28 /* Message Server Equipment */
#define BTA_ID_MCE 29 /* Message Client Equipment */
#define BTA_ID_HL 30 /* Health Device Profile*/
#define BTA_ID_GATTC 31 /* GATT Client */
#define BTA_ID_GATTS 32 /* GATT Client */
#define BTA_ID_BLUETOOTH_MAX 33 /* last BT profile */
/* FM */
#define BTA_ID_FM 34 /* FM */
#define BTA_ID_FMTX 35 /* FM TX */
/* SENSOR */
#define BTA_ID_SSR 36 /* Sensor */
/* GPS */
#define BTA_ID_GPS 37 /* GPS */
/* GENERIC */
#define BTA_ID_PRM 38
#define BTA_ID_SYSTEM 39 /* platform-specific */
#define BTA_ID_SWRAP 40 /* Insight script wrapper */
#define BTA_ID_MIP 41 /* Multicase Individual Polling */
#define BTA_ID_RT 42 /* Audio Routing module: This module is always on. */
/* JV */
#define BTA_ID_JV1 43 /* JV1 */
#define BTA_ID_JV2 44 /* JV2 */
#define BTA_ID_MAX (43 + BTA_DM_NUM_JV_ID)
可見一共有43個ID,另外加兩個JV_ID。這些ID中比較眼熟的有BTA_ID_GATTC和BTA_ID_GATTS,應該都是和GATT相關的,一個是Server,一個是Client。
我們再來看bta_sys_cb是在哪裡初始化的,在bta_sys_main.c中,如下:
BTA_API void bta_sys_init(void)
{
memset(&bta_sys_cb, 0, sizeof(tBTA_SYS_CB));
ptim_init(&bta_sys_cb.ptim_cb, BTA_SYS_TIMER_PERIOD, p_bta_sys_cfg->timer);
bta_sys_cb.task_id = GKI_get_taskid();
/* register BTA SYS message handler */
bta_sys_register( BTA_ID_SYS, &bta_sys_hw_reg);
/* register for BTM notifications */
BTM_RegisterForDeviceStatusNotif ((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback );
}
這個bta_sys_init就是初始化整個BTA的,是在btu_task執行緒中呼叫的。而btu_task執行緒入口是在bte_main.c的bte_main_enable中,再往上走是btif_core.c的btif_enable_bluetooth中,看樣子這是開啟藍芽時呼叫的,再往上走是bluetooth.c的enable函式。而btif_task初始化是在btif_core.c中的btif_init_bluetooth,往上是bluetooth.c中的init函式,相比btu_task還是簡單些。
我們回到bta_sys_init,這裡我們關注的邏輯是首先設定bta_sys_cb的task_id為BTU TASK。然後註冊BTA_ID_SYS的訊息處理函式。我們看這個bta_sys_register是怎麼註冊的,如下:
void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg)
{
bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg;
bta_sys_cb.is_reg[id] = TRUE;
}
邏輯很簡單,我們看看GATTC是在哪裡註冊的,是在bta_gattc_api.c中的BTA_GATTC_AppRegister,如下:
void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb)
{
tBTA_GATTC_API_REG *p_buf;
if (bta_sys_is_register(BTA_ID_GATTC) == FALSE)
{
bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
}
......
return;
}
這個函式是在btif_gatt_client.c的btgattc_handle_event中呼叫,往上走是註冊clientIf時也就是開啟gatt時。所以我們瞭解了當開啟gatt連線時,會自動去註冊GATTC子系統。這個子系統的回撥在bta_gattc_api.c中:
static const tBTA_SYS_REG bta_gattc_reg =
{
bta_gattc_hdl_event, // 在bta_gattc_main.c中
BTA_GATTC_Disable
};
我們重點關注GATTC子系統下的事件處理函式為bta_gattc_hdl_event,這個之後會用到的。因為所有Gatt相關的事件處理最終都調到了這個。
我們回到bta_sys_sendmsg,這裡呼叫了GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg);
,這個bta_sys_cb的task_id毫無疑問是btu_task了,其中的mbox是什麼呢?我們來看p_bta_sys_cfg是在哪裡初始化的,在bta_sys_cfg.c中,如下:
/* GKI task mailbox event for BTA. */
#ifndef BTA_MBOX_EVT
#define BTA_MBOX_EVT TASK_MBOX_2_EVT_MASK
#endif
/* GKI task mailbox for BTA. */
#ifndef BTA_MBOX
#define BTA_MBOX TASK_MBOX_2
#endif
/* GKI timer id used for protocol timer for BTA. */
#ifndef BTA_TIMER
#define BTA_TIMER TIMER_1
#endif
const tBTA_SYS_CFG bta_sys_cfg =
{
BTA_MBOX_EVT, /* GKI mailbox event */
BTA_MBOX, /* GKI mailbox id */
BTA_TIMER, /* GKI timer id */
APPL_INITIAL_TRACE_LEVEL /* initial trace level */
};
tBTA_SYS_CFG *p_bta_sys_cfg = (tBTA_SYS_CFG *)&bta_sys_cfg;
就是說bta對應的mailbox是BTA_MBOX,也就是TASK_MBOX_2。每個task都有4個mailbox用於接收buff,這個是2號郵箱。
好了,bta_sys_sendmsg就是向btu task的2號郵箱傳送了msg。處理函式在哪裡呢?在btu_task中如下:
if (event & TASK_MBOX_2_EVT_MASK)
{
while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
{
bta_sys_event(p_msg);
}
}
是在bta_sys_event中,傳送訊息可以在別的執行緒,但是處理訊息都回到了btu_task執行緒內部。
BTA_API void bta_sys_event(BT_HDR *p_msg)
{
UINT8 id;
BOOLEAN freebuf = TRUE;
/* get subsystem id from event */
id = (UINT8) (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);
}
if (freebuf)
{
GKI_freebuf(p_msg);
}
}
這裡根據event獲取id,然後獲取到對應BTA的子系統的回撥,每個子系統有自己的事件處理函式的。所以如果這裡是GATT相關的事件,則會走到GATT的事件處理函式,為bta_gattc_hdl_event,在bta_gattc_main.c中。
總結一下,所有BTA訊息最終都送到了BTU TASK中,由bta_sys_event來處理。如果是Gatt相關的訊息,則最終由bta_gattc_hdl_event處理。