41

I noticed an issue on Samsung S8, Android 7.0 (upd. This also happens on Android 7.0: Samsung S7, Nexus 5x) which tells (after couple of tests) that app is scanning too frequently:

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

The problem definitely lies in those 6 STATE_ON call results, it's the part of undocumented BLE behavior change, first mentioned in DP4 release notes:

We’ve changed the BLE Scanning behavior starting in DP4. We’ll prevent applications from starting and stopping scans more than 5 times in 30 seconds. For long running scans, we’ll convert them into opportunistic scans.

What I don't get are the 6 scans in less than 30 seconds even if I set: ScanSettings.setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC).

The code is:

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 is derived from ScanCallback. We cannot use RxAndroidBle#rxBleClient.scanBleSettings(ScanSettings) because our code is about to freeze and we use 1.1.0 version of the lib.

Why does ScanSettings.setScanMode not alter results of the search?

Karolis Koncevičius
  • 9,417
  • 9
  • 56
  • 89
Margarita Litkevych
  • 2,086
  • 20
  • 28
  • It seems the restrictions of max 6 scans per 30 seconds applies to opportunistic scans as well, at least by checking the source code at https://android.googlesource.com/platform/packages/apps/Bluetooth/+/master/src/com/android/bluetooth/gatt/AppScanStats.java. – Emil Aug 15 '17 at 11:56
  • Yes, I think you're right, but as far as I understand while using opportunistic scan we only listen passively to system changes without starting scan ourselves as said in documentation (https://developer.android.com/reference/android/bluetooth/le/ScanSettings.html#SCAN_MODE_OPPORTUNISTIC). Why then the scan is started? – Margarita Litkevych Aug 15 '17 at 12:58
  • How often are you calling bluetoothAdapter.getBluetoothLeScanner().startScan(filters, scanSettings, recoderScanCallback); ? – Roberto Betancourt Aug 28 '17 at 13:45
  • Elaborating on my previous question; The Scan Mode is not what triggers the limit but rather, how ofter you start a scanning operation with startScan(). Are you frequently starting scanning operations? – Roberto Betancourt Aug 28 '17 at 13:54
  • How often: on each onResume and then, after 90s user can trigger again. So I'd say not often, only on demand. For the testing purposes, I only started it once on onResume, waited 90s, and then started again. Results were always the same. – Margarita Litkevych Aug 28 '17 at 15:58
  • Problem is that, if I post a log before the line that starts scan and after it, these logs are posted only once. – Margarita Litkevych Aug 28 '17 at 16:01
  • Try to add logging everywhere you call startscan, with the current datetime, and see if it is actually calling it too often. – Hack5 May 21 '18 at 15:44
  • I think there's a misunderstanding here with `SCAN_MODE_OPPORTUNISTIC`. This scan mode means that you will get scan results from *any* *application* that is running a BLE scan, not just yours. Some other app or apps could be scanning, then you call `startScan` and boom you've have scanned "too frequently". – DigitalNinja Jun 06 '18 at 23:44
  • @DigitalNinja according to the [doc](https://developer.android.com/reference/android/bluetooth/le/ScanSettings.html#SCAN_MODE_OPPORTUNISTIC), with ```SCAN_MODE_OPPORTUNISTIC``` app does not start a scan, it only listens to the others' results. So it could not possibly be an issue of the 6 scan starts. – Margarita Litkevych Jun 11 '18 at 16:31
  • Again you're misunderstanding my comment, your app might only call `startScan` *one* time (you are calling `startScan` in your code above), but that could take it over the scan limit, because another app or apps have also called `startScan` *x* number of times within the same time period. – DigitalNinja Jun 11 '18 at 19:42
  • How do you think it "listens to others' results"? Because those apps have called `startScan`. If you are going to rely on other apps starting a scan in order to discover your target device, then you shouldn't be calling `startScan` in your app - which would eliminate an additional scan that could cross the scan threshold within the 30 second window. – DigitalNinja Jun 11 '18 at 19:56
  • 1
    @DigitalNinja there were no other scanning apps running during the test. The only other app could be system, but I still don't agree that this is the case with this behaviour. Test conditions were: one phone, one bt device. No other phones with switched on bt in the room, no other devices with switched on bt in the room. After several correct connections (less than 5, usually 2-3), happens this behaviour. – Margarita Litkevych Jun 12 '18 at 13:39
  • 1
    @DigitalNinja and how are you going "to rely on other apps starting a scan" without calling ```startScan``` in your app? Again, in the docs (emphasis mine): A special Bluetooth LE scan mode. Applications using this scan mode will **passively** listen for other scan results **without starting BLE scans themselves.** – Margarita Litkevych Jun 12 '18 at 13:41

1 Answers1

10

Android 7 prevents scan start-stops more than 5 times in 30 seconds. The bad side is, it doesn't return an error, instead just prints a log. The app thinks the scan is started but it's not actually started back at the ble stack. Also it converts long running scans to opportunistic scan with an intent of preventing abusive apps. The duration is 30 minutes for a long running scan.

These changes are undocumented, mentioned in this post: https://blog.classycode.com/undocumented-android-7-ble-behavior-changes-d1a9bd87d983

Safa Kadir
  • 475
  • 1
  • 5
  • 18
  • any possibility to catch this event (6th scan start or stop) within the app? I can only come up with manually counting the scan starts/stops. – jo3rn May 14 '19 at 09:37