您的位置:首页 > 产品设计 > UI/UE

Android 4.4 Bluetooth学习之一

2014-01-10 16:29 148 查看
一、写在前面的话
近来由于项目需求需要搞蓝牙这一块,之前在上家公司带LC(本地连接)组时也做过一点蓝牙,在Android系统中也解过一些bug,但是不够系统,现在正好比较系统的学习蓝牙。

二、蓝牙的协议框架
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
(注册广播监听蓝牙状态变更、蓝牙设备状态)

四、小结
本来想采用UML画出流程图以备后查,无奈时间紧张、手头没有环境,唉做项目的人真心悲催啊!待续...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: