Android Bluetooth | 蓝牙开启源码分析

    好早之前就准备入坑蓝牙了,只是也没想到最终会选择入坑蓝牙方向的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,至此应用层~ 蓝牙服务层的开启流程到这里就结束了~ 。

    有些的不妥的地方也希望同好们来指点~

    其他的文章代码都已经上传到公众号上(二两仙气儿),欢迎小白一起交流学习。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值