1. 前言
蓝牙专栏
自1994年由爱立信推出至今,蓝牙技术已经走过了20个岁月。从最初的Bluetooth V1.0,到如今的Bluetooth V4.0(最新的为V4.1,2013年底发布),经历了近9个版本的修订后,发展为当前的状况。
说实话,如今的蓝牙4.0,简直是一个大杂烩:BR/EDR沿用旧的蓝牙规范;LE抄袭802.15.4;AMP直接使用802.11。而这一切的目的,就是以兼容性和易用性为基础,在功耗和传输速率之间左右为难。蜗蜗以为,这并不是优雅的设计。
不过没关系,存在即合理。因此蜗蜗就开出了这样一个专题,希望能够将蓝牙技术上上下下的知识,整理出来,以便在加深自己对蓝牙技术的理解的同时,能够给从事蓝牙相关工作的读者一点启发。
本文是这个专题的第一篇文章,主要基于蓝牙4.0规范(Core_V4.0.pdf),描述蓝牙技术的基本概念。
2. 蓝牙技术的概述
2.1 两种蓝牙技术:Basic Rate(BR)和Low Energy(LE)
蓝牙协议包括两种技术:Basic Rate(简称BR)和Low Energy(简称LE)。这两种技术,都包括搜索(discovery)管理、连接(connection)管理等机制,但它们是不能互通的!这也是蜗蜗抱怨蓝牙协议不优雅的原因之一。
厂商要么实现这两种技术中的一种,这时就只能和同样实现了这个技术的设备互通,而不能和实现另外一种技术的设备互通。如果厂商要确保能和所有的蓝牙设备互通,那么就只能同时实现两种技术,而不去管是否真的需要,这样就能碰到什么人说什么话了!
2.1.1 Basic Rate(BR)
Basic Rate是正宗的蓝牙技术,可以包括可选(optional)的EDR(Enhanced Data Rate)技术,以及交替使用的(Alternate)的MAC(Media Access Control)层和PHY层扩展(简称AMP)。说着真拗口,不过通过背后的应用场景,就好理解了:
蓝牙诞生之初,使用的是BR技术,此时蓝牙的理论传输速率,只能达到721.2Kbps。在那个年代,56Kbps的Modem就是高大上了,这个速度可以说是惊为天人了啊!但是科技变化太快了,BR技术转眼就过时了。那怎么办呢?缝缝补补一下,增强速度呗,Enhanced Data Rate就出现了。
使用EDR技术的蓝牙,理论速率可以达到2.1Mbps。这一次的升级换代,还算优雅,因为没有改变任何的硬件架构、软件架构和使用方式上的改变。
也许你也猜到了,EDR又落伍了,看看人家WIFI(WLAN),几十Mbps,上百Mbps,咱们才2.1Mbps,也太寒酸了吧!那怎么办呢?蓝牙组织想了个坏主意:哎,WIFI!把你的物理层和MAC层借我用用呗!这就是AMP(Alternate MAC and PHY layer extension)。艾玛,终于松口气了,我们可以达到24Mbps了。
不过呢,由于蓝牙自身的物理层和AMP技术差异太明显了,这次扩展只能是交替使用(Alternate)的,也就是说,有我(BR/EDR)没你(AMP)。嗯!不优雅!
埋个问题:只能交替使用,那它们怎么切换呢?蜗蜗会在后续的内容中,根据主流蓝牙芯片的解决方案,来探讨一下该问题。
【注1:细心的读者可能会注意到,这里特别强调了optional和alternate这两个字眼,这是蓝牙Spec的原话。它意味着,BR和EDR是可以同时存在的,但BR/EDR和AMP只能二选一。】
2.1.2 Low Energy(LE)
上面所讲的BR技术的进化路线,就是传输速率的加快、加快、再加快。但能量是守恒的,你想传的更快,代价就是消耗更多的能量。而有很多的应用场景,并不关心传输速率,反而非常关心功耗。这就是Bluetooth LE(称作蓝牙低功耗)产生的背景。
LE技术相比BR技术,差异非常大,或者说就是两种不同的技术,凑巧都加一个“蓝牙”的前缀而已。后面我们会详细的解释这种差异,以及LE的行为特征。
2.2 蓝牙系统的组成
蓝牙系统的组成,涉及到Bluetooth Application、Bluetooth Core、Bluetooth Host、Bluetooth Controller等词汇,不知道是因为对英文理解的歧义,还是因为蓝牙规范本身定义的歧义,蜗蜗理解这些词汇时感觉有点别扭。因此特意在这个章节中,对相关概念及其背后的意义进行说明。
上图描述了蓝牙系统的组成, 我们需要注意如下特点:
1)图中所描述的蓝牙系统的组成部分,如Bluetooth Core和Bluetooth Application,如Host和Controller,都是指“逻辑实体”。所谓的“逻辑实体”,需要和日常生活中的“物理实体”区隔开。如在做电路设计时,一个蓝牙芯片、一个主控CPU,就是指物理实体。而蓝牙协议所描述的这些“逻辑实体”,不一定会和物理实体一一对应,如在实际应用中,Host和Bluetooth Application可能会位于同一个物理实体中(主控CPU),而Controller单独位于另一个物理实体中(蓝牙芯片)。
2)蓝牙协议规定了两个层次的协议,分别为蓝牙核心协议(Bluetooth Core)和蓝牙应用层协议(Bluetooth Application)。蓝牙核心协议关注对蓝牙核心技术的描述和规范,它只提供基础的机制,并不关心如何使用这些机制;蓝牙应用层协议,是在蓝牙核心协议的基础上,根据具体的应用需求,百花齐放,定义出各种各样的策略,如FTP、文件传输、局域网等等。
3)Bluetooth Core由两部分组成,Host和Controller。这两部分在不同的蓝牙技术中(BR/EDR、AMP、LE),承担角色略有不同,但大致的功能是相同的。Controller负责定义RF、Baseband等偏硬件的规范,并在这之上抽象出用于通信的逻辑链路(Logical Link);Host负责在逻辑链路的基础上,进行更为友好的封装,这样就可以屏蔽掉蓝牙技术的细节,让Bluetooth Application更为方便的使用。
4)在一个系统中,Host只有一个,但Controller可以一个,也可以有多个。如:单独的LE Controller;单独的BR/EDR Controller;单独的LE+BR/EDR Controller;在单独的BR/EDR Controller或LE+BR/EDR Controller基础上,增加一个活多个额外的AMP Controller。
【注2:有关Bluetooth Core的详细描述,蜗蜗会在下一篇文章中描述,本文就不再深入介绍了。】
3. BR/EDR vs LE vs AMP
二、蓝牙的协议框架
A2dp Handset opp Hid Health Pan Map Dun...
| | |...
CORE Stack Specification
|
Host Controller Interface
|
chip
三、Android 4.4(Kitkat)上蓝牙的启动流程
1.服务启动
系统启动时在SystemServer中注册蓝牙服务管理BluetoothManagerService服务:
if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
Slog.i(TAG, "No Bluetooh Service (emulator)");
} else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
Slog.i(TAG, "No Bluetooth Service (factory test)");
} else if (!context.getPackageManager().hasSystemFeature
(PackageManager.FEATURE_BLUETOOTH)) {
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
} else if (disableBluetooth) {
Slog.i(TAG, "Bluetooth Service disabled by config");
} else {
Slog.i(TAG, "Bluetooth Manager Service");
bluetooth = new BluetoothManagerService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);
}
其它进程通过binder机制调用该服务,该服务属于综合服务管理类,包括AdapterService的启动、蓝牙适配器Adapter的管理等。
2.蓝牙启动模式
在4.4上蓝牙的启动模式分两种:QuietEnableMode和普通从“设置”里打开两种方式,前一中方式主要是为了NFC的Handover功能——在传递媒体大文件时nfc会打开蓝牙传送。
3.蓝牙关键服务启动和回调处理
下面就以在“设置”中打开为例描述下蓝牙的启动流程:
1)蓝牙所有的profiles位于上层代码中/packages/apps/Bluetooth目录下,常用的几个profiles包括A2dp、HeadSet、Opp、Hid、Pan等,并且Android 4.4上蓝牙协议栈采用的是BRCM和Google共同开发的bluedroid;
2)启动流程涉及代码结构Settings -> Bluetooth -> framework -> bluedroid -> hci -> chip,启动过程是先启动AdapterService并初始化bluedroid,然后启动所有的profile service(A2dpService、HeadsetService等),
成功加载所支持的profiles后使能bluedroid给蓝牙上电,蓝牙上电成功后回bluedroid回调类com_android_bluetooth_btservice_AdapterService.cpp的接口static void adapter_state_change_callback(bt_state_t status),通过JNI回调通知AdapterStateMachine更新Adapter状态,并且通知注册到AdapterService上回调:
void updateAdapterState(int prevState, int newState){
if (mCallbacks !=null) {
int n=mCallbacks.beginBroadcast();
Log.d(TAG,"Broadcasting updateAdapterState() to " + n + " receivers.");
for (int i=0; i <n;i++) {
try {
mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState,newState);
} catch (RemoteException e) {
Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
}
}
mCallbacks.finishBroadcast();
}
}
mCallbacks该回调是BluetoothManagerService在成功bind到AdapterService时注册的回调mBluetoothCallback:
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{
if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
mIsBluetoothServiceConnected = true;
IBinder service = (IBinder) msg.obj;
synchronized(mConnection) {
if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
break;
} // else must be SERVICE_IBLUETOOTH
//Remove timeout
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
mBinding = false;
mBluetooth = IBluetooth.Stub.asInterface(service);
try {
boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
}
} catch (RemoteException e) {
Log.e(TAG,"Unable to call configHciSnoopLog", e);
}
if (mConnection.isGetNameAddressOnly()) {
//Request GET NAME AND ADDRESS
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(getMsg);
if (!mEnable) return;
}
mConnection.setGetNameAddressOnly(false);
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback); //注册Adapter状态变更的callback
} catch (RemoteException re) {
Log.e(TAG, "Unable to register BluetoothCallback",re);
}
...
而BluetoothManagerService注册该callback的目的是通知系统所有支持的profiles蓝牙的开启状态,用于更新每个profile和对应profile服务的bind,如通知BluetoothHeadset bind到HeadsetService上,通过binder机制获取HeadsetService的句柄进行相关操作:
BluetoothHeadset.java
final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
if (VDBG) Log.d(TAG,"Unbinding service...");
synchronized (mConnection) {
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG,"",re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG,"Binding service...");
doBind();//绑定到HeadsetService
}
} catch (Exception re) {
Log.e(TAG,"",re);
}
}
}
}
};
那么既然profile要去bind到对应的service上,这些profile对应的Sercice又是什么时候注册的呢?
这个很关键,其实在我们使能蓝牙过程中,AdapaterStateMachine处于OffState状态,处理 msg.what == USER_TURN_ON
case USER_TURN_ON:
if (DBG) Log.d(TAG,"CURRENT_STATE=OFF, MESSAGE = USER_TURN_ON");
notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON);
mPendingCommandState.setTurningOn(true);
transitionTo(mPendingCommandState);
sendMessageDelayed(START_TIMEOUT, START_TIMEOUT_DELAY);
adapterService.processStart();//启动系统支持的所有profiles的services
对应调用AdapterService的接口:
void processStart() {
if (DBG) debugLog("processStart()");
Class[] supportedProfileServices = Config.getSupportedProfiles();
//Initialize data objects
for (int i=0; i < supportedProfileServices.length;i++) {
mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF);
}
mRemoteDevices = new RemoteDevices(mPowerManager, this);
mAdapterProperties.init(mRemoteDevices);
if (DBG) {debugLog("processStart(): Make Bond State Machine");}
mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices);
mJniCallbacks.init(mBondStateMachine,mRemoteDevices);
//FIXME: Set static instance here???
setAdapterService(this);
//Start profile services
if (!mProfilesStarted && supportedProfileServices.length >0) {
//Startup all profile services
setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
}else {
if (DBG) {debugLog("processStart(): Profile Services alreay started");}
mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
}
}
以上就是profiles对应服务的注册。
3)BluetoothManagerService中处理两个callback:一个是来自BluetoothAdapter实例化时注册的回调mManagerCallback并添加到BluetoothManagerService类private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks中,该callback主要用于当BluetoothManagerService成功bind到AdapterService时BluetoothDevice获取AdapterService的句柄(BluetoothDevice获取的过程也是向BluetoothAdapter注册回调的机制);另一个来自于各个profile实现类如BluetoothHeadset注册的callback添加到BluetoothManagerService类private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks中,用户通知每个profile adapter状态的变化如TURNING_ON、TURN_ON、TURNING_OFF、TURN_OFF等;
4)Bluetooth中采用的回调机的地方太多,从Settings中显示部分就多处采用回调来更新UI显示,如BluetoothSettings父类DeviceListPreferenceFragment在onResume()时向LocalBluetoothEventManager中注册callback:
@Override
public void onResume() {
super.onResume();
if (mLocalManager == null) return;
mLocalManager.setForegroundActivity(getActivity());
mLocalManager.getEventManager().registerCallback(this);//注册回调
updateProgressUi(mLocalAdapter.isDiscovering());
}
不仅如此,在JNI和bluedroid的通信中也采用的时回调机制,如com_android_bluetooth_btservice_AdapterService.cpp类在初始化bluedroid时:
static bool initNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));
if (sBluetoothInterface) {
int ret = sBluetoothInterface->init(&sBluetoothCallbacks);//初始化回调接口
if (ret != BT_STATUS_SUCCESS) {
ALOGE("Error while setting the callbacks \n");
sBluetoothInterface = NULL;
return JNI_FALSE;
}
if ( (sBluetoothSocketInterface = (btsock_interface_t *)
sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) {
ALOGE("Error getting socket interface");
}
if ( (sBluetoothMceInterface = (btmce_interface_t *)
sBluetoothInterface->get_profile_interface(BT_PROFILE_MAP_CLIENT_ID)) == NULL) {
ALOGE("Error getting mapclient interface");
} else {
if ( (sBluetoothMceInterface->init(&sBluetoothMceCallbacks)) != BT_STATUS_SUCCESS) {
ALOGE("Failed to initialize Bluetooth MCE");
sBluetoothMceInterface = NULL;
}
}
return JNI_TRUE;
}
return JNI_FALSE;
}
初次看code时可能会感觉很绕,怎么会那么多回调呀?习惯了就好,这貌似时BRCM代码风格。
4.蓝牙关键类管理流程
—— A2dpProfile < ———— > BluetoothA2dp <————> A2dpService <—————> A2dpStateMachine <————>
| (注册Listener监听profile的连接状态) (bind到A2dpService) (采用状态机管理) (jni机制)
com_android_bluetooth_a2dp <————> blueDroid <————> HCI
|...
—— LocalBluetoothProfile <——>|
| (管理所有的profiles) |
| —— HidProfile < ———— > BluetoothHid <————> HidService <—————> com_android_bluetooth_hid <————> blueDroid <————> HCI
| (注册Listener监听profile的连接状态) (bind到HidService) (jni机制)
| —— AdapterStateMachine
LocalBluetoothManager|—— LocalBluetoothApater <——> BluetoothAdapter <————> BluetoothManagerService <————> AdapterService < ————> | 均通过JniCallback回调
(上层本地蓝牙管理类)| (本地Adpater) (调用远端的实现) (开启/关闭) (蓝牙远端服务管理类) (负责开启/关闭及其它profile服务的管理) —— BondStateMachine
|
|
—— BluetoothEventManager <————> CachedBluetoothDeviceManager
(注册广播监听蓝牙状态变更、蓝牙设备状态)
关于 Android 中的 Bluetooth 协议栈的说明:
Android 4.2 版本系统之前,Google 一直使用的是 Linux 官方 Bluetooth 协议栈,即知名老牌开源项目 BlueZ。BlueZ 实际上是由高通公司在2001年5月基于 GPL 协议发布的一个开源项目,该项目仅发布一个月后就被 Linux 之父 Linux Torvalds 纳入了 Linux 内核,并做为 Linux 2.4.6 内核的官方 Bluetooth 协议栈。随着 Android 设备的流行,BlueZ 也得到了极大的完善和扩展。例如 Android 4.1 版本系统中 BlueZ 的版本升级为4.93,它支持 Bluetooth 核心规范 4.0,并实现了绝大部分的 Profile。
BlueZ 现在正处于其巅峰时期,但好景不长。从Android 4.2 即 Jelly Bean 开始,Google 便在 Android 源码中推出了它和博通公司一起开发的 BlueDroid 以替代 BlueZ。虽然因为时间及成熟度的原因,大部分手机厂商在 Android 4.2 中仍继续使用 BlueZ。但据笔者了解,BlueZ 的创始者,高通公司也将在基于其芯片的 Android 参考设计中去除 BlueZ,并仅支持BlueDroid。
BlueZ 的未来如何笔者姑且不论。不过,能让高通改弦易辙,BlueDroid 自有其合理之处。相比 BlueZ,BlueDroid 最值得称道的地方就是其框架结构变得更为简洁和清晰。另外,借助 HAL(Hardware Abstraction Layer,硬件抽象层),BlueDroid 终于不再和 DBUS 有任何瓜葛。下图所示为 Android 4.2 中 BlueDroid 的框架结构图:
由上图可以看出,Android 4.2 中 BlueDroid 框架包括以下几个部分:
1.应用程序通过 android.bluetooth 包下的API来调用系统的 Bluetooth 功能。
2.应用层空间增加了一个名为 Bluetooth 的 App。它作为系统的 Bluetooth 核心进程而存在。其内部将通过 JNI 来调用 Bluetooth HAL 层以完成各种蓝牙请求。
3.Bluetooth HAL 也属于 Android 4.2 新增模块,它由蓝牙核心规范硬件抽象层和蓝牙应用规范硬件抽象层组成。由于 HAL 层的隔离作用,上层代码可轻松移植到不同芯片平台。
4.作为整个蓝牙服务的核心,Bluetooth Stack 模块则由 Bluetooth Application Layer(BTA)和Bluetooth Embedded System(BTE)两大部分组成。BTA 实现了蓝牙设备管理、状态管理及一些应用规范。而 BTE 则通过 HCI 与厂商蓝牙芯片交互以实现了蓝牙协议栈的通用功能和相关协议。另外,BTE 还包括一个统一内核接口(GKI),蓝牙芯片厂商可借助 GKI 快速轻松得移植蓝牙协议栈到其他操作系统或手机平台上。
5.Vendor Extentions(厂商扩展):开发者可以添加自定义扩展以实现厂商特定的模块和组件。
除了 BlueDroid 外,在今年的 Google I/O 大会,谷歌公司还宣布将于与苹果、微软和黑莓等公司共同支持 Bluetooth Smart Ready(BSR,蓝牙智能就绪)和 Bluetooth Smart(BS,蓝牙智能)技术。这项技术使蓝牙设备或应用可以非常容易地连接全球成千上万的蓝牙设备,蓝牙使用者的生活也因此变得更加简单。BSR 和 BS 都是建立在蓝牙核心规范4.0和 GATT 应用规范。即将发布的 Android 4.3(MR2)支持 BSR 技术,使得 BS 的开发者可以轻易地将其设备和应用与 Android BSR 设备进行连接和发布。蓝牙使用者运用 BS 的智能应用配件(如健康监控或医疗设备)收集数据,再传送到支持 BSR 设备(如智能手机或平板)上。
另外,蓝牙 SIG 也正在研发工具 Bluetooth Application Accelerator(蓝牙应用加速器)。据可靠消息,该工具将随 Android 4.3 发布,并将帮助开发者在 Android 4.3 上快速开发蓝牙应用,从而加快相关产品的研发时间。
总结
本文对蓝牙核心规范、蓝牙应用规范以及 Android 4.2 中的蓝牙协议栈 BlueDroid 进行了一些简单介绍。从笔者了解的情况来看,BlueDroid 虽然对 BlueZ 大有取而代之的趋势,但现在它对蓝牙应用规范的支持还不够完善。例如 BlueDroid 仅支持 AVRCP 1.0,而非最新的 AVRCP 1.5。所以,国内某些芯片或手机厂商若能及早完成 BlueZ 相关模块到 BlueDroid 的移植工作,相信能帮助它们在竞争日趋白日化的移动世界中拔得先机。
另外,作为一种成熟、低功耗无线通信技术的先锋,蓝牙未来在可穿戴设备领域中也将扮演越来越重要的作用。那时,蓝牙或许就会真正像“牙齿”一样成为各种设备中不可或缺的一部分了。