Android 蓝牙架构概述

Android 提供支持经典蓝牙和蓝牙低功耗的默认蓝牙堆栈。借助蓝牙,Android 设备可以创建个人区域网络,以便通过附近的蓝牙设备发送和接收数据。

在 Android 4.3 及更高版本中,Android 蓝牙堆栈可提供实现蓝牙低功耗 (BLE) 的功能。要充分利用 BLE API,请遵循 Android 蓝牙 HCI 要求

具有合格芯片组的 Android 设备可以实现经典蓝牙或同时实现经典蓝牙和 BLE。BLE 不能向后兼容较旧版本的蓝牙芯片组。

在 Android 8.0 中,原生蓝牙堆栈完全符合蓝牙 5 的要求。要使用可用的蓝牙 5 功能,该设备需要具有符合蓝牙 5 要求的芯片组。

注意与之前的版本相比,Android 8.0 在原生蓝牙堆栈方面的最大变化是使用了 Treble。Android 8.0 中的供应商实现必须使用 HIDL 而不是 libbt-vendor

一.Android 8.0 架构

应用框架:处于应用框架级别的是应用代码,它使用 android.bluetooth(位于frameworks/base/core/java/android/bluetooth/) API 与蓝牙硬件进行交互。此代码在内部通过 Binder IPC 机制调用蓝牙进程。

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

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

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

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

HIDL:HIDL 定义了蓝牙堆栈和供应商实现之间的接口。要生成蓝牙 HIDL 文件,请将蓝牙接口文件传递到 HIDL 生成工具中。接口文件位于 hardware/interfaces/bluetooth 中。

蓝牙堆栈开发:Android 8.0 蓝牙堆栈是一个完全限定的蓝牙堆栈。限定列表位于蓝牙 SIG 网站上的 QDID 97584 下。核心蓝牙堆栈位于 system/bt 中。

二.Android 7.x 及更早版本的架构

应用框架:处于应用框架级别的是应用代码,它利用 android.bluetooth API 与蓝牙硬件进行交互。此代码在内部通过 Binder IPC 机制调用蓝牙进程。

蓝牙系统服务:位于 packages/apps/Bluetooth 中,被打包为 Android 应用,并在 Android 框架层实现蓝牙服务和配置文件。该应用通过 JNI 调用 HAL 层。

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

HAL硬件抽象层:定义了 android.bluetooth API 和蓝牙进程会调用的标准接口,并且必须实现该接口才能使蓝牙硬件正常工作。 蓝牙 HAL 的头文件是 hardware/libhardware/include/hardware/bluetooth.h。

另外,请查看所有 hardware/libhardware/include/hardware/bt_*.h 文件。

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

供应商扩展:要添加自定义扩展程序和用于跟踪的 HCI 层,可以创建一个 libbt-vendor 模块并指定这些组件。

实现HAL:蓝牙 HAL 位于 /hardware/libhardware/include/hardware/bluetooth.h 中。 bluetooth.h 文件包含蓝牙堆栈的基本接口,而且您必须实现其功能。

三、Android源码分析

 

一、BluetoothAdapter类的初始化

frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

public static synchronized BluetoothAdapter getDefaultAdapter() {

    if (sAdapter == null) {

        IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); //1

        if (b != null) {

            IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);//2

            sAdapter = new BluetoothAdapter(managerService); //3

        else {

            Log.e(TAG, "Bluetooth binder is null");

        }

    }

    return sAdapter;

}

1.获取蓝牙管理服务,SystemServer进程中创建:mSystemServiceManager.startService(BluetoothService.class);

2.使用Binder获取到BluetoothManagerService对象

3.创建BluetoothAdapter对象,单例模式

 

