目錄:
0 應用層設計相關
一、application Framework
二、Bluetooth server層:服務層 包括兩部分--Bluetooth System service(部分)和Bluetooth profile;
2.1 mtk 封裝的庫(JNI和中間協議)
三、JNI
四、HAL
五、BT stack---- 實現(中間協議+核心協議)。
六、Vendor extension---也就是HCI驅動層的用戶空間接口
七 system\bluetoothBluetooth (mtk removed it )
八 內核層
九 驅動層
================================================================
0 應用層設計相關
|
kitkat_ibd\packages\apps\Settings\src\com\android\settings\bluetooth -----android 4.4
|
谷歌原生的profile管理接口。包括opp、hfp、hdp、a2dp、pan,gatt等等, 這裏自稱爲面向應用的profile接口。
|
|
|
|
一、application Framework
這個層的代碼主要是利用android.bluetoothAPIS和 bluetooth hardware進行交互。也就是通過BinderIPC機制調用bluetooth進程;
Android原生的BTFramework代碼位於framework/base/core/java/android.bluetooth/下。 |
這個目錄裏的代碼更像一個橋樑,裏面有供java層使用一些類,也有對應的aidl文件聯繫C、C++部分的代碼,包括opp、hfp、hdp、a2dp、pan,gatt等等 |
MTK廠商客製化的修改代碼位於 \mediatek\frameworks-ext\base\core\java\android\bluetooth |
重寫了原生部分的BT代碼,而且各種profile API:是橋接application和server之間的接口:BluetoothFtp.java /BluetoothHealth.ajva /BluetoothHid.java……. |
兩者什麼關係?增加了自己的相關profile server橋接接口(與Bluetooth的server層 profile對應的):如下:
LOCAL_SRC_FILES += \
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothBipi.aidl \
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothBipr.aidl\
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothBpp.aidl \
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothDun.aidl \
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothFtpCtrl.aidl\
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothFtpServer.aidl \
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothFtpServerCallback.aidl\
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothProfileManager.aidl\
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothSimap.aidl\
../../mediatek/frameworks-ext/base/core/java/android/bluetooth/IBluetoothSimapCallback.aidl\
../../mediatek/frameworks-ext/base/core/java/com/mediatek/bluetooth/service/IBluetoothPrxm.aidl\
../../mediatek/frameworks-ext/base/core/java/com/mediatek/bluetooth/service/IBluetoothPrxr.aidl\
../../mediatek/frameworks-ext/base/core/java/android/net/INetworkManagementIpv6EventObserver.aidl
如何編譯?
通過\frameworks\base的Android,.mk包含include$(LOCAL_PATH)/../../mediatek/frameworks-ext/base/config.mk完成把:mtk客製化增加的framework和原生的BTFramework的整合->生成:framework.jar。
下面僅僅是原生的例子:
比如A2DP的連接:framework/base/core/java/android/bluetooth/BluetoothA2dp.java中的connect(Bluetoothevice)方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); if (mService != null && isEnabled() && isValidDevice(device)) { try { return mService.connect(device); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } } if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; } |
通過Binder IPC通信機制,調用到packages/apps/Bluetooth/src/com.android.bluetooth.a2dp/A2dpService.java下一個內部私有類
A2dpService是一個繼承於ProfileService的類,而類ProfileService是繼承於Service類的。
private static class BluetoothA2dpBinder extendsIBluetoothA2dp.Stub{}的connect(BluetoothDevice)方法。
1 2 3 4 5 |
public boolean connect(BluetoothDevice device) { A2dpService service = getService(); if (service == null) return false; return service.connect(device); } |
然後調用到A2dpService的connect(BluetoothDevice)方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public boolean connect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { return false; }
int connectionState = mStateMachine.getConnectionState(device); if (connectionState == BluetoothProfile.STATE_CONNECTED || connectionState == BluetoothProfile.STATE_CONNECTING) { return false; }
mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device); return true; } |
這個過程就是Bluetooth Application Framework與Bluetooth Process的調用過程。
二、Bluetooth server層:服務層 包括兩部分--Bluetooth System service(部分)和Bluetoothprofile;
1.Bluetooth System service:
\mediatek\frameworks-ext\base\core\java\android\server |
編譯到framework.jar :mtk自增加的profilemanager server部分 |
2.Bluetooth profile API接口(也就是各個profile的server層):
---這裏自稱爲server層的profile接口。
----實現了關於藍牙java應用profile的API代碼,包括opp、hfp、hdp、a2dp、pan,gatt等等,而且也有部分server性質的代碼(不同的profile,有不同的設計)
由兩部分組成:
packages/apps/Bluetooth |
android原生提供的profile:a2dp,gatt,hdp,hfp,hid,map,opp,pan,pbap |
生成bluetooth.apk |
\mediatek\packages\apps\bluetooth\profiles
|
mtk增加的profile: |
MtkBt.apk: 進程名:com.mediatek.bluetooth “如果刪除,則連接不上,提示parei,connet錯誤等信息。 因爲很多pofile都連接不上。” |
|
|
|
mtk增加的profile:
include$(MY_MODULE_PATH)/profiles/prxm/Android.mk
include$(MY_MODULE_PATH)/profiles/prxr/Android.mk
include$(MY_MODULE_PATH)/profiles/simap/Android.mk
include$(MY_MODULE_PATH)/profiles/ftp/Android.mk
include$(MY_MODULE_PATH)/profiles/bpp/Android.mk
include$(MY_MODULE_PATH)/profiles/bip/Android.mk
include$(MY_MODULE_PATH)/profiles/dun/Android.mk
src_list +=profiles/prxm profiles/prxr profiles/simap profiles/ftp profiles/bppprofiles/bip profiles/dun
Bluetooth System service位於packages/apps/Bluetooth目錄下,它打包成一個android app包,並且在android framework 層實現BTservice和各種profile。BT app會通過JNI調用到HAL層。
A2dpService.java
的connect方法會發送一個StateMachine.sendMessage(A2dpStateMachine.CONNECT,device)的message,這個message會被A2dpStateMachine.java對象的processMessage(Message)方法接收到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
case CONNECT: BluetoothDevice device = (BluetoothDevice) message.obj; broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED);
if (!connectA2dpNative(getByteAddress(device)) ) { broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING); break; }
synchronized (A2dpStateMachine.this) { mTargetDevice = device; transitionTo(mPending); } // TODO(BT) remove CONNECT_TIMEOUT when the stack // sends back events consistently sendMessageDelayed(CONNECT_TIMEOUT, 30000); break; |
最重要的一句:connectA2dpNative(getByteAddress(device);
即會通過JNI調用到Native:
Com_android_bluetooth_a2dp.cpp(kitkat_ibd\packages\apps\bluetooth\jni): {"connectA2dpNative"
server層就調用到JNI層----》
////////////////////////////////////////////////////////////////////////////
mtk封裝的庫(JNI和中間協議)
////////////////////////////////////////////////////////////////////
\build\target\product\common.mk定義:
ifeq ($(strip$(MTK_BT_SUPPORT)), yes)
PRODUCT_PROPERTY_OVERRIDES += \
ro.btstack=blueangel
PRODUCT_PACKAGES += MtkBt \
btconfig.xml \
auto_pair_blacklist.conf \
libbtcusttable \
libbtcust \
libmtkbtextadp \
libextpbap \
libextavrcp \
libextopp \
libextsys \
libextftp \
libmtkbtextadpa2dp \
libmtka2dp \
libextbip \
libextbpp \
libexthid \
libextsimap \
libextjsr82 \
libbtsession \
libmtkbtextpan \
libextmap \
libmtkbtextspp \
libexttestmode \
libpppbtdun \
libextopp_jni \
libexthid_jni \
libextpan_jni \
libextftp_jni \
libextbpp_jni \
libextbip_jni \
libextpbap_jni \
libextavrcp_jni \
libextsimap_jni \
libextdun_jni \
libextmap_jni \
libextsys_jni \
libextadvanced_jni \
btlogmask \
btconfig \
libbtpcm \
libbtsniff \
mtkbt \
bluetooth.blueangel \
audio.a2dp.blueangel
Endif
\vendor\mediatek\huaqin82_we_iba_jb5\artifacts\out\target\product\huaqin82_we_iba_jb5\system\lib
三、JNI
與android.bluetooth有關的JNI代碼位於:分爲兩部分:
android原生的和mtk增加的:
\packages\apps\Bluetooth\jni, |
原生的BT JNI代碼: com_android_bluetooth_btservice_AdapterService.cpp: 控制本地藍牙芯片,加載藍牙hal層:BT_STACK_MODULE_ID定義在bluetooth。c。 com_android_bluetooth_hfp.cpp \ com_android_bluetooth_a2dp.cpp \ com_android_bluetooth_avrcp.cpp \ com_android_bluetooth_hid.cpp \ com_android_bluetooth_hdp.cpp \ com_android_bluetooth_pan.cpp \ com_android_bluetooth_gatt.cpp
|
生成:libbluetooth_jni.so 實現: 本地設備的hal控制; 調起各種中間協議; |
\mediatek\frameworks-ext\base\core\jni |
mtk平臺的BT jni代碼所在路徑 |
kitkat不使用 |
JNI的代碼會調用到HAL層,並且在確信一些BT操作被觸發時,會從HAL獲取一些回調。比如當BT設備被發現時。
再回到A2dp連接的例子中來,BT System Service通過JNI會調用到com_android_bluetooth_a2dp.cpp中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) { jbyte *addr; bt_bdaddr_t * btAddr; bt_status_t status;
ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface); if (!sBluetoothA2dpInterface) return JNI_FALSE;
addr = env->GetByteArrayElements(address, NULL); btAddr = (bt_bdaddr_t *) addr; if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; }
if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) { ALOGE("Failed HF connection, status: %d", status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } |
重點代碼是:status= sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr);
這個sBluetoothA2dpInterface結構體對象是在initNative(JNIEnv *env, jobject object)方法時得到的。
1 2 3 4 5 |
if ( (sBluetoothA2dpInterface = (btav_interface_t *) btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) { ALOGE("Failed to get Bluetooth A2DP Interface"); return; } |
四、HAL
4.1硬件抽象層定義android.bluetooth APIs和BTprocess調用的標準接口(所有的廠家都是按照這種接口定義來編寫自己的底層協議棧),並且你必須實現這些接口來讓你的BT hardware功能運行正常。BT HAL的的頭文件位於hardware/libhardware/include/hardware/bluetooth.h和hardware/libhardware/include/hardware/bt_*.h文件中。
JNI中sBluetoothA2dpInterface是一個btav_interface_t結構體,位於hardware/libhardware/include/hardware/bt_av.h中,定義爲:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
typedef struct {
/** set to sizeof(btav_interface_t) */ size_t size; /** * Register the BtAv callbacks */ bt_status_t (*init)( btav_callbacks_t* callbacks );
/** connect to headset */ bt_status_t (*connect)( bt_bdaddr_t *bd_addr );
/** dis-connect from headset */ bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr );
/** Closes the interface. */ void (*cleanup)( void );
} btav_interface_t;
就是定義好統一的協議棧接口,廠家按照該定義來實現自己的bt協議棧(與profile不是一個概念,這裏定義的是中間協議+核心協議)。
4.2 HAL實現
|
|
五、BT stack----實現(中間協議+核心協議)。
一個完整的藍牙協議棧按其功能又可劃分爲四層:
核心協議層: |
(BB、LMP)、 |
硬件實現 |
|
中間協議層: |
L2CAP、SDP線纜替換協議層(RFCOMM)、電話控制協議層(TCS-BIN)、 |
軟件實現 |
|
選用協議層: |
(PPP、TCP、TP、UDP、OBEX、IrMC、WAP、WAE):由系統或者第3方提供 |
軟件實現 |
例如android的:OBEX \frameworks\base\obex javax.obex.jar |
作爲默認的BT stack,(4.2之前是bluez作爲協議棧的)
代碼位於:
external/bluetooth/bluedroid下, |
這個stack實現了通用的BT HAL並且也可以通過擴展和改變配置來自定義。 |
生成libbt-brcm_stack.a.因爲商業關係,谷歌把bluez的協議換成的bocom公司的,bluedroid裏面的協議代碼可以作爲自己編寫新的profile時候的參考。 |
vendor\mediatek\huaqin82_we_iba_jb5\artifacts\out\target\product\huaqin82_we_iba_jb5\obj\STATIC_LIBRARIES\libmtkbtstack2_intermediates |
同上 |
mtk自定重新寫了一套BT協議棧libmtkbtstack2.a libmtkbtstack.a 增加了BLE支持所需要的gatt協議。 #ar -tlibmtkbtstack2.a列出其包含的.o mele.o rfc_ctl.o rfc_fcs.o rfc_sm.o rfc_util.o rfcomm.o sdap.o sdp.o sdpclient.o sdpserv.o avc.o avctp.o avctp l2cap等等 |
|
|
|
A2dp的連接會調用到external/bluetooth/bluedroid/btif/src/btif_av.c的connect方法。
1 2 3 4 5 6 7 |
static bt_status_t connect(bt_bdaddr_t *bd_addr) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); CHECK_BTAV_INIT();
return btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, bd_addr, connect_int); } libbt-brcm_stack.a.與libmtkbtstack2.a兩者什麼關係???????
|
六、Vendor extension---也就是HCI驅動層的用戶空間接口
爲了追蹤添加自定義拓展和一個HCI層,你可以創建一個libbt-vendor模塊並且指定這些組件。
\external\bluetooth\bluedroid\hci |
HCI驅動層的用戶空間接口,完成dlopen("libbt-vendor.so", RTLD_NOW); 文件系統接口就是:bt_vnd_if。 |
|
|
七system\bluetoothBluetooth --mtk removed it
適配層代碼,和framework那個作用類似,是串聯framework與blueZ的工具。
BOARD_HAVE_BLUETOOTH沒定義,mtk平臺也是棄用,只是利用裏面的標準藍牙配置參數(EnableLE等等 有時間研究一下)
#ifeq($(BOARD_HAVE_BLUETOOTH),true)
include $(all-subdir-makefiles)
#endif
#ifeq($(MTK_BT_SUPPORT),true)
include $(LOCAL_PATH)/data/Android.mk
#endif
八內核層---
mtk平臺android2.3以上的平臺都不用blueZ,使用MTK自編寫的blueangel,這裏僅僅以blueZ爲藍本分析數據流程。
kernel\drivers\bluetooth |
對各種接口的Bluetoothdevice的驅動實例(意思就是指導大家porting驅動的時候做一個參考設計)。例如:USB接口,串口,SDIO等,例如: --Hci_ldis.c實現一個藍牙專用的線路規程。但是mtk不是這樣,mtk是combo芯片,中間的數據傳輸還通過STP(Serial Transport Protocol)模塊。 |
||||||
kernel\net\bluetooth |
核心協議和中間層協議實現。包括hci,hid,rfcomm,sco,SDP等協議
以及socket接口定義和實現。 |
||||||
|
|
9驅動層
預備知識:1.Linux網絡體系結構
1.Linux網絡體系結構由以下五個部分組成,以及對應的網絡模型關係
1)系統調用接口 |
應用層 |
berkeley庫:socket的基本操作
通過系統調用內陷到socket實現層, 比如:sys_socket()---》sock_creat() |
2)協議無關接口 socket |
應用層 |
由socket(net/socket.c)來實現的。它提供了一組通用函數來支持各種不同協議。 操作接口是: file_operations socket_file_ops{} 如何與協議稱通信?通過file ops。如下 通過sock->ops->recvmsg()//ops來自層註冊好的接口 …... |
3)網絡協議 |
傳輸層+網絡層 |
net_family實現各種協議的數據封裝。 例如: proto_ops hci_sock_ops 藍牙的hci協議:hci_sock.c proto_ops l2cap_sock_ops = { //l2cap_sock.c proto_ops inet6_dgram_ops IPv6的協議 ……. |
4)設備無關接口 |
數據連路層 |
1.實現對netdevice的管理。包括設備驅動程序可能會通過調用 register_netdevice 或 unregister_netdevice在內核中進行註冊或註銷 2.與協議層的數據(socket)的bufer緩衝; 不同的網絡設備功能來決定,比如網卡,wifi,紅外就是這種標準的驅動模型。 藍牙就不完全是,藍牙只有模擬eth,ip設備時候走這標準。 |
5)設備驅動程序。 |
數據鏈路層 |
1負責管理物理網絡設備的設備驅動程序:net_device_ops和net_device的創建 。例如,包串口使用的 SLIP驅動程序以及以太網設備使用的以太網驅動程序都是這一層的設備。 讀寫數據的操作對象是:sk_buff 例如: 6lowpan.c (\kernel\net\ieee802154):static const struct net_device_opslowpan_netdev_ops ----------------- Irda_framer.c (\mediatek\platform\mt6582\kernel\drivers\ldvt\irda):static const structnet_device_ops mt_irda_netdev_ops= 接受:mt_irda_irq()---》mt_irda_rx_one_skb()---》netif_rx() 發送:mt_irda_xmit() ------------------- mtk藍牙就是:bt_net_dev.c,實現模擬IP設備(藍牙作爲網關設備,實現對其他藍牙設備的ip控制)和eth設備(就是藍牙手機做網卡) 注意:藍牙的一般通信(常規的profile)沒有這一層 |
|
物理傳輸 |
stp_uart.c |
mtk平臺的設備驅動組成:
CONFIG_MTK_COMBO=m
CONFIG_MTK_COMBO_BT=m--------生成ko
CONFIG_MTK_COMBO_GPS=m
CONFIG_MTK_COMBO_WIFI=m
網絡設備驅動層 |
bt_net_dev.c |
註冊網絡設備驅動,實現了net_device_ops和創建net_device---kikat棄用 在alps\mediatek\config\mt65xx\autoconfig\kconfig\platform中添加下面定義: CONFIG_MTK_BT_NET_DEV=y
|
1.功能:實現模擬IP設備(藍牙作爲網關設備,實現對其他藍牙設備的ip控制)和eth設備(就是藍牙手機做網卡) net_device_ops和net_device的創建;
2應用範圍: 2.1藍牙共享網絡(Bluetooth tethering),也就是Personal Area Networking Profile |
通過tty串口驅動與藍牙芯片交互 |
stp_uart.c |
1.tty_register_ldisc註冊tty驅動接口。 ----線路ID(可以自定義):N_MTKSTP ---stp_uart_tty_read()++stp_uart_tty_write() +stp_uart_tty_poll()爲空--》 所以上層就不能再通過讀寫tty設備的方式發送、接收HCI數據。取而代之的,N_MTKSTP中實現了對上層的socket接口,即與/net/bluetooth/目錄下的代碼交互數據的接口。 mtk是combo芯片,中間的數據傳輸還通過STP(Serial Transport Protocol)模塊。
2.如何(誰)操作該tty設備?通過應用/system/bin/6620_launcher \mediatek\external\combo_tool\src 比如註冊tty設備到hci core的list裏面。mtk這裏什麼也沒有做,why? 一般都是在tty驅動裏面通過HCIUARTSETPROTO完成tty設備註冊到HCI core。
3.tty如何與hci socket之間通信?通過HCI core 。所以驅動需要alloc分配和註冊hci設備到:hci_dev_list這樣一個鏈表。 要hci_register_dev()(實例Hci_ldis裏面的)來完成於socket的綁定。 ”但是mtk不知道放到哪裏無完成註冊hci_register_dev。“--還與stp掛鉤,這塊先不跟進。
HCI socket通過hci_dev_list即可完成對tty驅動(也就是HCI設備驅動的)操作。
|
生成mtk_stp_bt.ko 編譯命令: ./mk r k\mediatek\kernel\drivers\combo |
藍牙與STP之間 |
stp_chrdev_bt.c |
|
生成 mtk_stp_bt.ko. 編譯命令: ./mk r k\mediatek\kernel\drivers\combo |
|
|
|
|