廢話不說,直接擼代碼。
模塊一:模擬手機設置界面打開藍牙操作逐步分析。
Step1
對應文件packages/apps/Settings/SettingsActivity.java
private static final String[] ENTRY_FRAGMENTS = {
......
BluetoothSettings.class.getName(),
......
}```
藍牙作爲衆多設置的一個,也被添加到數組中了。
Step2
藍牙設置界面
對應文件ackages/apps/Settings/bluetooth/BluetoothSettings.java
public class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
……….
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);
mBluetoothEnabler.setupSwitchBar();
}
}
繼承自fragment,添加了一個switchBar。嗯,接下來分析BluetoothEnabler這個文件時如何來控制藍牙的開關的。
Step3
文件目錄:packages/apps/Settings/bluetooth/BluetoothEnabler.java
`public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (isChecked &&
!WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off
switchView.setChecked(false);
}
MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked);
Log.d(TAG, "mUpdateStatusOnly is " + mUpdateStatusOnly);
/// M: if receive bt status changed broadcast, do not need enable/disable bt.
if (mLocalAdapter != null && !mUpdateStatusOnly) {
mLocalAdapter.setBluetoothEnabled(isChecked);
}
mSwitch.setEnabled(false);
}`
Step4
調用bluetoothAdapter的setBluetoothEnabled(isChecked)方法,
boolean success = enabled ? mAdapter.enable() : mAdapter.disable()
終於到核心類BluetoothAdapter了。
目錄來了一個大的改變從packages目錄到了frameworks目錄。
frameworks/base/core/java/android/bluetooth/bluetoothAdapter.java
@SystemApi
public boolean enableBLE() {
if (!isBleScanAlwaysAvailable()) return false;
if (isLeEnabled() == true) {
if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
try {
mManagerService.updateBleAppCount(mToken, true);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
return true;
}
try {
if (DBG) Log.d(TAG, "Calling enableBLE");
mManagerService.updateBleAppCount(mToken, true);
return mManagerService.enable();
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
return false;
}
Step5
重點關注 return mManagerService.enable(); mManagerService的創建時在BluetoothAdapter中完成的
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;
}
/**
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
*/
BluetoothAdapter(IBluetoothManager managerService) {
if (managerService == null) {
throw new IllegalArgumentException("bluetooth manager service is null");
}
try {
mService = managerService.registerAdapter(mManagerCallback);
} catch (RemoteException e) {Log.e(TAG, "", e);}
mManagerService = managerService;
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
mToken = new Binder();
}
我們可以看到,getDefaultAdapter方法和構造方法配合着使用。當獲取實例時,mManagerService也實例化了。首先通過ServiceManager的getService返回一個binder類型的對象,然後獲取到遠程對象的接口managerService ,來進行遠程調用。這樣我們直接查看frameworks/base/core/java/android/bluetooth/BluetoothManagerService 的enable方法。
Step5
在這裏前面最終還是調用了, sendEnableMsg(false);發送了MESSAGE_ENABLE消息,我們看看,哪個handler接收了這個消息。
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);
}
/// M: MoMS permission check @{
if (MobileManagerUtils.isSupported()) {
checkEnablePermission();
return true;
}
/// @}
synchronized(mReceiver) {
mQuietEnableExternal = false;
mEnableExternal = true;
// waive WRITE_SECURE_SETTINGS permission check
sendEnableMsg(false);
}
if (DBG) Log.d(TAG, "enable returning");
return true;
}
private void sendEnableMsg(boolean quietMode) {
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
quietMode ? 1 : 0, 0));
}
Step6
BluetoothManagerService有個內部類BluetoothHandler.java,繼續發消息,裏面有個doBind方法,發現最終拉起一個Service,看看ServiceConnection的onServiceConected方法,發現又是發消息MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED,裏面會根據AdapterService和GattService的差異區別發送,最終傳一個binder對象到message中,繼續看看這個消息發送的目的地,他在BluetoothHandler中,這裏也是把之前的binder對象轉化成調用遠程服務的接口,所以最終我們要看在
AdapterService和GattService是如何處理的。
public void handleMessage(Message msg) {
...
case MESSAGE_ENABLE:
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
handleEnable(msg.arg1 == 1);
break;
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{
。。。。
IBinder service = (IBinder) msg.obj;
synchronized(mConnection) {
if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
onBluetoothGattServiceUp();
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);
}
.....
break;
}
case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
{
Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
synchronized(mConnection) {
if (msg.arg1 == SERVICE_IBLUETOOTH) {
// if service is unbinded already, do nothing and return
if (mBluetooth == null) break;
mBluetooth = null;
} else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt = null;
break;
} else {
Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
break;
}
}
...
}
private void handleEnable(boolean quietMode) {
synchronized(mConnection) {
if ((mBluetooth == null) && (!mBinding)) {
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 | Context.BIND_IMPORTANT,
UserHandle.CURRENT)) {
}
}
boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
Log.e(TAG, "Fail to bind to: " + intent);
return false;
}
return true;
}
private class BluetoothServiceConnection implements ServiceConnection {
。。。。。
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);
}
。。。。
}
Step7
上面已經說到,要找AdapterService和GattService裏繼續追蹤。接下來重點考慮AdapterService,他的路徑在Packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService,所以又從framework層調到了app層。從何處入手了,Step6中說了拉起服務的事,其實後面拉起服務後還會有一段代碼,啓動藍牙,我們看看AdapterService的enable方法。
//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);
}
public class AdapterService extends Service {
...
public synchronized boolean enable(boolean quietMode) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
debugLog("enable() - Enable called with quiet mode status = " + mQuietmode);
mQuietmode = quietMode;
Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_ON);
mAdapterStateMachine.sendMessage(m);
return true;
}
...
}
Step8
嗯,繼續發消息,AdapterState.BLE_TURN_ON
Packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java,裏面有很多stateMachine,也有對消息的監聽這裏,我也有點蒙圈,不按照套路出牌,最終要調用adapterService.enableNative()的native方法,進行jni通信。
case BLE_TURN_ON:
if (isTurningOff || isBleTurningOff) {
infoLog("Deferring BLE_TURN_ON request...");
deferMessage(msg);
}
break;
case BLE_STARTED:
//Remove start timeout
removeMessages(BLE_START_TIMEOUT);
//Enable
if (!adapterService.enableNative()) {
errorLog("Error while turning Bluetooth on");
notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);
transitionTo(mOffState);
} else {
sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);
}
break;
Step9
從應用層調到了藍牙協議棧了,我們看看它的c++層是如何操作的。
Packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp,藍牙驅動對象sBluetoothInterface的enable方法。好吧我再也分析不下去了。
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;
}
總的來說博通寫的藍牙模塊的內容涉及了好多message信息的處理。下面一篇我會對藍牙文件傳輸進行分析。