好早之前就准备入坑蓝牙了,只是也没想到最终会选择入坑蓝牙方向的FWK。
这篇文章呢,主要是梳理下蓝牙打开时Android应用层 ~ 蓝牙服务层的一个流程。
ps:(顺道我自己也巩固下知识,刚磕源码不久)[狗头.jpg]。
首先在梳理流程之前,我们先来看下Android中蓝牙的架构,如下图:
官方图中蓝牙的架构被分为了六部分:
APPLICATION FRAMEWORK
(Android提供的API)
BLUETOOTH PROCESS
(一个在操作系统中运行的后台进程,负责蓝牙状态的管理,允许应用程序和其他的设备进行通信)
JNI
(与硬件交互的接口)
BLUETOOTH STACK
(由多个协议栈组成的软件堆栈,负责处理蓝牙的数据流和与其他设备通信)
HIDL INTERFACES
(硬件抽象层接口)
VENDOR IMPLEMENTATION
(厂商实现,包括驱动或者一些定制内容)
好了,废话不多说。
用层APP想打开蓝牙开关时,一般是使用BluetoothAdapter,通过适配器调用enable()方法。
(当然,随着Android权限重视程度的提升,调用enbale()方法前还可能要动态检查/申请权限,这部分我略过了哈)
//声明下适配器
private BluetoothAdapter mBluetoothAdapter ;
//假装我动态检查/获取了权限
checkPermissions();
//蓝牙使能(开启)
mBluetoothAdapter.enable();
我们追踪进enable()方法,即进入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;
}
会发现BluetoothAdapter.java中调用enbale()后最终会返回
mManagerService.enable(ActivityThread.currentPackageName());
mManagerService在BluetoothAdapter.java中的声明如下:
private final IBluetoothManager mManagerService;
```
找了下IBluetoothManager ,其实是一个AIDL接口,源码如下:
```JAVA
/**
* System private API for talking with the Bluetooth service.
*
* {@hide}
*/
interface IBluetoothManager
{
IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
void unregisterAdapter(in IBluetoothManagerCallback callback);
void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
boolean isEnabled();
boolean enable(String packageName);
boolean enableNoAutoConnect(String packageName);
boolean disable(String packageName, boolean persist);
int getState();
IBluetoothGatt getBluetoothGatt();
boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
String getAddress();
String getName();
boolean isBleScanAlwaysAvailable();
int updateBleAppCount(IBinder b, boolean enable, String packageName);
boolean isBleAppPresent();
}
从官方直白的注释中“ System private API for talking with the Bluetooth service.”
这个接口是负责API与蓝牙服务进行通信的。(蓝牙服务即与上述架构中 BLUETOOTH PROCESS 层。)
BluetoothManagerService继承自IBluetoothManager.Stub,属Binder实现类,代码如下。
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 并尝试绑定到远程蓝牙服务。如果绑定成功,将 mBinding 标志设置为 true。
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();
}
}
至此开启蓝牙的动作就会传入到蓝牙服务层(BLUETOOTH PROCESS)。
进入AdapterService.java中调用enable()方法,代码如下:
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;
}
好了,终于讲到了状态机!下面先来科普下蓝牙里的状态机的“流转状态”
以开启蓝牙为例,执行“开启动作”时,并不是说开就噗~的一下开了,而时要从初始状态进行流转,这里初始指的是“OFF状态”。
开启状态的流转图如下:
可能到这里就有人会问:“为啥ON状态流转会先流转Ble?”
BLE一般被称作低功耗蓝牙,开启蓝牙时先打开低功耗蓝牙,大家可以理解为是一种容错/节能策略(一直如此)
1.蓝牙一直处于打开状态,耗电量增加,通过BLE流转的话,可以确保只有当需要使用蓝牙时才会打开它。
2.避免冲突:一些特殊情况下,同时连接多个蓝牙设备可能会导致冲突,先执行BLEon可以避免
(上述均为我个人理解,如有好奇的大佬请深入挖掘)
好了,咱们回过头来继续看代码,上边AdapterService.java中调用了
mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);
mAdapterStateMachine指向的类是AdapterState.java,代码如下:
//和上边说的状态机流程一样,先进入OffState
private class OffState extends BaseAdapterState {
@Override
int getStateValue() {
return BluetoothAdapter.STATE_OFF;
}
//在processMessage()中处理接收到的信息
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case BLE_TURN_ON:
//状态转换成TuringBleOnState
transitionTo(mTurningBleOnState);
break; default:
infoLog("Unhandled message - " + messageString(msg.what));
return false;
}
return true;
}
}
transitionTo(mTurningBleOnState);意思是状态机转换成TuringBleOnState。代码如下:
private class TurningBleOnState extends BaseAdapterState {
@Override
int getStateValue() {
return BluetoothAdapter.STATE_BLE_TURNING_ON;
}
//进入TurningBleOnState后会先执行enter()方法。
@Override
public void enter() {
super.enter();
//在超时时发送一条延时消息
sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
//调用对应方法启动BLE
mAdapterService.bringUpBle();
}
//....省略了一些代码
}
执行bringUpBle()后,会去启动Gatt的服务,而GattService服务继承自ProfileService。
而源码中,AdapterService中使用processProfileServiceStateChanged监听了ProfileService的状态改变。
故此启动GattService启动后,具体的处理会被processProfileServiceStateChanged监听and处理。 代码如下:
private void processProfileServiceStateChanged(ProfileService profile, int state) {
switch (state) {
case BluetoothAdapter.STATE_ON:
if (!mRegisteredProfiles.contains(profile)) {
Log.e(TAG, profile.getName() + " not registered (STATE_ON).");
return;
}
if (mRunningProfiles.contains(profile)) {
Log.e(TAG, profile.getName() + " already running.");
return;
}
mRunningProfiles.add(profile);
if (GattService.class.getSimpleName().equals(profile.getName())) {
//调用协议栈的接口去开启蓝牙
enableNative();
} else if (mRegisteredProfiles.size() == Config.getSupportedProfiles().length
&& mRegisteredProfiles.size() == mRunningProfiles.size()) {
mAdapterProperties.onBluetoothReady();
updateUuids();
setBluetoothClassFromConfig();
getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS);
getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS_BLE);
mAdapterStateMachine.sendMessage(AdapterState.BREDR_STARTED);
}
break;
//省略了一些代码
}
走到这步之后,就会通过这协议栈接口通知协议栈,“叼毛,我要开启蓝牙了!”
协议栈就会告诉蓝牙芯片“叼毛,有人要开启蓝牙了,命令是ATxxxxxx”
蓝牙芯片就会开启啦~
而蓝牙芯片开启后,协议栈会告知当前的蓝牙状态给蓝牙服务层
服务层会通过“广播”或者“AIDL”或者"接口回调"等方式,通知应用层进行视图的更新。
OK,至此应用层~ 蓝牙服务层的开启流程到这里就结束了~ 。
有些的不妥的地方也希望同好们来指点~