蓝牙是Android设备中非常常见的一个feature,设备厂家可以用BT来做RC、连接音箱、设备本身做Sink等常见功能。如果一些设备不需要BT功能,Android也可以通过配置来disable此模块,方便厂家为自己的设备做客制化。APP操作设备的蓝牙功能,一般是通过标准API-BluetoothAdapter实现,这里我们先不关心具体API的实现flow,先来了解Bluetooth framework的启动过程,这样可以为后面介绍一些BT 常见flow,做铺垫。
我们都知道Android的主要系统服务都是在system_server中启动的,BT也不例外:
// Skip Bluetooth if we have an emulator kernel
// TODO: Use a more reliable check to see if this product should
// support Bluetooth - see bug 988521
if (isEmulator) {
Slog.i(TAG, "No Bluetooth Service (emulator)");
} else if (mFactoryTestMode == FactoryTest.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 {
traceBeginAndSlog("StartBluetoothService");
mSystemServiceManager.startService(BluetoothService.class);
traceEnd();
}
在SystemServer中,BT framework启动的起点以服务启动的形式表现,这在Android中非常常见;我们可以通过配置feature xml文件来表明系统当前是否支持蓝牙,在一些没有蓝牙模组的设备上,就可以去掉hardware feature bluetooth的声明,这样设备启动时就不会启动BT framework相关的模块了:
@frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java
class BluetoothService extends SystemService {
private BluetoothManagerService mBluetoothManagerService;
public BluetoothService(Context context) {
super(context);
//创建BluetoothManagerService的实例
mBluetoothManagerService = new BluetoothManagerService(context);
}
........
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
//将BluetoothManagerService实例发布到系统中,这样就可以Context根据BT的service名去获取它的Binder代理操作API了
publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
mBluetoothManagerService);
} else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
//此时系统应该启动到一个比较晚的阶段了,可以使用AMS去Bind需要的Service了
mBluetoothManagerService.handleOnBootPhase();
}
}
........
}
BluetoothManagerService构造过程中,跟开机flow中自动enable bt相关的主要是mEnableExternal这个flag:
BluetoothManagerService(Context context) {
mHandler = new BluetoothHandler(IoThread.get().getLooper());//创建内部处理msg的handler
mContext = context;
mPermissionReviewRequired = context.getResources()
.getBoolean(com.android.internal.R.bool.config_permissionReviewRequired);
mCrashes = 0;
mBluetooth = null;
mBluetoothBinder = null;
mBluetoothGatt = null;
mBinding = false;
mUnbinding = false;
mEnable = false;
mState = BluetoothAdapter.STATE_OFF;
mQuietEnableExternal = false;//false表示此次enable需要触发auto connect device和保存状态,BluetoothAdapter::enableNoAutoConnect()可以改变此状态
mEnableExternal = false;
mAddress = null;
mName = null;
mErrorRecoveryRetryCounter = 0;
mContentResolver = context.getContentResolver();
// Observe BLE scan only mode settings change.
registerForBleScanModeChange();
mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);//监听App通过接口修改BT local name的广播(对端设备搜索你显示的字符串)
filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);//监听bt地址改变的广播
filter.addAction(Intent.ACTION_SETTING_RESTORED);//监听当前设置需要restore回上一次设置的广播,此时需要重新保存name和addr为上一次的信息
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(mReceiver, filter);
loadStoredNameAndAddress();//从数据库中加载本机Bt的local name和address
if (isBluetoothPersistedStateOn()) {//查看上一次关机时,BT是否为enable状态;如果是,这次开机也需要enable BT
if (DBG) {
Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
}
mEnableExternal = true;//表明开机过程中需要enable BT
}
String airplaneModeRadios =
Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
if (airplaneModeRadios == null || airplaneModeRadios.contains(
Settings.Global.RADIO_BLUETOOTH)) {
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
mAirplaneModeObserver);//监听Airplane mode改变,相应改变BT状态;这在TV plateform上基本没用
}
int systemUiUid = -1;
try {
// Check if device is configured with no home screen, which implies no SystemUI.
boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen);
if (!noHome) {
systemUiUid = mContext.getPackageManager()
.getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY,
UserHandle.USER_SYSTEM);
}
Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid));
} catch (PackageManager.NameNotFoundException e) {
// Some platforms, such as wearables do not have a system ui.
Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
}
mSystemUiUid = systemUiUid;
}
它为true,表明上一次关机前BT就是enable的,这次开机也需要enable;其他的主要是一些广播、数据库字段的初始化动作。
回到前面BluetoothService启动的过程,当系统启动到合适的阶段,就回调SystemService相应的函数,当phase为PHASE_ACTIVITY_MANAGER_READY时,调用到BMS::handleOnBootPhase(),进行BT framework的启动:
/**
* Send enable message and set adapter name and address. Called when the boot phase becomes
* PHASE_SYSTEM_SERVICES_READY.
*/
public void handleOnBootPhase() {
if (DBG) {
Slog.d(TAG, "Bluetooth boot completed");
}
UserManagerInternal userManagerInternal =
LocalServices.getService(UserManagerInternal.class);
userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
final boolean isBluetoothDisallowed = isBluetoothDisallowed();
if (isBluetoothDisallowed) {
return;
}
if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
if (DBG) {
Slog.d(TAG, "Auto-enabling Bluetooth.");
}
sendEnableMsg(mQuietEnableExternal/*默认false,表示此次enable需要自动连接device/保存enable状态*/,
BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,
mContext.getPackageName());
} else if (!isNameAndAddressSet()) {
if (DBG) {
Slog.d(TAG, "Getting adapter name and address");
}
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(getMsg);
}
}
handleOnBootPhase()的内容比较单一,根据一些flag判断是否需要enable BT;而enable蓝牙这里是通过触发send msg实现:
private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
//发送MESSAGE_ENABLE msg
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));
addActiveLog(reason, packageName, true);
mLastEnabledTime = SystemClock.elapsedRealtime();
}
case MESSAGE_ENABLE:
if (DBG) {
Slog.d(TAG, "MESSAGE_ENABLE(" + msg.arg1 + "): mBluetooth = " + mBluetooth);
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
// Use service interface to get the exact state
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) { //开机第一次enable,值为null
int state = mBluetooth.getState();
if (state == BluetoothAdapter.STATE_BLE_ON) {//大部分设备一般都不是ble only mode
Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
mBluetooth.onLeServiceUp();
persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
break;
}
}
} catch (RemoteException e) {
Slog.e(TAG, "", e);
} finally {
mBluetoothLock.readLock().unlock();
}
mQuietEnable = (msg.arg1 == 1);//此时为false
if (mBluetooth == null) {//mBluetooth是后面绑定Bt apk中AdapterService时拿到的Binder代理对象;用以把操作bypass到BT核心框架中
handleEnable(mQuietEnable);
} else {//如果mBluetooth不是null,说明之前已经启动过了;此时是Restart flow,以MESSAGE_RESTART_BLUETOOTH_SERVICE触发
//
// We need to wait until transitioned to STATE_OFF and
// the previous Bluetooth process has exited. The
// waiting period has three components:
// (a) Wait until the local state is STATE_OFF. This
// is accomplished by "waitForOnOff(false, true)".
// (b) Wait until the STATE_OFF state is updated to
// all components.
// (c) Wait until the Bluetooth process exits, and
// ActivityManager detects it.
// The waiting for (b) and (c) is accomplished by
// delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
// message. On slower devices, that delay needs to be
// on the order of (2 * SERVICE_RESTART_TIME_MS).
//
waitForOnOff(false, true);
Message restartMsg =
mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
}
break;
handleEnable()去Bind AdapterService拿到它的Binder句柄,bindServiceAsUser如果服务端没有启动,就会去启动服务端:
private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
......
private class BluetoothServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName componentName, IBinder service) {
String name = componentName.getClassName();
if (DBG) {
Slog.d(TAG, "BluetoothServiceConnection: " + name);
}
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
} else if (name.equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
Slog.e(TAG, "Unknown service connected: " + name);
return;
}
msg.obj = service;
mHandler.sendMessage(msg);
}
public void onServiceDisconnected(ComponentName componentName) {
// Called if we unexpectedly disconnect.
String name = componentName.getClassName();
if (DBG) {
Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);
}
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
} else if (name.equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
Slog.e(TAG, "Unknown service disconnected: " + name);
return;
}
mHandler.sendMessage(msg);
}
}
......
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)) {
Slog.e(TAG, "Fail to bind to: " + intent);
return false;
}
return true;
}
IBluetooth.class对于的Service声明在Bluetooth apk的manifest xml中,AdapterService是真正的服务端:
@packages/apps/Bluetooth/AndroidManifest.xml
<application android:name=".btservice.AdapterApp"
android:icon="@mipmap/bt_share"
android:persistent="false"
android:label="@string/app_name"
android:supportsRtl="true"
android:usesCleartextTraffic="false"
android:directBootAware="true
android:defaultToDeviceProtectedStorage="true"
<service
android:process="@string/process"
android:name = ".btservice.AdapterService">
<intent-filter>
<action android:name="android.bluetooth.IBluetooth" />
</intent-filter>
</service>
@packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
public class AdapterService extends Service {
private static final String TAG = "BluetoothAdapterService";
public void onCreate() {
super.onCreate();
debugLog("onCreate()");
去Bind AdapterService服务,并拿到它的Binder句柄,用以后面操作它的接口。AdapterService的初始化下篇再讲,现在先回到BMS binder成功之后发送MESSAGE_BLUETOOTH_SERVICE_CONNECTED(arg1:SERVICE_IBLUETOOTH)的处理:
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
if (DBG) {
Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
}
IBinder service = (IBinder) msg.obj; //保存Service的onBinder()句柄
try {
mBluetoothLock.writeLock().lock();
if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt =
IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
continueFromBleOnState();
break;
} // else must be SERVICE_IBLUETOOTH
//Remove timeout
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
mBinding = false;
mBluetoothBinder = service;
mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));//再转成IBluetooth对象
if (!isNameAndAddressSet()) {
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(getMsg);
if (mGetNameAddressOnly) {
return;
}
}
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);//mBluetoothCallback用来监听BT的enable状态,如state_on/state_off的状态变化
} catch (RemoteException re) {
Slog.e(TAG, "Unable to register BluetoothCallback", re);
}
//Inform BluetoothAdapter instances that service is up
sendBluetoothServiceUpCallback();
//Do enable request
try {
if (!mQuietEnable) {
if (!mBluetooth.enable()) {//Service bind成功之后,call AdpaterService的enable()接口;做一些初始化动作,并向stack发送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();
}
if (!mEnable) {
waitForOnOff(true, false);
handleDisable();
waitForOnOff(false, false);
}
break;
}
主要操作:
拿到bind服务的onBinder()句柄,并转成IBluetooth类型
通过IBluetooth类型的obj,调用enable()接口,将flow转到AdapterService中,做一些初始化、并向stack下enable bt的cmd
也要注意到,如果BMS中和AdapterService的连接断掉了,最终会通过MESSAGE_RESTART_BLUETOOTH_SERVICE msg去重新bind它;这在场景可能是由于模组异常导致Bluetooth apk crash(会产生tombstone),与AdapterService的bind连接断掉;这里触发Restart,会导致重走一遍介绍的enable BT流程。
到此,enable BT的flow就从BluetoothManagerService转到AdapterService中了;实际上,通过BluetoothAdapter下来的大部分API调用最终都是call到AdapterService,再通过它下cmd给stack。
AdapterService是蓝牙框架中一个非常重要的服务,它的启动和初始化部分,我们下篇再单独介绍。
PS:
可以看到BT启动过程中有两个常见到的flag:
mEnable:它主要是用来标记系统运行时,蓝牙状态的变化,它有些时候时跟mEnableExternal值一致的。但如果蓝牙的状态是因为某些原因,如stack崩溃,导致蓝牙需要reset、重新启动时,需要靠这个flag来标记这种case的enable/disable状态
mEnableExternal:它主要是记录通过用户手动操作导致的BT使能状态,如通过蓝牙功能按钮来enable/disable BT
@packages/apps/Bluetooth/AndroidManifest.xml
<application android:name=".btservice.AdapterApp"
android:icon="@mipmap/bt_share"
android:persistent="false"
android:label="@string/app_name"
android:supportsRtl="true"
android:usesCleartextTraffic="false"
android:directBootAware="true
android:defaultToDeviceProtectedStorage="true"
<service
android:process="@string/process"
android:name = ".btservice.AdapterService">
<intent-filter>
<action android:name="android.bluetooth.IBluetooth" />
</intent-filter>
</service>