androidbluetooth-lowenergyaltbeaconandroid-8.0-oreo

How does BLE scanning work for altbeacon library on Oreo?


Before Android L Android Altbeacon library used background running services to scan BLE beacons. Default scan times are 1.1 seconds in a loop in the foreground and 10 seconds every 5 mins in the background. Also for background tasks alarm manager is used to wakeup the app.

I was looking at how similar setup works in Android Oreo given that long-running background services are not allowed. I was going through http://www.davidgyoungtech.com/2017/08/07/beacon-detection-with-android-8 and it did clear something but I am still not completely clear on how scan works with the combination of bluetooth scanning API and job scheduler.

So how is low power scan is used in combination of job scheduler based periodic scheduling to monitor and range beacons? If someone could provide an example that would be great.

To be a bit more specific -

  1. when would we go for passive new beacon detection vrs normal background scans?
  2. Why is passive scan work only for new detections? Why can't we run this in a loop? And why is it run only between job scheduler scans?
  3. Lets us say I have set scan period of 10 seconds and scan interval of 2 minutes. What techniques are used at what intervals to scan the beacons?
  4. If job scheduler can schedule jobs with frequency more than 15 mins and it can run with max 10 mins time can we set scan interval to 10 mins and scan interval to 5 mins? That we would lose only 5 mins worth of scan due to OS limitation? Also, can we do a passive scan in these 5 mins? So we do not have any span of time when beacons are not scanned?

Solution

  • It is critical to understand how low power scans work at a low level:

    A low power scan relies on offloading the Bluetooth LE pattern matching to a hardware filter on the Bluetooth chip. If it is matched by an incoming packet, the chip notifies the operating system, which sends an intent to the app that wakes it up to process the packet.

    The above relies on a combination on of filtered scans delivered by intents (a new API in Android 8).

    When a scheduled scan job ends with the Android Beacon Library, this intent based delivery is set up to be handled by the operating system and Bluetooth chip. The end result is that if a new beacon is detected, it will be handled by a broadcasted receiver very quickly. This can send a monitoring callback to the app within a few seconds instead of waiting 15 minutes for the next scheduled job.

    This is all designed to work when the filter will not match a Bluetooth device that is already nearby. If one is already nearby, the Intent would be sent within 100ms or so, which is a very CPU inefficient way of getting constant updates, which defeats the whole point of low power APIs, and would cause the app to be running constantly and eligible for termination by Android 8.

    The filter used matches any beacon. This is done to conserve filters as they are a limited hardware resource. For this reason, these scanning APIs are not used if a beacon is known to be present already, because it would immediately match a packet and defeat the purpose of the technique. Bottom line: if a scan job ends with a beacon visible, the low power scanning is not done.

    You cannot set a scheduled job to execute any more often than 15 minutes. This is an operating system restriction. A 10 minute between scan period would work, but the library only delivers scan results at the end of the cycle, so this probably isn't lot helpful. It would be possible to modify the library to simply scan for the max 10 minutes on each scan job, but currently it does not do this, and as you note it would leave 5 minutes uncovered.

    If you really want to do constant BLE scanning in the background on Android 8+, the OS-permitted way to do so is with a foreground service that displays an icon so the user knows it is running. Be careful about doing this in consumer apps, though, as battery drain will be very significant and users will probably uninstall the app after blaming it for dead batteries. For special use cases, however, this may be acceptable.