1、寫在前面的話
近來因爲項目需求須要搞藍牙這一塊,以前在上家公司帶LC(本地鏈接)組時也作過一點藍牙,在Android系統中也解過一些bug,可是不夠系統,如今正比如較系統的學習藍牙。
2、藍牙的協議框架
A2dp Handset opp Hid Health Pan Map Dun...
| | |...
CORE Stack Specification
|
Host Controller Interface
|
chip
3、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
(註冊廣播監聽藍牙狀態變動、藍牙設備狀態)
4、小結
原本想採用UML畫出流程圖以備後查,無奈時間緊張、手頭沒有環境,唉作項目的人真心悲催啊!待續...java