BluetoothAdapter(IBluetoothManager managerService) {

 

    if (managerService == null) {

        throw new IllegalArgumentException("bluetooth manager service is null");

    }

    try {

        mServiceLock.writeLock().lock();

        mService = managerService.registerAdapter(mManagerCallback); //1

    catch (RemoteException e) {

        Log.e(TAG, "", e);

    finally {

        mServiceLock.writeLock().unlock();

    }

    mManagerService = managerService;

    mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();

    mToken = new Binder();

}

1.向BluetoothManagerService类注册回调函数

frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

public IBluetooth registerAdapter(IBluetoothManagerCallback callback) {

    if (callback == null) {

        Slog.w(TAG, "Callback is null in registerAdapter");

        return null;

    }

    Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); //1

    msg.obj = callback;

    mHandler.sendMessage(msg);

 

    return mBluetooth;

}

1.注册监听,将接口保存到RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;

二、Bluetooth Profiles的使用

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.getProfileProxy(mService, new A2dpServiceListener(),BluetoothProfile.A2DP);

frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,

        int profile) {

    if (context == null || listener == null) {

        return false;

    }

 

    if (profile == BluetoothProfile.HEADSET) {

        BluetoothHeadset headset = new BluetoothHeadset(context, listener);

        return true;

    else if (profile == BluetoothProfile.A2DP) {

        BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);

        return true;

    else if (profile == BluetoothProfile.A2DP_SINK) {

        BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);

        return true;

    else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {

        BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);

        return true;

    else if (profile == BluetoothProfile.HID_HOST) {

        BluetoothHidHost iDev = new BluetoothHidHost(context, listener);

        return true;

    else if (profile == BluetoothProfile.PAN) {

        BluetoothPan pan = new BluetoothPan(context, listener);

        return true;

    else if (profile == BluetoothProfile.HEALTH) {

        BluetoothHealth health = new BluetoothHealth(context, listener);

        return true;

    else if (profile == BluetoothProfile.MAP) {

        BluetoothMap map = new BluetoothMap(context, listener);

        return true;

    else if (profile == BluetoothProfile.HEADSET_CLIENT) {

        BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);

        return true;

    else if (profile == BluetoothProfile.SAP) {

        BluetoothSap sap = new BluetoothSap(context, listener);

        return true;

    else if (profile == BluetoothProfile.PBAP_CLIENT) {

        BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener);

        return true;

    else if (profile == BluetoothProfile.MAP_CLIENT) {

        BluetoothMapClient mapClient = new BluetoothMapClient(context, listener);

        return true;

    else if (profile == BluetoothProfile.HID_DEVICE) {

        BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener);

        return true;

    else if (profile == BluetoothProfile.HEARING_AID) {

        BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener);

        return true;

    else {

        return false;

    }

frameworks/base/core/java/android/bluetooth/BluetoothA2dp.java

 /*package*/ BluetoothA2dp(Context context, ServiceListener l) {

    mContext = context;

    mServiceListener = l;

    mAdapter = BluetoothAdapter.getDefaultAdapter(); 

    IBluetoothManager mgr = mAdapter.getBluetoothManager();//1

    if (mgr != null) {

        try {

            mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);//2

        catch (RemoteException e) {

            Log.e(TAG, "", e);

        }

    }

 

    doBind();//3

}

1.从BluetoothAdapter类中获取到蓝牙管理服务对象

2.注册A2DP状态回调接口

3.绑定蓝牙A2DP Service

 

boolean doBind() {

    Intent intent = new Intent(IBluetoothA2dp.class.getName());  //1

    ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);

    intent.setComponent(comp);

    if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,

            mContext.getUser())) {

        Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);

        return false;

    }

    return true;

}

1.绑定A2dpService(位于packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/),实现与Bluetooth进程通信

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BluetoothKit是一款功能强大的Android蓝牙通信框架,支持经典蓝牙和低功耗蓝牙设备混合扫描,提供了一系列简单易用的接口用于低功耗蓝牙设备的连接,数据读写,通知等。 特点 一、支持经典蓝牙和BLE蓝牙混合扫描,支持自定义扫描策略  作为智能家居平台,接入的设备包括经典蓝牙和BLE,因此扫描设备时需要两者混合进行,而设备扫描场景不同,扫描策略也会不一样,因此需要支持扫描策略可配置。 二、充分解决了Android中BLE兼容性和稳定性问题  Android系统对蓝牙4.0支持得并不完善,有许多bug, BluetoothKit很好地解决了其中大部分已知的问题。  三、简单易用,接口简洁明了  BluetoothKit采用异步串行化策略处理所有设备操作,并支持任务超时及出错重试。  技术 一、实现了一个完整的跨进程异步任务队列,支持任务超时、出错重试及防御队列溢出 二、拦截并Hook系统层蓝牙Binder,实现对所有蓝牙设备通信的监控,当同时连接设备数过多时会自动断掉活跃度最低的设备 三、整个框架封装在一个service中,可灵活指定service所在进程。通过client与service通信,client可源于多个不同进程,因此适用于多进程架构的app 四、屏蔽了接口异步回调可能持有调用端Activity引用导致的内存泄露 五、利用动态代理自动将所有操作封闭在工作线程,所以整个框架无锁 使用 // 首先,需要按如下方式初始化BluetoothClient: BluetoothClient mClient = BluetoothClient.getInstance(context); // 扫描设备:支持经典蓝牙和BLE设备混合扫描,可自由定制扫描策略如下: SearchRequest request = new SearchRequest.Builder() .searchBluetoothLeDevice(3000, 3) .searchBluetoothClassicDevice(5000) .searchBluetoothLeDevice(2000) .build(); mClient.search(request, new SearchResponse() { @Override public void onSearchStarted() { } @Override public void onDeviceFounded(SearchResult device) { } @Override public void onSearchStopped() { } @Override public void onSearchCanceled() { } }); // 停止蓝牙扫描 mClient.stopSearch(); // BLE设备连接 mClient.connect(MAC, new BleConnectResponse() { @Override public void onResponse(int code, Bundle data) { if (code == REQUEST_SUCCESS) { } } }); // BLE设备断开连接 mClient.disconnect(MAC); // 读取BLE设备 mClient.read(MAC, serviceUUID, characterUUID, new BleReadResponse() { @Override public void onResponse(int code, byte[] data) { if (code == REQUEST_SUCCESS) { } } }); // 写BLE设备 mClient.write(MAC, serviceUUID, characterUUID, bytes, new BleWriteResponse() { @Override public void onResponse(int code) { if (code == REQUEST_SUCCESS) { } } }); // 打开设备通知 mClient.notify(MAC, serviceUUID, characterUUID, new BleNotifyResponse() { @Override public void onNotify(UUID service, UUID character, byte[] value) { } @Override public void onResponse(int code) { if (code == REQUEST_SUCCESS) { } } }); // 关闭设备通知 mClient.unnotify(MAC, serviceUUID, characterUUID, new BleUnnotifyResponse() { @Override public void onResponse(int code) { if (code == REQUEST_SUCCESS) { } } }); // 读取rssi mClient.readRssi(MAC, new BleReadRssiResponse() { @Override public void onResponse(int code, Integer rssi) { if (code == REQUEST_SUCCESS) { } } }); 标签:BluetoothKit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值