前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 上层蓝牙enable流程

Android 上层蓝牙enable流程

作者头像
小蚂蚁与大象
发布2021-12-16 09:31:20
1.4K0
发布2021-12-16 09:31:20
举报
文章被收录于专栏:构建FFmpeg Android播放器

Android 蓝牙框架

基于Android9.0 Amlogic代码分析, 蓝牙应用通过 Binder 与蓝牙进程进行通信。蓝牙进程使用 JNI 与蓝牙堆栈通信,并向开发者提供对各种蓝牙配置文件的访问权限。下图显示了蓝牙堆栈的常规结构:

fluoride_architecture.png

代码语言:javascript
复制
应用框架
 client:
 frameworks/base/core/java/android/bluetooth/*
 servie:
 framework/base/services/core/java/com/android/server/BluetoothService.java
 framework/base/services/core/java/com/android/server/BluetoothManagerService.java

这部分主要提供给app调用的api,跟其他系统服务一样,分为client端和service端,通过binder通讯

蓝牙系统服务 蓝牙系统服务(位于 packages/apps/Bluetooth 中)被打包为 Android 应用,并在 Android 框架层实现蓝牙服务和配置文件。此应用通过 JNI 调用原生蓝牙堆栈。

JNI 与 android.bluetooth 相关联的 JNI 代码位于 packages/apps/Bluetooth/jni 中。当发生特定蓝牙操作时(例如发现设备时),JNI 代码会调用蓝牙堆栈。

蓝牙堆栈 AOSP 中提供了默认蓝牙堆栈(位于 system/bt 中)。该堆栈实现常规蓝牙 HAL,并通过扩展程序和更改配置对其进行自定义

供应商实现 供应商设备使用硬件接口设计语言 (HIDL) 与蓝牙堆栈交互。

framework与bluetootk app

android 蓝牙framework层跟其他系统服务有点不同,framework层的service主要是跟bluetooth app的sercive进行绑定,大部分功能逻辑都是在bluetooth app实现

mManagerService在打开蓝牙的时候会间接调用到handleEnable方法,handleEnable的dobind会绑定BluetoothService,回调到BluetoothServiceConnection方法中把service赋值给mBluetooth,这样我们就可以拿到Bluetooth app里的service(AdapterService)进行操作了

代码语言:javascript
复制
    //打开蓝牙的时候会间接调用到handleEnable方法
    private void handleEnable(boolean quietMode) {
        mQuietEnable = quietMode;

        try {
            mBluetoothLock.writeLock().lock();
            if ((mBluetooth == null) && (!mBinding)) {

                //绑定bluetooth app Service
                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) {
                
            }
        } finally {
            mBluetoothLock.writeLock().unlock();
        }
    }

    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;
    }

    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);
            }

           //service绑定成功后,会回调。第一步是先绑定AdapterService,
           //之后通过AdapterService 去启动GattService,并且
            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) {

        }
    }

 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
                    if (DBG) {
                        Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
                    }

                    IBinder service = (IBinder) msg.obj;
                    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));

                     //Do enable request
                        try {
                            if (!mQuietEnable) {
                                if (!mBluetooth.enable()) {
                                    Slog.e(TAG, "IBluetooth.enable() returned false");
                                }
                            } else {
                                if (!mBluetooth.enableNoAutoConnect()) {
                                    Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
                                }
                            }
                        } 

和bluetooth app service绑定成功后,BluetoothManagerService会获取到bluetooth app 两个service binder对象 mBluetooth 绑定的是 AdapterService mBluetoothGatt 绑定的是 GattService

frame_app.png

总结:

  1. BluetoothManagerService 通过 bind 绑定AdapterService,连接成功后,通过回调onServiceConnected获取到AdapterService 里面的binder对象
  2. 调用AdapterService enable,触发enable流程,enable流程中会启动GattService去打开蓝牙和Ble。
  3. 蓝牙打开成功后会native会回调AdapterService。AdapterService会继续调用状态机进行处理,而在每次状态机发生改变后,AdapterService 都会回调BluetoothManagerService bluetoothStateChangeHandler
  4. BluetoothManagerService 收到回调后会再次通过bind 绑定GattService
  5. 绑定成功后 会走continueFromBleOnState() --> onLeServiceUp流程, 启动bluetooth app里面其他service

相对详细的流程看下节分析

bluetooth app

Bluetooth apk是蓝牙功能逻辑具体的实现。常规打开关闭功能在AdapterService入口实现。这些方法最后跟踪都会跟踪到native方法上

enable流程

上层或设置同过enable接口打开蓝牙时,会调用到AdapterService.java的接口enable,大体时序图如下所示:

SequenceDiagram1.png

AdapterService通过AdapterState进行状态转换

代码语言:javascript
复制
private AdapterState mAdapterStateMachine;

 public synchronized boolean enable(boolean quietMode) {
        ...
        mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);
    }

AdapterState.java代码片段

代码语言:javascript
复制
private TurningOnState mTurningOnState = new TurningOnState();
private TurningBleOnState mTurningBleOnState = new TurningBleOnState();
private TurningOffState mTurningOffState = new TurningOffState();
private TurningBleOffState mTurningBleOffState = new TurningBleOffState();
private OnState mOnState = new OnState();
private OffState mOffState = new OffState();
private BleOnState mBleOnState = new BleOnState();

private AdapterState(AdapterService service) {
        super(TAG);
        addState(mOnState);
        addState(mBleOnState);
        addState(mOffState);
        addState(mTurningOnState);
        addState(mTurningOffState);
        addState(mTurningBleOnState);
        addState(mTurningBleOffState);
        mAdapterService = service;
        setInitialState(mOffState);
    }

AdapterState 是一个状态机,状态机改变状态时就会执行类的一些行为。构造函数默认是mOffState,收到BLE_TURN_ON消息。那么第一个地方就是OffState的processMessage处理BLE_TURN_ON,消息也是再直接传递到TurningBleOnState

AdapterState.java代码片段

代码语言:javascript
复制
private class OffState extends BaseAdapterState {
        ...
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case BLE_TURN_ON:
                    transitionTo(mTurningBleOnState);
                    break;
        }
    }
代码语言:javascript
复制
private class TurningBleOnState extends BaseAdapterState {
        ...
        @Override
        public void enter() {
            super.enter();
            sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
            mAdapterService.bringUpBle();
        }

这里会调用到AdapterService,开始启动ble 服务

代码语言:javascript
复制
 void bringUpBle() {
    ...
    //Start Gatt service
    setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON);
 }

 private void setProfileServiceState(Class service, int state) {
        Log.e(TAG, "setProfileServiceStat :" + service.getSimpleName());
        Intent intent = new Intent(this, service);
        intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
        startService(intent);
    }

bluetooth apk里面很多service都时继承自ProfileService, 这里通过启动startService会调用到ProfileService的onStartCommand,service启动完后会回调到AdapterService

ProfileService.java 代码片段

代码语言:javascript
复制
 private void doStart() {
        // 回调到 AdapterService MESSAGE_PROFILE_SERVICE_REGISTERED
        mAdapterService.addProfile(this);  

        //调用到对应子类的的 start方法
        mProfileStarted = start();
        if (!mProfileStarted) {
            Log.e(mName, "Error starting profile. start() returned false.");
            return;
        }
       // 回调到 AdapterService MESSAGE_PROFILE_SERVICE_REGISTERED
        mAdapterService.onProfileServiceStateChanged(this, BluetoothAdapter.STATE_ON);
    }

这是第一步先启动GattService。

启动其他Service

在蓝牙打开成功之后,JNI层会通过JniCallbacks的stateChangeCallback方法把消息回调给AdapterService处理,AdapterService则继续把消息给到状态机处理:

AdapterService.java代码片段:

代码语言:javascript
复制
void stateChangeCallback(int status) {
        if (status == AbstractionLayer.BT_STATE_OFF) {
            debugLog("stateChangeCallback: disableNative() completed");
            mAdapterStateMachine.sendMessage(AdapterState.BLE_STOPPED);
        } else if (status == AbstractionLayer.BT_STATE_ON) {
            mAdapterStateMachine.sendMessage(AdapterState.BLE_STARTED);
        } else {
            Log.e(TAG, "Incorrect status " + status + " in stateChangeCallback");
        }
    }

此时的AdapterState处于TurningBleOnState状态,TurningBleOnState在接收到BLE_STARTED消息后,迁入到BleOnState状态:

AdapterState.java代码片段:

代码语言:javascript
复制
private class TurningBleOnState extends BaseAdapterState {
        .......
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case BLE_STARTED:
                    transitionTo(mBleOnState);
                    break;
               ........
    }

每一个状态的迁移,都会触发AdapterService的updateAdapterState,这个方法内部会把状态改变回调给远程的监听者:

AdapterState.java代码片段:

代码语言:javascript
复制
private abstract class BaseAdapterState extends State {

        abstract int getStateValue();

        @Override
        public void enter() {
            int currState = getStateValue();
            infoLog("entered ");
            mAdapterService.updateAdapterState(mPrevState, currState);
            mPrevState = currState;
        }

AdapterService.java代码片段:

代码语言:javascript
复制
void updateAdapterState(int prevState, int newState) {
        mAdapterProperties.setState(newState);
        if (mCallbacks != null) {
            int n = mCallbacks.beginBroadcast();
            debugLog("updateAdapterState() - Broadcasting state " + BluetoothAdapter.nameForState(
                    newState) + " to " + n + " receivers.");
            for (int i = 0; i < n; i++) {
                try {
                    mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState, newState);  //远程回调
                } catch (RemoteException e) {
                    debugLog("updateAdapterState() - Callback #" + i + " failed (" + e + ")");
                }
            }
            mCallbacks.finishBroadcast();
        }

这里会远程回调到BluetoothManagerService里面的监听接口,经过handler消息处理机制会调用到bluetoothStateChangeHandler方法:

BluetoothManagerService.java代码片段

代码语言:javascript
复制
private class BluetoothHandler extends Handler {
        ...
        @Override
        public void handleMessage(Message msg) {
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
                    IBinder service = (IBinder) msg.obj;
                    try {
                        mBluetoothLock.writeLock().lock();
                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
                            continueFromBleOnState();
                            break;
                        } 

    private void continueFromBleOnState() {
         ...
         mBluetooth.onLeServiceUp();
    }

mBluetooth.onLeServiceUp() 调用到了AdapterService

AdapterService.java 代码片段

代码语言:javascript
复制
    void onLeServiceUp() {
        mAdapterStateMachine.sendMessage(AdapterState.USER_TURN_ON);
    }

接着是跟上面启动gattService的流程差不多, 通过状态机切换,调用到AdapterService,启动

AdapterState.java代码片段

代码语言:javascript
复制
private class TurningOnState extends BaseAdapterState {
        @Override
        public void enter() {
            ...
            mAdapterService.startProfileServices();
        }

AdapterService.java 代码片段

代码语言:javascript
复制
void startProfileServices() {
        Class[] supportedProfileServices = Config.getSupportedProfiles();
        ...
            setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON);
        }
    }
private void setAllProfileServiceStates(Class[] services, int state) {
        for (Class service : services) {
            if (GattService.class.getSimpleName().equals(service.getSimpleName())) {
                continue;
            }
            setProfileServiceState(service, state);
        }
    }

 private void setProfileServiceState(Class service, int state) {
        Intent intent = new Intent(this, service);
        intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
        startService(intent);
    }

这里用for循环,启动supportedProfileServices里面的所有service, 这里的service都是继承自ProfileService, 每个service启动完后都会回调到AdapterService,当所有service都启动完后会走到下面else if的流程

代码语言:javascript
复制
 private void processProfileServiceStateChanged(ProfileService profile, int state) {
            switch (state) {
                case BluetoothAdapter.STATE_ON:
                    if (GattService.class.getSimpleName().equals(profile.getName())) {
                        enableNativeWithGuestFlag();
                    } else if (mRegisteredProfiles.size() == Config.getSupportedProfiles().length - 1
                            && mRegisteredProfiles.size() == mRunningProfiles.size()) {
                        mAdapterProperties.onBluetoothReady();
                        updateUuids();
                        setBluetoothClassFromConfig();

                        mAdapterStateMachine.sendMessage(AdapterState.BREDR_STARTED);
                    }
                    break;
app启动总结:

图片来自https://blog.csdn.net/yus201120/article/details/119038589

beac4f61a8a842d08d0ecc0eb70207cd.png

参考: https://source.android.google.cn/devices/bluetooth?hl=zh-cn https://www.jianshu.com/p/b15314d91df0 https://blog.csdn.net/yus201120/article/details/119038589

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/12/10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Android 蓝牙框架
    • framework与bluetootk app
    • bluetooth app
      • 启动其他Service
      相关产品与服务
      腾讯云代码分析
      腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,助力维护团队卓越代码文化。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档