蓝牙系列之BlueDroid与MTK代码分布

蓝牙系列之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文件联系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实现

\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----实现(中间协议+核心协议)。

一个完整的蓝牙协议栈按其功能又可划分为四层:

核心协议层:

(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等协议

核心协议层:

(BB、LMP、LCAP、SDP)、

中间协议层:

线缆替换协议层(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

应用层

由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)没有这一层

蓝牙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/目录下的代码交互数据的接口。

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

评论留言