BTIF: Bluetooth Interface
BTU : Bluetooth Upper Layer
BTM: Bluetooth Manager
BTE: Bluetooth embedded system
BTA :Blueetooth application layer
CO: call out\CI: call in
HF : Handsfree Profile
HH: HID Host Profile
HL: Health Device Profile
AV:audio\vidio
ag: audio gateway
ar: audio/video registration
gattc: GATT client
BLE: Bluetooth Low Energy
再把左边的部分展开来看:
再把它摊开来看:
代码分布:
frameworks/base/core/java/android/Bluetooth:
frameworks/base/services/java/com/android/server/BluetoothManagerService.java:
里面提供java层使用的一些类和一些aidl文件,供其他进程调用。打开和关闭蓝牙的公共接口也在这里面。
packages/apps/Bluetooth:对应Bluetooth.apk,作为系统的蓝牙的核心进程而存在,com.android.bluetooth,调用framework的打开蓝牙接口后会启动该进程。其内部实现了多种上层蓝牙模式:opp,hfp,a2dp,hdp,hid等,并通过JNI调用与hal层完成联系。
/hardware/libhardware/include/hardware/bluetooth.h: hal层接口头文件
external/bluetooth/bluedroid:bluedroid官方协议栈
packages/apps/Settings/src/com/android/settings/Bluetooth: setting中蓝牙部分,界面相关
bluedroid蓝牙的调用方式:从apk到framework,framework再通过binder调用bluetooth应用,在通过应用层利用jni调用hal层实现蓝牙的各种请求。
OPP:文件传输规范
hfp:和电话相关,接听、挂断电话,以及连接sco通路
a2dp:蓝牙立体声规范,其中包含avrcp规范,avrcp规范实现了听歌时暂停、上下歌曲选择等控制模式。目前蓝牙耳机一般都支持这两种规范。
hid:人机交互规范,蓝牙鼠标键盘等
phap:电话号码簿访问协议
hdp:蓝牙医疗相关规范
文件路径:
frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
frameworks/base/services/java/com/android/server/BluetoothManagerService.java
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
hardware/libhardware/include/hardware/bluetooth.h
external/bluetooth/bluedroid/btif/src/bluetooth.c
先从framework提供的公共接口开始:
打开蓝牙使用BluetoothAdapter.java提供的方法getDefaultAdapter(),该方法中先获取BluetoothManagerService.java提供的binder对象,并且用该对象创建BluetoothAdapter实例。
获取到BluetoothAdapter实例用,调用enable方法,BluetoothAdapter的enable方法会调用BluetoothManagerService.java的enable,直接看BluetoothManagerService.java,在其中enable方法会启动一个service,这个service就是AdapterService。在启动这个service之后,先不看这个service的具体动作,继续看BluetoothManagerService会做什么。
在启动这个AdapterService之后,先不看这个AdapterService的具体动作,继续看BluetoothManagerService中的执行流程。在启动AdapterService,会回调mConnection的onServiceConnected()方法,在该方法中发送MESSAGE_BLUETOOTH_SERVICE_CONNECTED 消息,在处理该消息时,做了下面三件事:
1、得到AdapterService返回的IBluetooth.aidl接口的实现类。
mBluetooth = IBluetooth.Stub.asInterface(service)
2.调用IBluetooth.aidl提供的接口注册AdapterService的回调方法。
这样,不仅BluetoothManagerService可以通过aidl调用AdapterService中的方法,也实现了AdapterService可以回调BluetoothManagerService中的方法。回调方法如下所示,记住这个回调方法,后面会讲到。
mBluetooth.registerCallback(mBluetoothCallback)
3、第三件事就是调用IBluetooth.aidl提供的enable方法。下面就进入到AdapterService.java中。
下面就进入了package/apps下:
首先看onBind方法,返回了一个对象mBinder。执行其中的enable方法,
调用mAdapterStateMachine的sendMessage方法,发送USER_TURN_ON消息。。AdapterState.java是一个状态机,有以下几种状态:
mOffState:关闭
mPendingCommandState:活动,打开中
mOnState:打开
初始状态是mOffState。
发送消息后,在OffState状态下处理消息,首先切换状态到mPendingCommandState,然后调用adapterService.processStart()方法。
继续回到adapterService。执行如下代码,启动手机支持的所有profile,
手机支持的所有profile如下:
挨个启动上面所有的服务。每个服务启动之后都会调用adapterService中的notifyProfileServiceStateChanged方法。该方法中发送MESSAGE_PROFILE_SERVICE_STATE_CHANGED消息。消息处理如下:
如果所有服务都起来之后,给状态机AdapterState发送消息AdapterState.STARTED。
根据以上流程,现在状态机在mPendingCommandState状态,在该状态下处理STARTED消息。代码如下:
终于看到native方法。
对应的native方法在com_android_bluetooth_btservice_AdapterService.cpp中。调用了sBluetoothInterface结构体中的enable方法。该结构体的定义在bluetooth.h中,具体实现在bluetooth.c中。后面的代码这里不做具体分析。
回调主要使用
HAL_CBACK(bt_hal_cbacks, device_found_cb, num_properties, properties); HAL_CBACK就是一宏定义,就是调用结构体中对应的方法。
这里重点看一下一个bt_callbacks_t结构体,定义在bluetooth.h中,如下
初始化在bluetooth.c中,初始化的流程。
回到AdapterService.java,在服务启动时调用了initNative方法。看下jni中的initNative方法:
还是sBluetoothInterface结构体,继续看bluetooth.c文件,可以看到init方法中将地址sBluetoothCallbacks赋值给bt_callbacks_t,也就是,回调结构体的地址指向了sBluetoothCallbacks,看下sBluetoothCallbacks的定义。任然在jni中定义。这样在启动AdapterService时将回调地址传入了hal层。
最后,在驱动层完成蓝牙打开之后,会执行以下两个回调方法:
adapter_properties_callback:返回手机蓝牙设备的地址、名称、UUID等。
adapter_state_change_callback:更新AdapterProperties中蓝牙状态,发送广播通知蓝牙状态变化。
具体分析下adapter_state_change_callback。对应的jni方法为:adapter_state_change_callback,方法执行以下方法。
callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status);
也就是回调java层代码:JniCallback.java文件中stateChangeCallback方法。这时跳转到AdapterState.java中,执行stateChangeCallback()方法;发送了ENABLED_READY消息。根据以上分析,这时状态机还处于PendingCommandState,在该状态下处理ENABLED_READY消息,
做下面两个动作:状态切换到mOnState;更新adapterProperties中的蓝牙状态信息;通知蓝牙状态变为打开。具体看下notifyAdapterStateChange方法。主要是调用了adapterService类的方法。
adapterService.updateAdapterState(oldState, newState);
来到adapterService类。
可以看到,看是执行该服务中注册的回调方法。应该还能记得,之前在打开蓝牙操作初期,在BluetoothManagerService中注册了回调方法。因此又跳转到framework中,执行回调方法。在该回调方法中,发送广播通知蓝牙状态变化。
蓝牙打开的流程到这里,蓝牙打开从framework公共接口开始调用enable方法,执行到bluetooth.apk中,在该应用中通过jni注册回调方法和调用hal层打开蓝牙方法,在驱动层完成蓝牙上电等操作后,通过hal-jni回调到应用层中,应用通过aidl回调通知framework蓝牙状态变化,framework发送广播通知大家蓝牙打开。
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
packages/apps/Settings/src/com/android/settings/Bluetooth/*
BluetoothSettings.java中的startScanning命令,开始搜索。
如果a2dp没有在播放,就调用BluetoothAdapter.java中的startDiscovery()方法。
然后又回到AdapterService中,调用startDiscovery方法。在该方法中直接进入到jni层。
在jni层的函数中执行如下语句,依然是该结构体。
int ret = sBluetoothInterface->start_discovery();
具体的底层搜索方法暂不往下追踪。驱动层完成搜索之后,返回状态,根据返回的消息进行处理。回调消息分如下几种:包括搜索结果返回消息、搜索完成消息、搜索取消等。
BTA_DM_INQ_RES_EVT
BTA_DM_INQ_CMPL_EVT
BTA_DM_DISC_RES_EVT
BTA_DM_DISC_BLE_RES_EVT
BTA_DM_DISC_CMPL_EVT
BTA_DM_DI_DISC_CMPL_EVT
BTA_DM_SEARCH_CANCEL_CMPL_EVT
当收到搜索结果放回消息之后,会执行以下回调方法。
其中后面两个参数:设备属性个数和设备属性。其中设备属性包括:地址、名称、信号强度等属性。根据上面所讲的回调方法初始化,直接找到jni层的对应回调方法,可以看到会先后调用以下两个方法。
其中devicePropertyChangedCallback方法更新RemoteDevice类中的变量值。
deviceFoundCallback方法发送BluetoothDevice.ACTION_FOUND广播,通知setting中要更新界面显示该设备。
packages/apps/Settings/src/com/android/settings/Bluetooth/*
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/ BondStateMachine.java
packages/apps/Settings/src/com/android/settings/Bluetooth/BluetoothEventManager.java
packages/apps/Settings/src/com/android/settings/Bluetooth/CachedBluetoothDevice.java
在setting中点击设备之后开始进行配对。调用BluetoothDevice的createBond方法,走到AdapterService.java中的createBond方法。驱动BondStateMachine中的状态从StableState到
PendingCommandState。然后调用jni层createBondNative方法。又来到hal层接口sBluetoothInterface:
sBluetoothInterface->create_bond((bt_bdaddr_t *)addr);
同样,在底层完成配对之后进行回调:
找到对应的回调方法,JniCallback.java中的
void bondStateChangeCallback(int status, byte[] address, int newState) {
mBondStateMachine.bondStateChangeCallback(status, address, newState);
}
只有opp的弹框是bluetooth里,其他都是setting中弹框。
点击用蓝牙分享文件后,会调用BluetoothOppLauncherActivity.java,其中会判断当前蓝牙是否打开,如果没打开则进入BluetoothOppBtEnableActivity.java打开蓝牙,如果已经打开,则直接进入BluetoothDevicePicker.java选择传输文件设备选择。
蓝牙开启后会启动BluetoothMapService.java
在BluetoothMapService.java调用了BluetoothMapMasInstance.java的startRfcommSocketListener()方法,监听rfcomm端的连接请求,如果有连接请求,调用BluetoothMapService 的 onConnect()方法,在该方法里发送广播到setting中,setting弹框,用户确认后发送广播ACTION_CONNECTION_ACCESS_REPLY通知BluetoothMapService,BluetoothMapService收到广播后调用onConnectHandler方法,调用startObexServerSession方法,启动Obex传输通道。
类似map,连接后弹框都是广播给setting弹框
之前的audiopath比较复杂,要到DSP里面去硬解码。现在比较简单了,从驱动角度看,收到AF写下来的PCM数据后,经协议栈SBC编码后经HCI接口写入到蓝牙芯片,然后就发出去了。
SBC编码是针对蓝牙设备的一种音频编码方式,压缩率中等,但是cpu消耗低。电话对应HFP profile,音乐对应Profile。电话使用的是同步链路SCO,音乐时异步链路ACL,使用A2DP profile。另外还有其它profile,传问题,获取电话本,短信同步等。
使用A2DP时,先是进行音乐的解码,然后再把解码后的PCM进行SBC编码。A2DP支持下行audio编码采样率范围为8k-48k。在高通的大多数方案里面,SBC编码是在DSP里做的。
HFP,有两个角色AG和HF,正常情况下手机作为AG,耳机作为HF。但是手机代码中也有HF部分的代码
手机蓝牙芯片是三合一的,包括BT,FM和WLAN,使用一根天线。蓝牙耳机和蓝牙模块之间通过AT命令进行通信,分为master和slave,谁先连对方谁就是master。蓝牙功耗待机1mA左右,传文件要100多mA,听音乐60左右,打电话30。