第一次接觸藍牙,先從藍牙的開啓流程入手吧,藉此順便熟悉一下藍牙的代碼架構。
1、UI
/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java
public void onClick(View v) {
// send users to scanning settings if they click on the link in the summary text
new SubSettingLauncher(mContext)
.setDestination(ScanningSettings.class.getName())
.setSourceMetricsCategory(MetricsProto.MetricsEvent.BLUETOOTH_FRAGMENT)
.launch();
}
/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEnabler.java
public boolean onSwitchToggled(boolean isChecked) {
if (maybeEnforceRestrictions()) {
triggerParentPreferenceCallback(isChecked);
return true;
}
// Show toast message if Bluetooth is not allowed in airplane mode
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
mSwitchController.setChecked(false);
triggerParentPreferenceCallback(false);
return false;
}
mMetricsFeatureProvider.action(mContext, mMetricsEvent, isChecked);
if (mLocalAdapter != null) {
boolean status = mLocalAdapter.setBluetoothEnabled(isChecked);
// If we cannot toggle it ON then reset the UI assets:
// a) The switch should be OFF but it should still be togglable (enabled = True)
// b) The switch bar should have OFF text.
if (isChecked && !status) {
mSwitchController.setChecked(false);
mSwitchController.setEnabled(true);
mSwitchController.updateTitle(false);
triggerParentPreferenceCallback(false);
return false;
}
}
mSwitchController.setEnabled(false);
triggerParentPreferenceCallback(isChecked);
return true;
}
2、framework
public boolean 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();
}
return success;
}
/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
if (isEnabled()) {
if (DBG) {
Log.d(TAG, "enable(): BT already enabled!");
}
return true;
}
try {
return mManagerService.enable(ActivityThread.currentPackageName());
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
return false;
}
這個方法中的關鍵代碼是“return mManagerService.enable();” mManagerService 對象是由IBluetoothManager 接口代碼實現的,IBluetoothManager實際定義的是AIDL文件,對應的類就是 BluetoothManagerService 類,在路徑 frameworks/base/core/java/android/bluetooth/BluetoothManagerService 下面 。
/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java
public boolean enable(String packageName) throws RemoteException {
final int callingUid = Binder.getCallingUid();
final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
if (isBluetoothDisallowed()) {
if (DBG) {
Slog.d(TAG, "enable(): not enabling - bluetooth disallowed");
}
return false;
}
if (!callerSystem) {
if (!checkIfCallerIsForegroundUser()) {
Slog.w(TAG, "enable(): not allowed for non-active and non system user");
return false;
}
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
if (!isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName,
callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
return false;
}
}
if (DBG) {
Slog.d(TAG, "enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = "
+ mBinding + " mState = " + BluetoothAdapter.nameForState(mState));
}
synchronized (mReceiver) {
mQuietEnableExternal = false;
mEnableExternal = true;
// waive WRITE_SECURE_SETTINGS permission check
sendEnableMsg(false,
BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
}
if (DBG) {
Slog.d(TAG, "enable returning");
}
return true;
}
方法中先判斷是否是系統app操作藍牙,檢查是否有操作藍牙的權限等,然後關鍵的代碼是“sendEnableMsg(false)”,handler最後調用handleEnable方法處理該消息。
private void handleEnable(boolean quietMode) {
mQuietEnable = quietMode;
try {
mBluetoothLock.writeLock().lock();
if ((mBluetooth == null) && (!mBinding)) {
//Start bind timeout and bind
Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
Intent i = new Intent(IBluetooth.class.getName());
if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
UserHandle.CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
} else {
mBinding = true;
}
} else if (mBluetooth != null) {
//Enable bluetooth
try {
if (!mQuietEnable) {
if (!mBluetooth.enable()) {
Slog.e(TAG, "IBluetooth.enable() returned false");
}
} else {
if (!mBluetooth.enableNoAutoConnect()) {
Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
}
}
} catch (RemoteException e) {
Slog.e(TAG, "Unable to call enable()", e);
}
}
} finally {
mBluetoothLock.writeLock().unlock();
}
}
這裏通過AIDL的方式,調用Bluetooth App 中的AdapterService 。先綁定服務,然後註冊Ibluetooth回調函數,之後調用enable方法方法開啓藍牙。所以之後就從Framworks 跳到 Bluetooth APP 中繼續分析。
3、Bluetooth APP
/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
public synchronized boolean enable(boolean quietMode) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
// Enforce the user restriction for disallowing Bluetooth if it was set.
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM)) {
debugLog("enable() called when Bluetooth was disallowed");
return false;
}
debugLog("enable() - Enable called with quiet mode status = " + quietMode);
mQuietmode = quietMode;
mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);
return true;
}
private class OffState extends BaseAdapterState {
@Override
int getStateValue() {
return BluetoothAdapter.STATE_OFF;
}
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case BLE_TURN_ON:
transitionTo(mTurningBleOnState);
break;
default:
infoLog("Unhandled message - " + messageString(msg.what));
return false;
}
return true;
}
}
private class TurningBleOnState extends BaseAdapterState {
@Override
int getStateValue() {
return BluetoothAdapter.STATE_BLE_TURNING_ON;
}
@Override
public void enter() {
super.enter();
sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
mAdapterService.bringUpBle();
}
@Override
public void exit() {
removeMessages(BLE_START_TIMEOUT);
super.exit();
}
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case BLE_STARTED:
transitionTo(mBleOnState);
break;
case BLE_START_TIMEOUT:
errorLog(messageString(msg.what));
transitionTo(mTurningBleOffState);
break;
default:
infoLog("Unhandled message - " + messageString(msg.what));
return false;
}
return true;
}
}
/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
void bringUpBle() {
debugLog("bleOnProcessStart()");
if (getResources().getBoolean(
R.bool.config_bluetooth_reload_supported_profiles_when_enabled)) {
Config.init(getApplicationContext());
}
mRemoteDevices.reset();
mAdapterProperties.init(mRemoteDevices);
debugLog("bleOnProcessStart() - Make Bond State Machine");
mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices);
mJniCallbacks.init(mBondStateMachine, mRemoteDevices);
try {
mBatteryStats.noteResetBleScan();
} catch (RemoteException e) {
Log.w(TAG, "RemoteException trying to send a reset to BatteryStats");
}
StatsLog.write_non_chained(StatsLog.BLE_SCAN_STATE_CHANGED, -1, null,
StatsLog.BLE_SCAN_STATE_CHANGED__STATE__RESET, false, false, false);
//Start Gatt service
setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON);
}
/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java
private BondStateMachine(AdapterService service, AdapterProperties prop,
RemoteDevices remoteDevices) {
super("BondStateMachine:");
addState(mStableState);
addState(mPendingCommandState);
mRemoteDevices = remoteDevices;
mAdapterService = service;
mAdapterProperties = prop;
mAdapter = BluetoothAdapter.getDefaultAdapter();
setInitialState(mStableState);
}
private class StableState extends State {
@Override
public void enter() {
infoLog("StableState(): Entering Off State");
}
@Override
public boolean processMessage(Message msg) {
BluetoothDevice dev = (BluetoothDevice) msg.obj;
switch (msg.what) {
case CREATE_BOND:
OobData oobData = null;
if (msg.getData() != null) {
oobData = msg.getData().getParcelable(OOBDATA);
}
createBond(dev, msg.arg1, oobData, true);
break;
case REMOVE_BOND:
removeBond(dev, true);
break;
case BONDING_STATE_CHANGE:
int newState = msg.arg1;
/* if incoming pairing, transition to pending state */
if (newState == BluetoothDevice.BOND_BONDING) {
sendIntent(dev, newState, 0);
transitionTo(mPendingCommandState);
} else if (newState == BluetoothDevice.BOND_NONE) {
/* if the link key was deleted by the stack */
sendIntent(dev, newState, 0);
} else {
Log.e(TAG, "In stable state, received invalid newState: "
+ state2str(newState));
}
break;
case CANCEL_BOND:
default:
Log.e(TAG, "Received unhandled state: " + msg.what);
return false;
}
return true;
}
}
通過調用adapterService.enableNative()方法,開始調用JNI方法,進入C/C++層。adapterService.enableNative對應的cpp文件爲
/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
static jboolean enableNative(JNIEnv* env, jobject obj, jboolean isGuest) {
ALOGV("%s", __func__);
if (!sBluetoothInterface) return JNI_FALSE;
int ret = sBluetoothInterface->enable(isGuest == JNI_TRUE ? 1 : 0);
return (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE
: JNI_FALSE;
}
通過調用“int ret = sBluetoothInterface->enable()”來驅動底層打開藍牙開關。接下來就是C裏面對打開藍牙的實現。
4、藍牙協議棧
/system/bt/btif/src/bluetooth.cc
static int enable(bool start_restricted) {
LOG_INFO(LOG_TAG, "%s: start restricted = %d", __func__, start_restricted);
restricted_mode = start_restricted;
if (!interface_ready()) return BT_STATUS_NOT_READY;
stack_manager_get_interface()->start_up_stack_async();
return BT_STATUS_SUCCESS;
}
enable方法會調用start_up_stack_async方法,start_up_stack_async的實現在stack_manager.c 文件中:
/system/bt/btif/src/stack_manager.cc
static void start_up_stack_async(void) {
thread_post(management_thread, event_start_up_stack, NULL);
}
通過thread_post異步event_start_up_stack,來啓動藍牙棧
static void event_start_up_stack(UNUSED_ATTR void* context) {
if (stack_is_running) {
LOG_INFO(LOG_TAG, "%s stack already brought up", __func__);
return;
}
ensure_stack_is_initialized();
LOG_INFO(LOG_TAG, "%s is bringing up the stack", __func__);
future_t* local_hack_future = future_new();
hack_future = local_hack_future;
// Include this for now to put btif config into a shutdown-able state
module_start_up(get_module(BTIF_CONFIG_MODULE));
bte_main_enable();
if (future_await(local_hack_future) != FUTURE_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s failed to start up the stack", __func__);
stack_is_running = true; // So stack shutdown actually happens
event_shut_down_stack(NULL);
return;
}
stack_is_running = true;
LOG_INFO(LOG_TAG, "%s finished", __func__);
btif_thread_post(event_signal_stack_up, NULL);
}
bte_main_enable()方法中進行btsnoop_module和hci_module的啓動以及啓動BTU操作。