转载:http://blog.csdn.net/wenbo13579/article/details/47083923
【Android4.4蓝牙代码分析】- 蓝牙Enable过程
(一)基本说明
本文的代码选用的是Android4.4的kitkat代码。
本文是在Windows环境下通过source insight进行代码阅读,所以大部分目录是以windows的目录结构以’\’区分层级关系。
(二)搭建代码环境
首先介绍下本文source insight所加载的代码路径,bluedroid代码结构可以参考BlueDroid概述。
- package/apps/Bluetooth,这个目录下是Bluetooth的app源码。
- hardware/libhardware/include/hardware,JNI层的一些代码。
- external/Bluetooth/bluedroid,bluedroid协议栈代码。
- frameworks\base\core\java\android\bluetooth,framework层的java代码与aidl文件。
- packages\apps\Settings\src\com\android\settings\bluetooth,Setting App源码中的bluetooth代码
- frameworks\base\services\java\com\android\server,系统核心服务的代码,系统启动后会在这注册蓝牙服务。
(三)蓝牙enable好文分享
有关于Android bluedroid的enable分析已经有很多大牛分析了,现在分享出部分好的博客,本文很多东西都是参考他们的文章。
- Android BlueDroid(三):BlueDroid蓝牙开启过程enable,该文给出了总体的流程图,在总体结构上对蓝牙enable过程可以有个清晰的认识。
- Android 4.2 Bluetooth 分析总结(二) 蓝牙enable 的整个过程,该文给出了log,并且按照代码运行流程一个个函数的进行分析,本文很多内容都参考至该文。
- android bluetooth 移植相关注意事项,该文将了下蓝牙移植的相关知识,在进行代码阅读之前看看该文,能够从一个总体层次上对bluedroid代码进行分析。
- android – 蓝牙 bluetooth (二) 打开蓝牙,该文是也很不错,作者最开始就是看的该博客。
(四)代码分析
在Android系统启动过程中,其会首先加载SystemServer.java,System Server是Android系统的核心,他在Dalvik虚拟机启动后立即开始初始化和运行。其它的系统服务在System Server进程的环境中运行。在Android系统开机过程中,蓝牙服务也会在这里注册,并运行,关于SystemServer.java详见(Android的System Server),这样蓝牙服务进程就作为一个线程运行在SystemServer进程中。最后一个else分支是我们所关心的,通过ServiceManager.addService方法向ServiceManager进程中注册了蓝牙服务,后面要使用时只需要通过getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE)
方法即可(BluetoothAdapter类在frameworks\base\core\java\android\bluetooth目录下,BLUETOOTH_MANAGER_SERVICE值为“bluetooth_manager”)。
代码位置:frameworks\base\services\java\com\android\server\SystemServer.java
- 1
- 2
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);
}
我们先看一下BluetoothManagerService类的构造函数,代码比较多,我们主要看两个地方,loadStoredNameAndAddress()
是读取蓝牙打开默认名称的地方,isBluetoothPersistedStateOn()
是用来判断蓝牙是否已打开的,如果已打开,需要执行开启蓝牙的动作,前几行注册的广播其中就有这个作用。
代码位置:frameworks\base\services\java\com\android\server\BluetoothManagerService.java
- 1
- 2
BluetoothManagerService(Context context) {
…一些变量声明初始化…
IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
registerForAirplaneMode(filter);
mContext.registerReceiver(mReceiver, filter);
loadStoredNameAndAddress();
if (isBluetoothPersistedStateOn()) {
mEnableExternal = true;
}
}
上面就完成了蓝牙的系统服务注册工作,如果没有设置蓝牙打开,系统也不会打开蓝牙,后面如果需要用到蓝牙服务只需通过systemServer的getServer方法即可。
现在回到用户真正能接触到的界面开关部分,蓝牙界面开关就是Setting界面中的蓝牙开关,其实际就是调用BluetoothEnabler.java这个类了,BluetoothEnabler类是实现
CompoundButton.OnCheckedChangeListener
按键监听器,看到其onCheckedChanged方法,当按键按下时会跳入该方法,在该方法中首先判断是否开启了飞行模式,如果没则调用mLocalAdapter(LocalBluetoothAdapter)的setBluetoothEnabled()
方法,执行具体的开关动作。
代码位置:packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothEnabler.java
- 1
- 2
public final class BluetoothEnabler implements CompoundButton.OnCheckedChangeListener {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Show toast message if Bluetooth is not allowed in airplane mode
if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off
buttonView.setChecked(false);
}
if (mLocalAdapter != null) {
mLocalAdapter.setBluetoothEnabled(isChecked);
}
mSwitch.setEnabled(false);
}
}
在LocalBluetoothAdapter类的setBluetoothEnabled方法中,根据是否打开再调用mAdapter(BluetoothAdapter)的enable或disable方法。并更新蓝牙状态机。
代码位置:packages\apps\Settings\src\com\android\settings\bluetooth\LocalBluetoothAdapter.java
- 1
- 2
public void setBluetoothEnabled(boolean enabled) {
boolean success = enabled
? mAdapter.enable()
: mAdapter.disable();
if (success) {
setBluetoothStateInt(enabled
? BluetoothAdapter.STATE_TURNING_ON
: BluetoothAdapter.STATE_TURNING_OFF);
} else {
if (Utils.V) {
Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
"success for enabled: " + enabled);
}
syncBluetoothState();
}
}
请注意:这时候代码已经跳转到了framework层了。
在BluetoothAdapter类中可以看到一个单例模式的应用,主要提供给其它程序调用蓝牙的一些方法用的,外部程序想调用蓝牙的方法就要先用这个拿到BluetoothAdapter对象,代码也简单看下吧,里面是典型的binder应用。就是前面在SystemServer中注册的蓝牙服务。
代码位置:frameworks\base\core\java\android\bluetooth\BluetoothAdapter.java
- 1
- 2
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
sAdapter = new BluetoothAdapter(managerService);
} else {
Log.e(TAG, "Bluetooth binder is null");
}
}
return sAdapter;
}
此时我们更关心mAdapter.enable()
的后续操作,外部其它应用到getDefaultAdapter()也是调用enable(),注意,到了BluetoothAdapter我们已经在framework层了,顺着BluetoothAdapter.java的enable()调用,其先判断蓝牙是否已经打开,如果没打开则调用mManagerService(IBluetoothManager)的enable方法。
代码位置:frameworks\base\core\java\android\bluetooth\BluetoothAdapter.java
- 1
- 2
public boolean enable() {
if (isEnabled() == true){
if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
return true;
}
try {
return mManagerService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
IBluetoothManager类是Android进程间通信的接口,在其中定义了一堆的接口,一般这种远程服务对应的类名就是 BluetoothManagerService 类,主要用于调用在SystemServer中注册的蓝牙服务。在BluetoothAdapter类的构造函数中,将mManagerService绑定到了ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE)
的蓝牙服务中。我们直接进入BluetoothManagerService类的enable()方法。
代码位置:frameworks\base\core\java\android\bluetooth\BluetoothAdapter.java
- 1
- 2
interface IBluetoothManager {
IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
void unregisterAdapter(in IBluetoothManagerCallback callback);
void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
boolean isEnabled();
boolean enable();
boolean enableNoAutoConnect();
boolean disable(boolean persist);
IBluetoothGatt getBluetoothGatt();
String getAddress();
String getName();
}
在BluetoothManagerService类的enable()方法中,第一个if看到log那就知道如果enable正常就不会走,第二个if是打印调试信息,在后面的synchronized函数体中,实际有用的是sendEnableMsg(false)
方法,跳到sendEnableMsg中。
代码位置:frameworks\base\services\java\com\android\server\BluetoothManagerService.java
- 1
- 2
public boolean enable() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
Log.w(TAG,"enable(): not allowed for non-active and non system user");
return false;
}
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
if (DBG) {
Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
" mBinding = " + mBinding);
}
synchronized(mReceiver) {
mQuietEnableExternal = false;
mEnableExternal = true;
// waive WRITE_SECURE_SETTINGS permission check
long callingIdentity = Binder.clearCallingIdentity();
persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
Binder.restoreCallingIdentity(callingIdentity);
sendEnableMsg(false);
}
return true;
}
可以看到在sendEnableMsg中向系统发送了一条MESSAGE_ENABLE
消息,再跳转到mHandler(BluetoothHandler)类的handleMessage方法,可以看到在handleMessage
中有对MESSAGE_ENABLE
消息的处理函数,实际的话就是调用了BluetoothManagerService类的handleEnable方法。
代码位置:frameworks\base\services\java\com\android\server\BluetoothManagerService.java
- 1
- 2
private class BluetoothHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
if (DBG) Log.d (TAG, "Message: " + msg.what);
switch (msg.what) {
case MESSAGE_ENABLE:
if (DBG) {
Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
handleEnable(msg.arg1 == 1);
break;
}
}
}
}
handleEnable方法比较长,看到注释说明//Enable bluetooth,我们直接看这部分代码,实际执行的是mBluetooth.enable()
,又是一个接口IBluetooth。
代码位置:frameworks\base\services\java\com\android\server\BluetoothManagerService.java
- 1
- 2
private void handleEnable(boolean quietMode) {
mQuietEnable = quietMode;
synchronized(mConnection) {
if ((mBluetooth == null) && (!mBinding)) {
//Start bind timeout and bind
Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
mConnection.setGetNameAddressOnly(false);
Intent i = new Intent(IBluetooth.class.getName());
if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
} else {
mBinding = true;
}
} else if (mBluetooth != null) {
if (mConnection.isGetNameAddressOnly()) {
// if GetNameAddressOnly is set, we can clear this flag,
// so the service won't be unbind
// after name and address are saved
mConnection.setGetNameAddressOnly(false);
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
} catch (RemoteException re) {
Log.e(TAG, "Unable to register BluetoothCallback",re);
}
//Inform BluetoothAdapter instances that service is up
sendBluetoothServiceUpCallback();
}
//Enable bluetooth
try {
if (!mQuietEnable) {
if(!mBluetooth.enable()) {
Log.e(TAG,"IBluetooth.enable() returned false");
}
}
else {
if(!mBluetooth.enableNoAutoConnect()) {
Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
}
}
} catch (RemoteException e) {
Log.e(TAG,"Unable to call enable()",e);
}
}
}
}
mBluetooth(IBluetooth)这个接口到底是对应哪个远程服务呢?在同一个目录下搜索,先搜索mBluetooth在哪里赋值了,搜索完BluetoothManagerService.java只在handleMessage
中找到了mBluetooth = IBluetooth.Stub.asInterface(service)
,而IBinder service = (IBinder) msg.obj
。也就是远程服务是发送“MESSAGE_BLUETOOTH_SERVICE_CONNECTED”消息对象。继续在BluetoothManagerService类中搜索是谁发送这条消息。
代码位置:frameworks\base\services\java\com\android\server\BluetoothManagerService.java
- 1
- 2
private class BluetoothHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
if (DBG) Log.d (TAG, "Message: " + msg.what);
switch (msg.what) {
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{
if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
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);
...
break;
}
}
}
}
在BluetoothManagerService.java中发现在onServiceConnected方法中构建了该消息,并将调用该方法的service赋值给msg.obj
,到底谁调用了这个函数呢,尝试搜索了下“onServiceConnected”并没有得到想要的结果,再回到onServiceConnected方法中,可以看到有个log,"BluetoothServiceConnection: " + className.getClassName()
,就是说将BluetoothServiceConnection连接到一个服务上,在看到下面的if判断,最有可能的是连接到了AdapterService
服务中。在Android 4.2 Bluetooth 分析总结(二) 蓝牙enable 的整个过程中作者从实际打印的log中也指出了在这一步系统会跳转到AdapterService。
D/BluetoothManagerService( 1646): BluetoothServiceConnection: connected to AdapterService
代码位置:frameworks\base\services\java\com\android\server\BluetoothManagerService.java
- 1
- 2
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
// TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
// } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
Log.e(TAG, "Unknown service connected: " + className.getClassName());
return;
}
msg.obj = service;
mHandler.sendMessage(msg);
}
这时代码从framework层跳到了APP层,符合了android代码架构图中的定义。
我们看到AdapterService的enable方法,可以发现在AdapterService类中有三个enable函数,从framework层到这到底调用了哪个enable函数呢,根据代码注释和实际情况,应该是调用了在AdapterServiceBinder
类中的enable方法,在该方法中调用了service.enable()
,而service是通过getService()
方法获取的,看到该方法,实际是返回了mService(AdapterService)
,也就是调用了boolean enable()
方法,最终调用了public synchronized boolean enable(boolean quietMode)
方法。在这个方法中主要是构建了一个AdapterState.USER_TURN_ON消息,并发送给状态机mAdapterStateMachine
去处理。
代码位置:packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterService.java
- 1
- 2
public class AdapterService extends Service {
...
private static class AdapterServiceBinder extends IBluetooth.Stub {
private AdapterService mService;
public AdapterServiceBinder(AdapterService svc) {
mService = svc;
}
...
public boolean enable() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!Utils.checkCaller())) {
Log.w(TAG,"enable(): not allowed for non-active user and non system user");
return false;
}
AdapterService service = getService();
if (service == null) return false;
return service.enable();
}
...
public AdapterService getService() {
if (mService != null && mService.isAvailable()) {
return mService;
}
return null;
}
}
...
//----API Methods--------
...
boolean enable() {
return enable (false);
}
...
public synchronized boolean enable(boolean quietMode) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
if (DBG)debugLog("Enable called with quiet mode status = " + mQuietmode);
mQuietmode = quietMode;
Message m =
mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
mAdapterStateMachine.sendMessage(m);
return true;
}
}
这里用到了状态机的概念,在网上查了下有关Android蓝牙状态机的资料,没有找到合适的,大多是Android4.2之前的状态机分析,通过查看源码,在AdapterState状态机的注释中可以发现如下说明,说明该状态机有三个状态,分别是OnState、OffState以及PendingCommandState,再根据注释,在初始状态下,蓝牙应该处于OffState,中间态是PendingCommandState,正在打开是OnState。具体没有深入去分析代码,可能有错误,暂时按照这个流程继续进行蓝牙enable分析。
代码位置:packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterState.java
- 1
- 2
/**
* This state machine handles Bluetooth Adapter State.
* States:
* {@link OnState} : Bluetooth is on at this state
* {@link OffState}: Bluetooth is off at this state. This is the initial
* state.
* {@link PendingCommandState} : An enable / disable operation is pending.
* TODO(BT): Add per process on state.
*/
我们重点看状态机的消息处理部分,由于这时候进行的是蓝牙开启操作,状态机处于OffState状态下,在OffState的processMessage
中找到对USER_TURN_ON
的处理函数,前面的几个是进行状态机的状态更新,最后调用了adapterService.processStart()
,我们跳进去看。
代码位置:packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterState.java
- 1
- 2
final class AdapterState extends StateMachine {
...
private class OffState extends State {
...
@Override
public boolean processMessage(Message msg) {
AdapterService adapterService = mAdapterService;
if (adapterService == null) {
Log.e(TAG,"receive message at OffState after cleanup:" +
msg.what);
return false;
}
switch(msg.what) {
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();
break;
...
}
return true;
}
}
...
}
又回到了AdapterService,通过看给出的log提示以及函数名称,大概是进行了所有profile的状态机状态开启设置,在最后一个else中的log中也是显示processStart(): Profile Services alreay started
,最后又调用状态机执行AdapterState.STARTED
消息,执行mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED))
。
代码位置:packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterService.java
- 1
- 2
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(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));
}
}
再次回到AdapterState类,由于这时候状态机处于pending状态下,所以在PendingCommandState
中对该消息进行处理,实际是调用了adapterService.enableNative()
方法,也就是终于通过JNI开始向下层调用底层操作方法进行蓝牙Enable操作。
代码位置:packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterState.java
- 1
- 2
final class AdapterState extends StateMachine {
...
private class PendingCommandState extends State {
private boolean mIsTurningOn;
private boolean mIsTurningOff;
...
@Override
public boolean processMessage(Message msg) {
...
switch(msg.what) {
case STARTED:
if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = STARTED, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff);
//Remove start timeout
removeMessages(START_TIMEOUT);
//Enable
boolean ret = adapterService.enableNative();
if (!ret) {
Log.e(TAG, "Error while turning Bluetooth On");
notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);
transitionTo(mOffState);
} else {
sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);
}
break;
...
}
return true;
}
}
...
}
这里已经通过JNI从APP framework层进入了bluedroid协议栈了。
根据Android JNI层的命名规则,找到了com_android_bluetooth_btservice_AdapterService.cpp
,看到其中的enableNative()
方法。实际是调用了sBluetoothInterface(bt_interface_t)
的enable方法。sBluetoothInterface这个又是一个接口,在网上看别人写的博客说不能跳转,但是我这边可以直接跳转到bt_interface_t
的定义,如果不能跳转依然可以到这个文章中看如何跳转Android 4.2 Bluetooth 分析总结(二) 蓝牙enable 的整个过程。
代码位置:packages\apps\Bluetooth\jni\com_android_bluetooth_btservice_AdapterService.cpp
- 1
- 2
static jboolean enableNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;
int ret = sBluetoothInterface->enable();
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
可以看出,在这个结构体中包含了大量的接口,有bluetooth.h自然有bluetooth.c文件,我们跳转到bluetooth.c中看下接口的具体实现。
代码位置:hardware\libhardware\include\hardware\bluetooth.h
- 1
- 2
/** Represents the standard Bluetooth DM interface. */
typedef struct {
/** set to sizeof(bt_interface_t) */
size_t size;
/**
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
*/
int (*init)(bt_callbacks_t* callbacks );
/** Enable Bluetooth. */
int (*enable)(void);
/** Disable Bluetooth. */
int (*disable)(void);
...
} bt_interface_t;
终于开始了最喜欢的c代码了,c代码看起来就轻松多了。
在这里可以看到bluetooth.c实例化了一个bt_interface_t
对象,bluetoothInterface。跳转到enable函数中,在打印了一个log信息后,先会对接口进行检查,如果接口ready就调用btif_enable_bluetooth()
方法。
代码位置:external\bluetooth\bluedroid\btif\src\bluetooth.c
- 1
- 2
static int enable( void )
{
ALOGI("enable");
/* sanity check */
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;
return btif_enable_bluetooth();
}
...
static const bt_interface_t bluetoothInterface = {
sizeof(bluetoothInterface),
init,
enable,
disable,
cleanup,
get_adapter_properties,
get_adapter_property,
set_adapter_property,
get_remote_device_properties,
get_remote_device_property,
set_remote_device_property,
get_remote_service_record,
get_remote_services,
start_discovery,
cancel_discovery,
create_bond,
remove_bond,
cancel_bond,
pin_reply,
ssp_reply,
get_profile_interface,
dut_mode_configure,
dut_mode_send,
#if BLE_INCLUDED == TRUE
le_test_mode,
#else
NULL,
#endif
config_hci_snoop_log
};
到了这一步基本上已经完成了上层的一堆蓝牙Enable代码分析,后面的都是bluedroid的代码了,具体到蓝牙的实际开关又涉及到各个厂商Vendor的设计。下面简要写一些后续的蓝牙Enable过程。
一下就跳转到了btif_core.c中了,前面是一堆的判断以及状态机的设置,我们直接看到后面,又调用了bte_main_enable()
,跳进去继续看。
代码位置:external\bluetooth\bluedroid\btif\src\btif_core.c
- 1
- 2
bt_status_t btif_enable_bluetooth(void)
{
BTIF_TRACE_DEBUG0("BTIF ENABLE BLUETOOTH");
if (btif_core_state != BTIF_CORE_STATE_DISABLED)
{
ALOGD("not disabled\n");
return BT_STATUS_DONE;
}
btif_core_state = BTIF_CORE_STATE_ENABLING;
/* Create the GKI tasks and run them */
bte_main_enable();
return BT_STATUS_SUCCESS;
}
认真看下这个函数,首先初始化了BTE的控制块,是什么呢,大概看了下,主要是一些参数设置。主要看到bte_hci_enable()
,这个函数比较长,首先启动了一个preload定时器,主要用于重新打开蓝牙的操作,以防蓝牙长时间没有打开,先不管,继续往下看,bt_hc_if(bt_hc_interface_t)
是什么东西呢,我们跳进去看看,bte_hci_enable()
的分析后面继续开展,先看看bt_hc_if(bt_hc_interface_t)
是什么东西,后面很多地方都有调用。
代码位置:external\bluetooth\bluedroid\main\bte_main.c
- 1
- 2
void bte_main_enable()
{
APPL_TRACE_DEBUG1("%s", __FUNCTION__);
/* Initialize BTE control block */
BTE_Init();
lpm_enabled = FALSE;
bte_hci_enable();
GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
(UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
sizeof(bte_btu_stack));
GKI_run(0);
}
...
static void bte_hci_enable(void)
{
APPL_TRACE_DEBUG1("%s", __FUNCTION__);
preload_start_wait_timer();
if (bt_hc_if)
{
int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
APPL_TRACE_EVENT1("libbt-hci init returns %d", result);
assert(result == BT_HC_STATUS_SUCCESS);
if (hci_logging_enabled == TRUE || hci_logging_config == TRUE)
bt_hc_if->logging(BT_HC_LOGGING_ON, hci_logfile);
#if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE)
APPL_TRACE_DEBUG1("%s Not Turninig Off the BT before Turninig ON", __FUNCTION__);
/* Do not power off the chip before powering on if BT_CLEAN_TURN_ON_DISABLED flag
is defined and set to TRUE to avoid below mentioned issue.
Wingray kernel driver maintains a combined counter to keep track of
BT-Wifi state. Invoking set_power(BT_HC_CHIP_PWR_OFF) when the BT is already
in OFF state causes this counter to be incorrectly decremented and results in undesired
behavior of the chip.
This is only a workaround and when the issue is fixed in the kernel this work around
should be removed. */
#else
/* toggle chip power to ensure we will reset chip in case
a previous stack shutdown wasn't completed gracefully */
bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF);
#endif
bt_hc_if->set_power(BT_HC_CHIP_PWR_ON);
bt_hc_if->preload(NULL);
}
}
bt_hc_interface_t
和前面的bt_interface_t
接口一样,根据其说明文件,其是Bluetooth Host/Controller Interface。这个接口的实现在哪呢,看到目录,我们在src目录找找,也可以对整个project进行检索,很快我们发现了对该接口的实现。
代码位置:external\bluetooth\bluedroid\hci\include\bt_hci_lib.h
- 1
- 2
/*
* Bluetooth Host/Controller Interface
*/
typedef struct {
/** Set to sizeof(bt_hc_interface_t) */
size_t size;
/**
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
*/
int (*init)(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr);
/** Chip power control */
void (*set_power)(bt_hc_chip_power_state_t state);
/** Set low power mode wake */
int (*lpm)(bt_hc_low_power_event_t event);
/** Called prior to stack initialization */
void (*preload)(TRANSAC transac);
/** Called post stack initialization */
void (*postload)(TRANSAC transac);
/** Transmit buffer */
int (*transmit_buf)(TRANSAC transac, char *p_buf, int len);
/** Controls receive flow */
int (*set_rxflow)(bt_rx_flow_state_t state);
/** Controls HCI logging on/off */
int (*logging)(bt_hc_logging_state_t state, char *p_path);
/** Closes the interface */
void (*cleanup)( void );
} bt_hc_interface_t;
bt_hc_interface_t
接口在bt_hci_bdroid.c
中有具体实现,现在再次回到bte_hci_enable()
。
代码位置:external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
- 1
- 2
static const bt_hc_interface_t bluetoothHCLibInterface = {
sizeof(bt_hc_interface_t),
init,
set_power,
lpm,
preload,
postload,
transmit_buf,
set_rxflow,
logging,
cleanup
};
首先调用了bt_hc_if
的init函数,根据注释,init函数主要用来打开interface并且提供回调机制,我们跳进去看下。
代码位置:external\bluetooth\bluedroid\main\bte_main.c
- 1
- 2
static void bte_hci_enable(void)
{
APPL_TRACE_DEBUG1("%s", __FUNCTION__);
preload_start_wait_timer();
if (bt_hc_if)
{
int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
APPL_TRACE_EVENT1("libbt-hci init returns %d", result);
assert(result == BT_HC_STATUS_SUCCESS);
if (hci_logging_enabled == TRUE || hci_logging_config == TRUE)
bt_hc_if->logging(BT_HC_LOGGING_ON, hci_logfile);
#if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE)
APPL_TRACE_DEBUG1("%s Not Turninig Off the BT before Turninig ON", __FUNCTION__);
/* Do not power off the chip before powering on if BT_CLEAN_TURN_ON_DISABLED flag
is defined and set to TRUE to avoid below mentioned issue.
Wingray kernel driver maintains a combined counter to keep track of
BT-Wifi state. Invoking set_power(BT_HC_CHIP_PWR_OFF) when the BT is already
in OFF state causes this counter to be incorrectly decremented and results in undesired
behavior of the chip.
This is only a workaround and when the issue is fixed in the kernel this work around
should be removed. */
#else
/* toggle chip power to ensure we will reset chip in case
a previous stack shutdown wasn't completed gracefully */
bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF);
#endif
bt_hc_if->set_power(BT_HC_CHIP_PWR_ON);
bt_hc_if->preload(NULL);
}
}
我们都知道,蓝牙的话分为Host和Controller,两者通过HCI层进行数据交互。Host的话是Android操作系统,这部分是通用的,由google公司提供;Controller的话是一个个芯片厂商提供的,这部分各个厂商都有其独立设计。在Android4.2后的bluedroid中将所有厂商的设计文件放在vendor目录中,而为了实现上层对芯片的操作,bluedroid提供了专门的接口,下面我们通过代码分析来了解bluedroid是怎么完成这些操作的。
这个init函数非常的长,首先看到第一个重要跳转就是init_vnd_if(local_bdaddr)
,从函数的字面理解就是调用厂商vender的init函数,在函数的注释中了解到这个函数主要完成vendor lib interface的初始化操作。
代码位置:external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
- 1
- 2
static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
{
...
/* store reference to user callbacks */
bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb;
init_vnd_if(local_bdaddr);
...
}
在这里完成了厂商定制功能与Android系统的绑定,系统后面都可以通过
bt_vnd_if
调用厂商的定制功能。在这里我们不深入分析厂商具体做了什么。
首先利用dlopen方法打开了libbt-vendor.so厂商的配置文件,并将动态库的句柄赋给dlhandle,再通过dlsym方法将"BLUETOOTH_VENDOR_LIB_INTERFACE"
句柄返回给bt_vnd_if
,关于libbt-vendor.so的介绍说明可以看android bluetooth 移植相关注意事项。在这里主要就是要厂商实现bt_vendor_interface_t
这一通用接口,并且将接口赋值给bt_vnd_if
,后面就可以通过bt_vnd_if
实现对厂商定制功能的调用。最后再利用厂商实现的init方法实现蓝牙芯片的init操作(厂商具体决定init过程的具体操作)。
代码位置:external\bluetooth\bluedroid\hci\src\bt_hw.c
- 1
- 2
void init_vnd_if(unsigned char *local_bdaddr)
{
void *dlhandle;
dlhandle = dlopen("libbt-vendor.so", RTLD_NOW);
if (!dlhandle)
{
ALOGE("!!! Failed to load libbt-vendor.so !!!");
return;
}
bt_vnd_if = (bt_vendor_interface_t *) dlsym(dlhandle, "BLUETOOTH_VENDOR_LIB_INTERFACE");
if (!bt_vnd_if)
{
ALOGE("!!! Failed to get bt vendor interface !!!");
return;
}
bt_vnd_if->init(&vnd_callbacks, local_bdaddr);
}
bt_vendor_lib.h
的定义如下,可以看到dlsym
方法返回的bt_vnd_if
就是指向了bt_vendor_interface_t
结构体。
代码位置:external\bluetooth\bluedroid\hci\include\bt_vendor_lib.h
- 1
- 2
/*
* Bluetooth Host/Controller VENDOR Interface
*/
typedef struct {
/** Set to sizeof(bt_vndor_interface_t) */
size_t size;
/*
* Functions need to be implemented in Vendor libray (libbt-vendor.so).
*/
/**
* Caller will open the interface and pass in the callback routines
* to the implemenation of this interface.
*/
int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr);
/** Vendor specific operations */
int (*op)(bt_vendor_opcode_t opcode, void *param);
/** Closes the interface */
void (*cleanup)(void);
} bt_vendor_interface_t;
/*
* External shared lib functions/data
*/
/* Entry point of DLib --
* Vendor library needs to implement the body of bt_vendor_interface_t
* structure and uses the below name as the variable name. HCI library
* will use this symbol name to get address of the object through the
* dlsym call.
*/
extern const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE;
回到bt_hci_bdroid.c
函数,在init_vnd_if
方法中注册了厂商的hci接口,utils_init()
初始化了一个互斥锁,暂不去管他,后面用到了#ifdef…#else…#endif的宏if语句,默认情况下,Android bluedroid是采用h4也就是uart传输方式,也就是其声明了一个hci_h4_func_table
函数体,并将p_hci_if
指向了该函数体,随后调用了hci_h4_func_table
中的init函数。
代码位置:external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
{
...
init_vnd_if(local_bdaddr);
utils_init();
#ifdef HCI_USE_MCT
extern tHCI_IF hci_mct_func_table;
p_hci_if = &hci_mct_func_table;
#else
extern tHCI_IF hci_h4_func_table;
p_hci_if = &hci_h4_func_table;
#endif
p_hci_if->init();
...
}
我们跳到hci_h4_func_table
函数体重看看其具体干了什么,可以看到其定义了一个h4的服务接口,在hci_h4_init
函数中奇首先初始化了一个队列h4_cb.acl_rx_q
用于接收acl数据。然后设置了一些参数,最后init了btsnoop,也就是初始化了抓取蓝牙hci log的btsnoop,实际就是初始化了一个thread,具体就不跳进去了,代码在external\bluetooth\bluedroid\hci\src\btsnoop.c
。
代码位置:external\bluetooth\bluedroid\hci\src\hci_h4.c
void hci_h4_init(void)
{
HCIDBG("hci_h4_init");
memset(&h4_cb, 0, sizeof(tHCI_H4_CB));
utils_queue_init(&(h4_cb.acl_rx_q));
/* Per HCI spec., always starts with 1 */
num_hci_cmd_pkts = 1;
/* Give an initial values of Host Controller's ACL data packet length
* Will update with an internal HCI(_LE)_Read_Buffer_Size request
*/
h4_cb.hc_acl_data_size = 1021;
h4_cb.hc_ble_acl_data_size = 27;
btsnoop_init();
}
/******************************************************************************
** HCI H4 Services interface table
******************************************************************************/
const tHCI_IF hci_h4_func_table =
{
hci_h4_init,
hci_h4_cleanup,
hci_h4_send_msg,
hci_h4_send_int_cmd,
hci_h4_get_acl_data_length,
hci_h4_receive_msg
};
bt_hc_worker_thread线程里面有很多重要的事件处理,可以具体看看。
再次回到bt_hci_bdroid.c
函数,在初始化hci后,其继续初始化了userial,也就是初始化了串口,这里需要根据前面的#ifdef来决定跳转到那个userial.c文件,文件位置在external\bluetooth\bluedroid\hci\src\userial.c
。随后对lpm进行了初始化,在lpm_init
函数中调用了芯片厂商中BT_VND_OP_GET_LPM_IDLE_TIMEOUT
所对应的函数,然后赋值给bt_lpm_cb.timeout_ms
,文件位置在external\bluetooth\bluedroid\hci\src\lmp.c
。在utils_queue_init
初始化了一个发送队列。在init函数最后创建了一个bt_hc_worker_thread
蓝牙工作主线程,用于发送和接收命令。
代码位置:external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
- 1
- 2
static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
{
...
p_hci_if->init();
userial_init();
lpm_init();
utils_queue_init(&tx_q);
...
pthread_mutex_init(&hc_cb.mutex, NULL);
pthread_cond_init(&hc_cb.cond, NULL);
pthread_attr_init(&thread_attr);
if (pthread_create(&hc_cb.worker_thread, &thread_attr, \
bt_hc_worker_thread, NULL) != 0)
{
...
}
...
return BT_HC_STATUS_SUCCESS;
}
回到最初的bte_hci_enable()
函数,上面就完成了bt_hc_if->init
函数,然后根据是否需要打开hci log来打开hci log,后面的宏if语句用于判断是否已经打开蓝牙,如果没有则先关闭chip power bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF)
然后再打开chip power bt_hc_if->set_power(BT_HC_CHIP_PWR_ON)
。最后调用了bt_hc_if->preload(NULL)
函数,主要进行一些芯片的预操作,具体分析见后文。
代码位置:external\bluetooth\bluedroid\main\bte_main.c
- 1
- 2
static void bte_hci_enable(void)
{
APPL_TRACE_DEBUG1("%s", __FUNCTION__);
preload_start_wait_timer();
if (bt_hc_if)
{
int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
...
if (hci_logging_enabled == TRUE || hci_logging_config == TRUE)
bt_hc_if->logging(BT_HC_LOGGING_ON, hci_logfile);
#if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE)
APPL_TRACE_DEBUG1("%s Not Turninig Off the BT before Turninig ON", __FUNCTION__);
/* Do not power off the chip before powering on if BT_CLEAN_TURN_ON_DISABLED flag
is defined and set to TRUE to avoid below mentioned issue.
Wingray kernel driver maintains a combined counter to keep track of
BT-Wifi state. Invoking set_power(BT_HC_CHIP_PWR_OFF) when the BT is already
in OFF state causes this counter to be incorrectly decremented and results in undesired
behavior of the chip.
This is only a workaround and when the issue is fixed in the kernel this work around
should be removed. */
#else
/* toggle chip power to ensure we will reset chip in case
a previous stack shutdown wasn't completed gracefully */
bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF);
#endif
bt_hc_if->set_power(BT_HC_CHIP_PWR_ON);
bt_hc_if->preload(NULL);
}
}
找到bt_hc_interface_t
接口在bt_hci_bdroid.c
中set_power()
的具体实现,首先设置了power的状态,然后调用厂商接口bt_vnd_if
中的BT_VND_OP_POWER_CTRL
所对应的函数,执行芯片的上电操作。
代码位置:external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
- 1
- 2
/** Chip power control */
static void set_power(bt_hc_chip_power_state_t state)
{
int pwr_state;
BTHCDBG("set_power %d", state);
/* Calling vendor-specific part */
pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF;
if (bt_vnd_if)
bt_vnd_if->op(BT_VND_OP_POWER_CTRL, &pwr_state);
else
ALOGE("vendor lib is missing!");
}
找到bt_hc_interface_t
接口在bt_hci_bdroid.c
中preload()
的具体实现,其就是发送了一个事件,也就是向我们前面在bt_hci_bdroid.c
创建的线程bt_hc_worker_thread
发送了HC_EVENT_PRELOAD
消息,我们跳到线程里对该消息的处理函数中,可以看到,其首先打开了串口userial_open(USERIAL_PORT_1)
,然后调用了vendor定义的BT_VND_OP_FW_CFG
所对应的函数进行芯片framework的config操作。
代码位置:external\bluetooth\bluedroid\hci\src\bt_hci_bdroid.c
- 1
- 2
/** Called prio to stack initialization */
static void preload(TRANSAC transac)
{
BTHCDBG("preload");
bthc_signal_event(HC_EVENT_PRELOAD);
}
...
static void *bt_hc_worker_thread(void *arg)
{
...
while (lib_running)
{
pthread_mutex_lock(&hc_cb.mutex);
while (ready_events == 0)
{
pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex);
}
events = ready_events;
ready_events = 0;
pthread_mutex_unlock(&hc_cb.mutex);
...
if (events & HC_EVENT_PRELOAD)
{
userial_open(USERIAL_PORT_1);
/* Calling vendor-specific part */
if (bt_vnd_if)
{
bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL);
}
else
{
if (bt_hc_cbacks)
bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL);
}
}
...
}
ALOGI("bt_hc_worker_thread exiting");
lib_running = 0;
pthread_exit(NULL);
return NULL; // compiler friendly
}
在userial_open
中主要调用vendor定义的BT_VND_OP_USERIAL_OPEN
所对应的函数进行userial的打开操作,然后再创建了一个串口读取线程userial_read_thread
。
代码位置:external\bluetooth\bluedroid\hci\src\userial.c
- 1
- 2
uint8_t userial_open(uint8_t port)
{
...
if (userial_running)
{
/* Userial is open; close it first */
userial_close();
utils_delay(50);
}
...
/* Calling vendor-specific part */
if (bt_vnd_if)
{
result = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &fd_array);
...
}
else
{
ALOGE("userial_open: missing vendor lib interface !!!");
ALOGE("userial_open: unable to open UART port");
return FALSE;
}
...
if (pthread_create(&(userial_cb.read_thread), &thread_attr, \
userial_read_thread, NULL) != 0 )
{
ALOGE("pthread_create failed!");
return FALSE;
}
...
return TRUE;
}
到现在已经完成了
bte_hci_enable
的全部操作,回忆下,其首先绑定了蓝牙芯片厂商定制功能函数,首先调用了vendor芯片的init函数;然后根据实际需要,通过宏if语句绑定了hci函数体hci_h4_func_table
,并调用其init函数进行hci的初始化;然后调用了userial和lpm的初始化,并创建了了用于蓝牙hc工作的主线程;接着进行了蓝牙的上电操作;最后进行了蓝牙的preload操作,包括打开userial,创建userial read线程,并执行蓝牙芯片的framework config操作。
再次回到bte_main.c
中的bte_main_enable()
函数,其最后create了一个GKI任务,并启动了该任务。
代码位置:external\bluetooth\bluedroid\main\bte_main.c
- 1
- 2
void bte_main_enable()
{
APPL_TRACE_DEBUG1("%s", __FUNCTION__);
/* Initialize BTE control block */
BTE_Init();
lpm_enabled = FALSE;
bte_hci_enable();
GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
(UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
sizeof(bte_btu_stack));
GKI_run(0);
}
至此,蓝牙的enable操作的就全部结束了,文章中存在很多问题,欢迎大家的指正。