Android 4.3:BLE:startLeScan() 的过滤行为
Posted
技术标签:
【中文标题】Android 4.3:BLE:startLeScan() 的过滤行为【英文标题】:Android 4.3: BLE: Filtering behaviour of startLeScan() 【发布时间】:2013-10-30 10:29:18 【问题描述】:我正在开发一个 BluetoothLE 传感器设备,为此我需要形成一对多的数据广播。根据规范,外围设备可能只有一个主设备,并且由于我设计的芯片和堆栈的限制,一个主设备只能有三个从设备。据我了解,android 无论如何都不能成为 BLE 从属设备,因此不能让我的设备作为主设备。
BT4 规范和制造商文档都谈到了另一种操作模式,称为广播模式。在广播模式下,永远不会建立连接,并且应用程序数据作为广告数据包的一部分进行传输。这完全符合我的需求,因为许多 Android/ios 手机可以同时扫描每个数据包。一个广告包以突发方式多次传输,所以我怀疑数据的接收大部分是可靠的。如果一个数据包到处丢失,这是可以容忍的。
有趣的是,我希望这些数据包能够携带实时传感器数据,这些数据以 10-20Hz 的速率更新。从我在网上找到的示例来看,这种模式下的 BLE 主要用于“iBeacon”类型的实现,它们在其中广播静态数据。我找不到有关如何在 Android 堆栈中过滤广告数据包的任何信息。它们可能是每个蓝牙硬件地址返回一个结果,也可能是地址和数据的唯一组合。第二个选项适用于此应用程序。如果开始和停止扫描会重置过滤器,我也可以做一些工作。
Android 文档没有提及扫描方法中设备过滤的工作原理。我已经能够在网上找到一篇试图解决同样问题的帖子,但回复未解决:BLE: Multiple discovery of the same peripheral during scan。在 iOS 中,我的同事告诉我,有一个参数可以传递给 scan 函数,使这成为可能。
我尝试从 Android 源代码中的 startLeScan() 调用追溯代码,但代码相当复杂,并且抽象的使用使得很难识别包含它的对象的实现。我得到的最远的是从 BluetoothManagerService 类方法 getBluetoothGatt() 返回的 IBluetoothGatt 对象。该对象接收开始扫描的请求。它在 github 上的当前修订版中围绕 line 790 of BluetoothManagerService.java 进行实例化。该对象是从消息的结果中投射出来的,所以我怀疑结果可能是电话/驱动程序特定的。能够进一步追踪它超出了我的专业知识。
我想解决的另一个问题是打开和关闭扫描的速度有多快。扫描是一项耗电量大的操作,但数据的广播将在相当精确的实时计时器上定期发生。因此,如果可以打开和关闭扫描,这将是一个很好的优化,这样广播和扫描是同步的,而扫描仪在其他 90% 以上的时间里会关闭。这可能需要进行实验测试。
我仍在进行可行性研究,看看这是否适用于我们的 Android 配件。我现在的手机还不能运行 4.3 版,所以我无法通过实验测试/破解它。
【问题讨论】:
不确定您的问题是什么。 Android 中的 BLE 扫描仪如何过滤结果?帖子的其余部分只是上下文。 【参考方案1】:到目前为止,Android 4.3 和 4.4 似乎一团糟:一些设备调用 onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) 在一次扫描中多次用于一台设备,有些则没有。无法像在 iOS 中那样配置过滤(请参阅 阿卡迪乌什·科尼奥尔)。所以,我现在开始列出一个列表,因为我无法向我的用户询问有关他们设备的此类问题。
不过,在“未过滤”的设备上,重新开始扫描也没有问题。所以,我现在在每台设备上重新开始扫描。
不过滤(不断调用 onLeScan())
Samsung Galaxy S4 with 4.2.2 using Samsung BLE sdk(我拥有该设备) Nexus 5 和 4.4(由 [vegarwe] 添加。设备会在扫描时连续提供附近设备的扫描记录) 带有 4.3 的三星 Galaxy S3(JSS15J.I9300XXUGMK6,我在该设备上进行测试) 带有 4.3 和 4.4.2 的三星 Galaxy S4 使用 Android SDK(由arnaud.b 添加,未提供构建) HTC One 4.4.2(由arnaud.b 添加,未提供内部版本号)过滤设备(适用于标准)
Nexus 4 和 4.3、4.4(我拥有该设备) Nexus 7 2013 4G 和 4.4.2(KOT49H,我在那个设备上测试) 带有 4.2.2 的三星 Galaxy S4 mini(我在此设备上进行测试) Motorola Moto X(由user1603602添加,未提供安卓版本信息) Motorola Moto G with 4.3(falcon_umts,我的测试设备) Sony Xperia Tablet Z Wifi 与 Android 4.3(构建 10.4.B.0.577,型号 SGP311,我的测试设备) 一加 5.0.1 和 5.1.1 (Cyanogen 12.1)未知过滤行为(请帮助将设备关联到某个组)
Nexus 7 2013(不同的行为被报告为 here。但我已经阅读了更多属于第一组的报告。) 其他 SAMSUNG、HTC、摩托罗拉、...、设备【讨论】:
似乎同一个 android 版本在所有设备上的行为并不相同。所以我想这是过滤设备的蓝牙驱动程序? (任何专家都可以确认?)此外,Nexus 5 使用 Snapdragon 800 (8974-AA) 芯片组,与三星 Galaxy S4 (GT-I9506) 的某些版本相同。 Galaxy S4还有其他版本:GT-I9505基于snapdragon 600(APQ8064T)和GT-I9500(exynos)Nexus 4,sony xperia tablet Z使用相同的芯片组(snapdragon s4 pro APQ8064)。 Moto X 和 Moto G 也基于 snapdragon s4 Nexus 7 2013 有不同的芯片组(全部?)基于 snapdrago 在我看来,这取决于可能取决于芯片组的 BLE 实现(软件)。例如,芯片制造商可以向手机制造商提供 BLE 实施。我还看到,持续扫描更常见于现有的参考 BLE 实现。这意味着 SGS4 是第一个实现 BLE 的设备,因此仍处于某种开发人员模式。毕竟,您不应该指望连续扫描模式。随着进一步的更新,它更有可能被删除。 不过滤(不断调用 onLeScan()) Galaxy S2 M250s(已测试) 关于使用新的 Android 5.0 BluetoothLeScanner 过滤设备的任何信息?它们会变成非过滤吗? 仅从我对 Nexus 4 和 5 的测试来看,我的实验发现它依赖于硬件,而不是依赖于操作系统。我的 Nexus 4 在 4.4 和 5.0 上都可以过滤,我的 Nexus 5 在 4.4 和 5.0 上都没有过滤——真是一团糟!【参考方案2】:蓝牙规范 (Core_v4.1.pdf) 第 2535-2536 页中关于重复广告报告的文本有些不清楚。但是,第 1258 页上的文字很清楚。它为 HCI_LE_Set_Scan_Enable 命令指定一个 Filter_Duplicates 参数。在 Android 版本 4.4 (Kitkat) 中,此参数为 0x00(禁用重复过滤)。
从 Android 4.4 (Kitkat) 版本开始,有一种简单的方法可以确定蓝牙芯片中是否进行了任何过滤。将手机设为开发者手机,进入开发者选项,勾选“启用蓝牙 HCI 监听日志”。然后关闭和打开蓝牙一次以使设置生效。从现在开始,应用处理器和蓝牙芯片之间的所有 HCI 数据包都将存储在手机上的一个文件中,该文件由 adb pull storage/emulated/legacy/btsnoop_hci.log 拉取。这不是文本文件,您需要来自http://www.fte.com/products/default.aspx 或wireshark 的程序来查看btsnoop_hci.log。对于wireshark,你需要一个相当新的版本,因为旧版本不支持BLE。我的经验是蓝牙芯片中从来没有任何过滤,即HCI事件“LE广告报告事件” ” 为每个 ADV_IND 发送 和 ADV_NONCONN_IND 蓝牙芯片接收到的。这适用于配备蓝牙芯片 Qualcomm/Atheros WCN 3680 和 Broadcom BCM 4339 的手机。
更正:btsnoop_hci.log 的路径可能因手机制造商而异。您可以通过 adb shell cat etc/bluetooth/bt_stack.conf 找到正确的路径 | grep BtSnoopFileName
【讨论】:
【参考方案3】:我正在使用 BLE 开发适用于 Android 4.3 (Nexus 4&7) 的应用程序,根据我的观察,如果没有 SCAN REQUEST 发送回外围设备,扫描会多次返回同一设备。
设备可以通过两种方式做广告:被动和主动。在被动模式下,外围设备只是广播它的所有数据,并且在发送周期性数据包后不监听。它只是发送,睡觉,发送,睡觉...... 在主动模式下,传感器也会做广告,但消息尽可能短。发送后,它会切换到听很短的时间。当扫描检测到短消息时,它会立即向外围设备发送 SCAN REQUEST 命令,并获得更多详细信息的响应。据我所知,Android 在一次扫描期间不会多次发送 SCAN REQUEST。
假设我们在范围内有 2 个设备。一个是 f.e. Nordic 的 nRF 温度传感器(被动广告)和其他可连接设备。我收到了以下扫描回复:
11-10 21:32:54.281: D/BluetoothAdapter(13468): startLeScan(): null
11-10 21:32:54.281: D/BluetoothAdapter(13468): onClientRegistered() - status=0 clientIf=4
11-10 21:32:54.321: D/BluetoothAdapter(13468): onScanResult() - Device=CD:61:1A:A8:BC:BE RSSI=-94
11-10 21:32:55.122: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-61
11-10 21:32:56.414: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-62
11-10 21:32:57.715: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-61
11-10 21:32:59.016: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:01.609: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:02.901: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:04.212: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-62
11-10 21:33:04.282: D/BluetoothAdapter(13468): stopLeScan()
如您所见,可连接的设备只出现了一次,而另一台出现了 7 次。
我想解决的另一个问题是打开和关闭扫描的速度有多快。扫描是一项耗电量大的操作,但数据的广播将在相当精确的实时计时器上定期发生。因此,如果可以打开和关闭扫描,这将是一个很好的优化,这样广播和扫描是同步的,而扫描仪在其他 90% 以上的时间里会关闭。这可能需要进行实验测试。
扫描频率取决于设备。此外,广告通常在 3 个频道上进行:37、38 和 39,以增加被发现的可能性。然而,这可能是从“活动”设备多次获取广告数据包的好主意。
【讨论】:
我已经在带有官方 4.3 更新的三星 S4 上测试了同一个案例,并且我多次收到这两款设备的更新。实际上,我从 61:1A:A8:BC:BE 获得的更新比后者更频繁。因此,总而言之,这取决于您使用的是什么设备。对开发人员来说一点也不好:/ 感谢您的评论,这是非常有用的信息。使用被动广告模式时,设备返回多个扫描结果是有趣且有用的。在这个应用程序中,理想情况下,我希望 Android 的行为类似于带有主动广告的被动扫描仪——这样我就可以让设备广播数据,并允许连接更改设置。 关于打开和关闭 Android Scanner:我在测试应用程序中成功打开和关闭了 startBleScan,并以 20Hz 的速率接收活动广告包。不幸的是,手机在打开和关闭时存在一些延迟,因此扫描过程最终在 80% 到 90% 的时间内处于活动状态。在较低的数据包速率下,这种方法作为“观察者”黑客可能是可行的。 @philips77:运行扫描仪的典型用例是能够向用户显示附近设备的列表,按信号最好的设备排序。在这种情况下,您真的希望设备的更新能够持续更新和排序列表(基于 RSSI)【参考方案4】:实际的蓝牙规格说:
不需要向主机发送重复的广告报告。 重复的广告报告是相同的广告报告 链路层处于扫描状态时的设备地址。这 广告数据可能会发生变化; 广告数据或扫描响应数据是 在确定重复广告时认为不重要 报告。
根据规范,这适用于扫描周期,这表明正确的解决方法是在每次收到广告时停止并重新开始扫描。
根据我在 BLE 方面的经验,在广告中发送可变数据似乎不是一个好主意。几乎所有事情都假设来自广告的数据不会改变。如果您想实际发送可变数据(例如温度计读数),那么最好实际连接到设备并通过特性来完成。它更可靠并且使用更少的功率。缺点是一次只能连接 8 台设备。
广告旨在检测设备的存在并识别它们。
【讨论】:
另请注意,Android 5.0 中有一个新的 BLE 扫描仪 API。我在装有 Android 5.0 的 Nexus 4 上收到所有广告。 (广告是无向的,不可连接的。) 你在这里是什么意思.."得到每一个广告",你得到连续(重复)数据包吗? 是的,在 Nexus 4 上,我收到了有关每个广告包的通知,即使它们是相同的。这是允许的行为,但也允许不这样做。规范令人讨厌。 这很有趣..你是否也在其他手机上交叉检查过?也像你建议“这是允许的行为,但也允许不这样做”,那么有没有办法知道广告已被外围设备停止! 无法检测广告何时停止 - 您只能稍等片刻,看看是否收到任何广告数据包。正如我所说,如果您想接收每一个广告,那么您必须在每次收到广告时停止并重新开始扫描。我还没有测试过。【参考方案5】:在 iOS 中,此标志名为 CBCentralManagerScanOptionAllowDuplicatesKey
。将其传递给扫描函数会导致通知每个广告数据包。我在 Android 中找不到类似的标志。
【讨论】:
这是真的!至少在 Android 4.4 中必须是类似的东西,以避免这些不同的行为,并成为符合标准的默认行为。以上是关于Android 4.3:BLE:startLeScan() 的过滤行为的主要内容,如果未能解决你的问题,请参考以下文章
Android BLE 4.3 onDescriptorWrite 在启用特征通知时返回状态 128
在 Android 4.3 中使用 Find Me Profile