藍牙系列之BlueDroid與MTK代碼分佈

目錄:

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文件聯繫CC++部分的代碼,包括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橋接接口(與Bluetoothserver 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);

}

然後調用到A2dpServiceconnect(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 FrameworkBluetooth 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接口(也就是各個profileserver層):

---裏自稱爲server層的profile接口。

----實現了關於藍牙java應用profile的API代碼,包括opp、hfp、hdp、a2dp、pan,gatt等等,而且也有部分server性質的代碼(不同的profile,有不同的設計)

由兩部分組成:

packages/apps/Bluetooth

android原生提供的profilea2dp,gatt,hdp,hfp,hid,map,opp,pan,pbap

生成bluetooth.apk

\mediatek\packages\apps\bluetooth\profiles

 

mtk增加的profile

MtkBt.apk

進程名:com.mediatek.bluetooth

“如果刪除,則連接不上,提示pareiconnet錯誤等信息。

因爲很多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和各種profileBT 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 APIsBTprocess調用的標準接口(所有的廠家都是按照這種接口定義來編寫自己的底層協議棧,並且你必須實現這些接口來讓你的BT hardware功能運行正常。BT HAL的的頭文件位於hardware/libhardware/include/hardware/bluetooth.hhardware/libhardware/include/hardware/bt_*.h文件中。

 

JNIsBluetoothA2dpInterface是一個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實現

\external\bluetooth\bluedroid\btif\

Bluetooth.c

生成在bluetooth.default.so以及提供各種profile interfaces供jni調用,如:

sock_if{}(只支持BTSOCK_RFCOMM  socket,不支持BTSOCK_SCO,BTSOCK_L2CAP);

bthfInterface{};//HFP接口

pan_if{}   

bt_av_interface{}//a2dp協議接口

 bthlInterface{}

….

 

 

 

 

五、BT stack----實現(中間協議+核心協議)。

一個完整的藍牙協議棧按其功能又可劃分爲四層:

核心協議層:

BBLMP)、

硬件實現

 

中間協議層:

L2CAPSDP線纜替換協議層(RFCOMM)、電話控制協議層(TCS-BIN)、

軟件實現

 

選用協議層:

PPPTCPTPUDPOBEXIrMCWAPWAE):由系統或者第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.cconnect方法。

 

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那個作用類似,是串聯frameworkblueZ的工具。

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不是這樣,mtkcombo芯片,中間的數據傳輸還通過STPSerial Transport Protocol)模塊。

kernel\net\bluetooth

核心協議和中間層協議實現。包括hci,hidrfcomm,sco,SDP等協議

核心協議層:

BBLMPLCAPSDP)、

 

中間協議層:

線纜替換協議層(RFCOMM)、電話控制協議層(TCS-BIN)、

 

 

以及socket接口定義和實現。

 

 

 

 

9驅動層

預備知識:1.Linux網絡體系結構

 

1.Linux網絡體系結構由以下五個部分組成,以及對應的網絡模型關係

1)系統調用接口 

應用層

berkeley庫:socket的基本操作

  • 3.1、socket()函數
  • 3.2、bind()函數
  • 3.3、listen()、connect()函數
  • 3.4、accept()函數
  • 3.5、read()、write()函數等
  • 3.6、close()函數

通過系統調用內陷到socket實現層,

比如:sys_socket()---》sock_creat()

2)協議無關接口 socket

應用層

socketnet/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,紅外就是這種標準的驅動模型。

藍牙就不完全是,藍牙只有模擬ethip設備時候走這標準。

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)沒有這一層

  1. 藍牙HCI驅動

物理傳輸

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/目錄下的代碼交互數據的接口。

  mtkcombo芯片,中間的數據傳輸還通過STPSerial Transport Protocol)模塊。

 

2.如何(誰)操作該tty設備?通過應用/system/bin/6620_launcher

\mediatek\external\combo_tool\src

比如註冊tty設備到hci corelist裏面。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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章