一文汇总开源鸿蒙蓝牙能力
liebian365 2025-01-02 17:42 36 浏览 0 评论
作者:王石
蓝牙功能是无线短距的重要能力,在工作、生活中有很多蓝牙设备,比如车载蓝牙设备,蓝牙耳机,蓝牙键盘。
1994 年由电信商爱立信发展出这个技术,最初蓝牙的设计是系统创建出一个 RS-232 数据线的无线通信技术替代版,能够链接多个设备并克服同步问题。
目前蓝牙技术由蓝牙技术联盟(SIG Special Interest Group)来负责维护其技术标准,IEEE 曾经将蓝牙技术标准化为 IEEE 802.15.1,但是这个标准已经不再继续使用。
接下来我们就深入分析下开源鸿蒙的蓝牙结构和各层作用及工作内容。
概述
在开源鸿蒙的源码里和系统功能相关的部分大多都放在 foundation 这个文件夹里,而通讯相关的部分则是在 communication 这个文件夹内。
我们本篇要分析的蓝牙功能就是在 foundation/communication/bluetooth 路径下。
具体目录结构如下:
.
├── bundle.json
├── frameworks //框架层
│ ├── inner
│ └── js
├── hisysevent.yaml
├── interfaces //接口层
│ ├── inner_api
│ └── kits
├── LICENSE
├── README.md
├── README_zh.md
├── sa_profile //系统能力配置
│ ├── 1130.xml
│ └── BUILD.gn
├── services //服务层
│ ├── bluetooth
│ └── bluetooth_lite
└── test 测试代码
├── example
├── fuzztest
├── moduletest
└── unittest
架构简析
根据目录结构和内部文件及编译框架总结架构如下:
接口层:对外提供 js 接口,采用 d.ts 定义,蓝牙文件夹内位置 interfaces/kits/js 具体存放路径在
interface/sdk-js/api/@ohos.bluetooth.d.ts
对内提供 c 接口,可以供 softbus,netmanager,audioframework 三个子系统调用,蓝牙文件夹内位置 interfaces/inner_api/include。
框架层:分两个子层,NAPI 框架实现层,蓝牙文件夹内位置
foundation/communication/bluetooth/frameworks/js/napi
实现所有 js 层代码接口适配并调用 innerapi 的实现;蓝牙接口实现层,使用 IPC 架构同蓝牙服务层通信,将从 NAPI 收到的命令,或者别的子系统收到的命令经由 IPC 架构发送给服务层,并注册服务层 observer,收听由服务层上报的事件。
服务层:分三个子层。
系统能力层,蓝牙文件夹内位置:
foundation/communication/bluetooth/services/bluetooth/server
实现蓝牙系统能力服务,接收从框架层经由 IPC 发送下来的命令,并收听蓝牙 service 传上来的消息并回传给蓝牙框架层。
蓝牙服务层,蓝牙文件夹内位置:
foundation/communication/bluetooth/services/bluetooth/service
实现不同蓝牙能力的 adapter(包括 classic_adapter 和 ble_adapter),通过调用蓝牙协议栈实现蓝牙业务的逻辑能力。
蓝牙协议栈,蓝牙文件夹内位置:
foundation/communication/bluetooth/services/bluetooth/stack
实现蓝牙协议包解析,打包以及蓝牙协议流程的处理,实现蓝牙 host,蓝牙 profile 以及蓝牙链路和 hci 接口,最后通过使用蓝牙硬件驱动收发蓝牙原始数据。
硬件驱动:预编译包,通过 dlopen 提供 hci 的底层接口,注册回调以及发送数据。
功能简析
①NAPI 功能?
HAP 应用层通过 @ohos.bluetooth.d.ts 引用调用蓝牙接口,蓝牙接口包括 bluetooth 接口,BLE 接口,profile 接口。
bluetooth 接口包括经典蓝牙接口,BLE 接口接口,和 profile 接口;目前支持的 profile 有 A2dpSourceProfile,HandsFreeAudioGatewayProfile,HidHostProfile 和 PanProfile。
NAPI 框架接口均通过 DECLARE_NAPI_FUNCTION,js 的回调也通过此接口经由传入回调函数指针实现。
NAPI 层通过调用蓝牙框架层的 BluetoothHost 实现功能,通过将 g_bluetoothHostObserver 注册到框架层内部实现来获得消息回调。
同时 NAPI 层提供 g_Observer 存储 js 层的回调函数,在收到框架层的回调后在 g_Observer 里查找对应的回调函数来实现应用通知;此对象因为是 map 结构体,所以一个应用只能注册一个并在应用内部自己处理。
②蓝牙框架功能
蓝牙框架提供 cadapter 接口和蓝牙框架具体实现(蓝牙 NAPI 层调用的 BluetoothHost 即在具体实现层)。
cadapter 实现 c 接口,通过 BluetoothHost 实现功能,其他外部模块均通过 cadapter 提供的 c 接口调用蓝牙能力。
蓝牙框架内部实现层提供接口一一对应 cadapter 和 NAPI 接口。
BluettoothHost 内部通过:
SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager()
接口得到 samgr,然后通过 BLUETOOTH_HOST_SYS_ABILITY_ID 标识获取蓝牙服务对象,然后通过蓝牙服务对象通过 IPC 接口调用蓝牙服务功能。
蓝牙框架内部提供 RegisterObserver 方式,允许其他层应用(比如软总线层通过调用 cadapter 接口 GapRegisterCallbacks 收听蓝牙的回调事件)收听蓝牙回调事件。
蓝牙框架因为是动态库实现,所以如果有多处依赖则会生成多份实例,如 NAPI 和软总线都依赖蓝牙框架库,所以在系统里会有两份实例同时若产生蓝牙通知也会有两个进程同时收到消息。
③蓝牙系统能力?
蓝牙系统能力通过继承 SystemAbility,BluetoothHostStub 两个类实现蓝牙服务能力并实现 IPC 进行通信。
IPC 通信部分的代码在蓝牙文件夹 foundation/communication/bluetooth/services/bluetooth/ipc 内,提供 proxy 和 stub 实现,即 btipc_static.a 静态库。
蓝牙系统能力可视作蓝牙服务进程,提供包括蓝牙状态机,蓝牙 adapter(classic,ble),蓝牙 profile 服务实例。
蓝牙系统配置在 foundation/communication/bluetooth/services/bluetooth/etc/init 目录内,此部分内容会在制作镜像包时打包到系统文件内去。
在蓝牙服务启动的时候会读取蓝牙配置(AdapterConfig::GetInstance()->Load(),ProfileConfig::GetInstance()->Load())并确定蓝牙的 snooplog(协议栈输出文件)。
蓝牙系统能力内部使用 Dispatcher 模型执行任务事务,在 Dispatcher 对象内部它通过线程加任务队列的方式处理多条任务命令,目前实现方法为但线程依次处理队列内的事务。
蓝牙系统能力层通过 permission_utils 提供应用权限保护能力,服务调用功能时首先调用 PermissionUtils::VerifyXXXBluetoothPermission(XXX包括,Use,Discover,Manage,Location)。
然后调用 AuthCenter 对应功能,最后调用 PermissionHelper 对应接口确认权限;在 AuthCenter 里内部定义了 g_permissionAlwaysGrant 全局变量,可以方便调试时拥有所有权限。
④蓝牙协议栈?
蓝牙协议栈通过 c 接口对蓝牙服务层提供接口;
蓝牙协议栈内部他提供任务队列方式处理蓝牙命令(GapRunTaskBlockProcess,GapRunTaskUnBlockProcess),分别对于蓝牙协议栈同步接口和异步接口。
蓝牙协议栈内部也有层级,对上的是 gap,中间是 btm,对下的是 hci,中间部分和其他蓝牙协议站定义的内容一致,如:att,avctp,avdtp,l2cap,rfcomm,sdp,smp。
HCI 层它通过 g_hdiLib 加载蓝牙驱动库 libbluetooth_hdi_adapter.so,并通过加载蓝牙驱动接口(HdiInit,HdiSendHciPacket,HdiClose)实现蓝牙数据发送,蓝牙数据接收(g_hdiCallacks)。
总结
蓝牙服务的结构也是所有开源鸿蒙的结构能力,大致流程均为:NAPI 框架,系统服务框架,IPC 框架,Observer 框架,原生 driver 框架(其实可以采用 HDF 框架)。
目前开源鸿蒙用的蓝牙协议站不是 android,bluez,btstack 这三种主流蓝牙协议栈,根据注释可得其参考《BLUETOOTH SPECIFICATION Version 5.0》实现。
目前官方最新的协议栈是 v5.3,参考链接如下:
https://www.bluetooth.com/specifications/specs/core-specification-5-3/
相关推荐
- python如何对字符串进行操作(python如何对字符串进行操作输出)
-
1.字符串的创建可通过直接赋值、构造或转义字符来创建字符串。#普通字符串s="Hello,World!"#多行字符串(使用三引号)multi_line_str='''Thisi...
- Excel表格中11个常用的字符串函数
-
今天和大家聊聊常用的字符串函数,在不同的条件下,如何选择字符串函数很关键。下面我为大家列举了11个关于字符串的函数公式。一、EXACT(两个字符串进行结果比较)比较两个字符串是否完全相同(这里是要区分...
- 详细介绍一下Python中如何对字符串进行操作?
-
在Python中,字符串做为一种常见的数据处理类型,几乎在每个应用程序中都会被用到。而作为Python中使用最广泛的数据类型Python也是提供了很多强大的方法来支持对于字符串的处理操作。下面我们就来...
- Java中你知道几种从字符串中找指定的字符的数量
-
遇到这样的问题,常规的思路估计就是遍历String,然后逐个对比。下面先看循环遍历循环遍历privatestaticintgetNum(StringoriginStr,Stringtarg...
- C语言strcspn函数详解:字符串的“扫雷探测器”
-
strcspn是C语言标准库中的一个函数,定义在头文件中。它用于计算从字符串的开始到首次出现任何属于指定字符集合的字符之间的字符数量。换句话说,strcspn计算的是主字符串中不包含指定字符集...
- 如何使用 Python 的 f-string 进行字符串格式化
-
Python中的字符串格式化曾经有点麻烦。必须在...
- java判断字符串中是否包含某个字符
-
1使用String类的contains()方法contains()方法用于判断字符串中是否包含指定的字符或字符串。语法如下:publicbooleancontains(CharSequence...
- Python基础:f-string不同数据类型的格式化选项,终极指南!
-
上一篇文章我们介绍了4种字符串格式化方法,其中最现代、最直观的方式是f-string,从Python3.6开始引入,而且时不时就增加一些超级优雅的小改进。今天,钢铁老豆想要继续给大家展开介绍不同数据...
- Excel查找指定字符串,返回相应的结果
-
通过下面的函数,可以实现查找指定字符串,若找到返回“有”,若找不到返回“无”。=IF(ISNUMBER(SEARCH("失业",G3)),"有","无")...
- 一个list中,有b.a.b.c.b.b.写个方法去掉所有b
-
importjava.util.ArrayList;importjava.util.List;publicclassRemoveBFromStringList{/**...
- 掌握Python f-string(掌握催眠能力之后的日常生活)
-
f-string,通常称为格式化字符串文本,是Python3.6中添加的一项强大功能,它提供了一种将表达式包含在字符串文本中的清晰实用的方法。,...
- 深入了解字符串:定义、转义字符和字符串下标
-
字符串是编程中常见的数据类型之一,用于表示文本信息。在绝大多数编程语言中,字符串都是由一系列字符组成的序列,可以包含字母、数字、符号以及空格等。字符串的定义:...
- 100个Java工具类之70:字符串处理工具类StringUtils
-
StringUtils是常用的工具类,提供大量处理字符串的静态方法。StringUtils主要特点...
- Shell中针对字符串的切片,截取,替换,删除,大小写操作
-
切片返回字符串变量var的长度...
- Sqlite - 常规函数 - RTRIM(sqlite命令行工具)
-
在SQLite中,RTRIM函数是一个用于处理字符串的函数,其主要作用是移除字符串右侧(尾部)的指定字符。如果不指定要移除的字符,默认会移除字符串右侧的空格字符。以下是对RTRIM函数的详细...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)