蓝牙设备作为一种短距离无线连接的载体,由于其体积小、操作方便等优点,在耳机、车载和电脑键鼠等应用方面被越来越多的消费者所青睐,渐渐走入大众视野中。
作为蓝牙设备的使用者,我们的第一想法往往是这个蓝牙设备的名字是什么,这样才知道去连接哪个蓝牙设备,而一个蓝牙名字又对应着全球唯一的蓝牙地址,这其实才是蓝牙设备的关键。本篇文章我们就来聊聊蓝牙名字和地址的这些事。
- 蓝牙名字:蓝牙设备的名称,代表这个蓝牙设备,类似于我们的姓名
- 蓝牙地址:一组由48位(6字节)二进制表示的数据,是蓝牙设备的唯一标识。每一个蓝牙设备的地址都是不一致的(就好比世上没有两片相同的落叶),类似于我们的基因
所以市面上众多的蓝牙设备尽管名字是有可能相同的,但蓝牙地址基本上是不一致的。但也有另外,因为从上图可以知道LAP部分虽然有24位二进制来进行分配,但如果这家厂商的设备数量太多,超过了2的24次方(哈哈,概率极小),就会出现蓝牙地址重复的现象。
现在我们大概了解了蓝牙Name和Address的关系,那在安卓源码中我们一般是如何获取这两个值的呢?这就随我接着往下看。
获取这两个值需要分情况来讨论,因为蓝牙设备首次开机和重启开机的获取流程有差异,所以接下来分别作出分析。
1、首次开机(fastboot刷机完成后首次开机)
这种情况下,应用获取到蓝牙名字和地址一般是从蓝牙协议栈bluedroid获取来的,详情可以参照如下时序图来分析:
从上图可以明显得知,底层bluedroid上报的蓝牙名字和地址最终都会存储于全局变量Settings的xml文件中:/data/system/users/0/settings_secure.xml,索引名分别为 bluetooth_name 和 bluetooth_address。
第三方应用通过蓝牙适配器BluetoothAdapter对外提供的接口getName()和getAddress()就可以获取到存储于BluetoothManagerService中的蓝牙名字和地址。
但是这里还有如下几个问题需要解决:
问题1:首次开机,上述时序图中BluetoothManagerService.handleOnBootPhase()的处理中为什么是打开蓝牙的操作而不是主动去获取蓝牙的Name和Address ?
解答:系统开机会根据关机前的蓝牙状态来决定开机后是否自动打开蓝牙。
但是重新刷机后的首次开机会根据配置文件的值来决定是否默认打开蓝牙。
配置文件路径:frameworks/base/packages/SettingsProvider/res/values/defaults.xml
该文件中的 name="def_bluetooth_on" 的值会在刷机后的首次开机创建安卓数据库时写入Setting中的settings_global.xml文件中,索引值为 name="bluetooth_on"。
执行写入数据的处理函数为:frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java中的loadBooleanSetting(stmt,Settings.Global.BLUETOOTH_ON,R.bool.def_bluetooth_on)。
其他情况下的系统重启后,根据settings_global.xml文件中存储的关机前的蓝牙状态来做处理。
因此刷完系统首次开机后,程序会根据配置文件中的默认值来决定是否打开蓝牙,如果默认不打开蓝牙,则程序也会主动读取Name和Address,这个操作其实是bind蓝牙服务及初始化底层的蓝牙模块,等获取到这两个值后再执行unbind蓝牙服务的动作。
问题2:蓝牙名字的原始定义在哪?
解答:上面时序图中获取到的蓝牙名字也只是从蓝牙协议栈的内存里获取到的值,那这个值是从哪儿来的呢?
分析协议栈的代码,有这几个地方可以获取到Name
- 步骤A:cfg2prop()->btif_config_get_str()查找/data/misc/bluedroid/bt_config.conf文件中[Adapter]是否包含Name,该文件是协议栈初始化时创建的,保存相关变量
- 步骤B:如果步骤A没有获取到Name,则从btif_dm_get_adapter_property()->btif_get_default_local_name()中获取到宏定义的变量BTM_DEF_LOCAL_NAME的值作为蓝牙名字,该宏定义的路径为:device\generic\common\bluetooth\bdroid_buildcfg.h
所以获取蓝牙名字的流程图大概如下所示:
问题3:蓝牙地址从哪儿获取的?
解答:类似于蓝牙名字是从协议栈相关的配置文件中获取的,蓝牙地址则是从蓝牙芯片获取上来的。
btif_storage_get_adapter_property( )函数中通过接口 controller_get_interface()->get_address()获取地址值。
而controller.c中的address赋值于:
HCI交互为:
第三方应用需要获取蓝牙地址的话,该应用除了"LOCAL_MAC_ADDRESS"的权限外,还需具备系统权限,否则获取到的地址为默认的错误值:"02:00:00:00:00:00"
2、重启开机
从以上分析可以知道,系统重启前会将蓝牙状态、名字和地址等参数存储于Setting的xml文件中,所以系统重启后,会首先从这些xml文件中读取参数,进而BluetoothManagerService在初始化时就已经获取了这些参数值。
现在我们已经分析完成了两种场景下的蓝牙名字和地址的获取流程,至此安卓系统中的蓝牙Name和Adress就会一直存储于Settings的xml文件中。
使用蓝牙设备过程中,蓝牙地址一经固件写入基本上是不可更改的。但蓝牙名字却是可以修改的,第三方应用使用BluetoothAdapter对外提供的接口setName()将新名字写入蓝牙协议栈,存储于bt_config.conf中,这样保证后续主动读取名字时先读取出更改后的名字。同时协议栈也会将最新的Name上报给服务层,通过广播通知BluetoothManagerService更改Settings中的Name值。
好了,本篇的蓝牙名字和地址的分析就到这里,感兴趣的小伙伴欢迎私信留言一起讨论。
,