編輯:關於Android編程
這裡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處理。
Android基礎入門教程——8.3.16 Canvas API詳解(Part 1)標簽(空格分隔): Android基礎入門教程本節引言: 前面
實現功能:實現網絡音樂搜索功能實現網絡音樂下載功能下載好的音樂目前不在播放器內,可以通過文件浏覽器查看。後續將博文,將實現歌詞和下載音樂掃描功能。經過將近4天,才發布這一
一.AsyncTask的簡介在Android中實現異步任務機制有兩種方式,Handler和AsyncTask。Handler模式需要為每一個任務創建一個新的線程,任務完成
概述在Android開發中LayoutInflater的應用非常普遍,可以將res/layout/下的xml布局文件,實例化為一個View或者ViewGroup的控件。與