使用ScanSettings.SCAN_MODE_OPPORTUNISTIC时,应用程序扫描太频繁。

42

我在三星S8,Android 7.0上发现了一个问题(更新:这个问题也发生在Android 7.0上的三星S7和Nexus 5x上),经过几次测试后得出结论,该应用程序扫描得太频繁:

08-14 12:44:20.693 25329-25329/com.my.app D/BluetoothAdapter: startLeScan(): null
08-14 12:44:20.695 25329-25329/com.my.app D/BluetoothAdapter: STATE_ON
08-14 12:44:20.696 25329-25329/com.my.app D/BluetoothAdapter: STATE_ON
08-14 12:44:20.698 25329-25329/com.my.app D/BluetoothLeScanner: Start Scan
08-14 12:44:20.699 25329-25329/com.my.app D/BluetoothAdapter: STATE_ON
08-14 12:44:20.700 25329-25329/com.my.app D/BluetoothAdapter: STATE_ON
08-14 12:44:20.700 25329-25329/com.my.app D/BluetoothAdapter: STATE_ON
08-14 12:44:20.701 25329-25329/com.my.app D/BluetoothAdapter: STATE_ON
08-14 12:44:20.703 4079-4093/? D/BtGatt.GattService: registerClient() - UUID=dbaafee1-caf1-4482-9025-b712f000eeab
08-14 12:44:20.807 4079-4204/? D/BtGatt.GattService: onClientRegistered() - UUID=dbaafee1-caf1-4482-9025-b712f000eeab, clientIf=5, status=0
08-14 12:44:20.808 25329-25342/com.my.app D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5 mClientIf=0
08-14 12:44:20.809 4079-7185/? D/BtGatt.GattService: start scan with filters
08-14 12:44:20.811 4079-7185/? D/BtGatt.GattService: getScanSettings 
08-14 12:44:20.812 4079-7185/? D/BtGatt.GattService: Is it foreground application = true
08-14 12:44:20.812 4079-7185/? D/BtGatt.GattService: not a background application
08-14 12:44:20.817 4079-7185/? E/BtGatt.GattService: App 'com.my.app' is scanning too frequently

问题明显出现在那6个STATE_ON呼叫结果上,这是未记录的BLE行为变更的一部分,首次在DP4版本说明中提到:

我们从DP4开始改变了BLE扫描行为。我们将防止应用程序在30秒内启动和停止扫描超过5次。对于长时间运行的扫描,我们将把它们转换为机会式扫描。

我不理解的是,即使我设置了: ScanSettings.setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC),仍然存在在30秒内进行6次以上的扫描。

代码如下:

List<ScanFilter> filters = new ArrayList<>();
ScanSettings scanSettings = new ScanSettings.Builder()
    .setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC)
    .build();
bluetoothAdapter.getBluetoothLeScanner().startScan(filters, scanSettings, recoderScanCallback);
//events from the log happen before this log is printed
Log.i("test", " started!");
return recoderScanCallback.scanResultObservable().map((ScanResult record) -> {
    //never gets here
    Log.i("test", " result!");
});

RecorderScanCallback继承自ScanCallback。 由于我们的代码即将冻结并且我们使用lib的1.1.0版本,因此我们无法使用RxAndroidBle#rxBleClient.scanBleSettings(ScanSettings)。

为什么ScanSettings.setScanMode不会改变搜索结果?


似乎每30秒最多只能进行6次扫描的限制也适用于机会式扫描,至少通过检查https://android.googlesource.com/platform/packages/apps/Bluetooth/+/master/src/com/android/bluetooth/gatt/AppScanStats.java的源代码是这样。 - Emil
是的,我认为你是对的,但据我所知,在使用机会扫描时,我们只是 passively 听取系统变化而不是自己启动扫描,正如文档中所说(https://developer.android.com/reference/android/bluetooth/le/ScanSettings.html#SCAN_MODE_OPPORTUNISTIC)。那么为什么扫描会启动呢? - Margarita Litkevych
你有多频繁地调用bluetoothAdapter.getBluetoothLeScanner().startScan(filters, scanSettings, recoderScanCallback)方法? - Roberto Betancourt
1
@DigitalNinja 在测试期间没有运行其他扫描应用程序。唯一可能的其他应用程序可能是系统,但我仍然不同意这种行为与此有关。测试条件是:一个手机,一个蓝牙设备。房间里没有其他开启蓝牙的手机,也没有其他开启蓝牙的设备。在几次正确连接之后(少于5次,通常是2-3次),会出现这种行为。 - Margarita Litkevych
1
@DigitalNinja,如果您的应用程序不调用startScan,又如何依赖其他应用程序开始扫描呢?再次强调,在文档中:一种特殊的蓝牙LE扫描模式。使用此扫描模式的应用程序将被动地监听其他扫描结果,而不会启动BLE扫描本身 - Margarita Litkevych
显示剩余8条评论
1个回答

11
Android 7系统对于30秒内超过5次的扫描启动和停止进行了限制。不好的一面是,它不会返回错误信息,只会打印一个日志。应用程序认为扫描已经开始,但实际上它并没有在蓝牙堆栈中真正地启动。此外,为了防止滥用,它将长时间运行的扫描转换为机会性扫描。长时间扫描的持续时间为30分钟。
这些变化未被记录在文档中,但在这篇文章中提到:https://blog.classycode.com/undocumented-android-7-ble-behavior-changes-d1a9bd87d983

有没有可能在应用程序中捕获这个事件(第6次扫描开始或停止)?我只能想到手动计算扫描的开始/停止次数。 - jo3rn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接