I am trying to perform BLE scans in a foreground service (Android 12) after some start scan end stop scan I receive the error SCAN_FAILED_APPLICATION_REGISTRATION_FAILED, I cannot figure out what is the reason of the error.
I do startScan and stopScan in sequence (the scan is a long-running scan)
The app target SDK 32 so I have the new Bluetooth permissions.
This is the complete scenario:
I open the app and I start the foreground service
I close the application (the foreground service is still running)
The foreground service scan and connect to my device and then I stop scanning
I turn off my BLE device and the foreground service start to scan again
I turn on my ble device and the foreground service detect it and connect to it.
Repeat step 4 and suddenly the error SCAN_FAILED_APPLICATION_REGISTRATION_FAILED show.
I also notice this error in the logcat App 'com.sample.xxx' is scanning too much clientif (I look into AOSP source code and seems that this string is specific of Xiaomi ROM)
https://github.com/appersiano/TestingBackgroundConnection
P.S. Tested on Xiaomi Mi11 Lite 5g
How can I solve?
you should not scan more than 5 times in 30s.
GattService:
This constant defines the time window an app can scan multiple times.
Any single app can scan up to |NUM_SCAN_DURATIONS_KEPT| times during
this window.
Once they reach this limit, they must wait until their earliest recorded scan exits this window.
static final int NUM_SCAN_DURATIONS_KEPT = 5;
static final long EXCESSIVE_SCANNING_PERIOD_MS = 30 * 1000;
Related
I use android phone to detect a beacon using startScan method, the interval time of beacon adversing is 800ms, but I got the beacon data from callback of startScan every 3~10 seconds. My expectation is I can get the data every 1 second.
Below is my codes. So is there any other ways to get my expectation. Or someone can explain why the interval time is not the same as the adversing time ?
ScanSettings.Builder builder = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
// scan filters has been set the right value.
bluetoothLeScanner.startScan(scanFilters, builder.build(), scanCallback);
Nothing about the code shown is a problem. I can confirm your expectation is met with equivalent code in other apps on other devices. This suggests a problem with :
Your BLE device not advertising as often as you expect
Your Android phone (possible but unlikely)
Some other aspect of your code that you did not show in your question.
Is you BLE device a beacon? If so, I suggest:
Install BeaconScope on the same phone, scan for your beacon, then check the PPS rating (Packets Per Second -- scan for at least 30 seconds until the measurement stabilizes). If you see a value of 0.1-0.3 then the problem is NOT with your code and must be (1) or (2). If you see a much higher PPS value, the problem is with some other aspect of your code not shown.
Use a second Android phone with BeaconScope as a transmitter and transmit a beacon at the 10 Hz default rate. Does your app get a packet every 100-200ms? If so, you have confirmed the problem is with your BLE device not transmitting as much as you expect.
If your BLE device is not a beacon you can at least perform the second test.
It's recommended to use 'SCAN_MODE_LOW_LATENCY' mode only hen the application is running in the foreground.
Incase you are in background, you can run a sticky foreground service and set a periodic frequency of 1 sec for your service.
Also scanning Ble for every 1 sec might be extremely heavy for the app.
Good day.
I would like to know if the bluetooth scanning is unavailable now (locked by doze mode?).
Now i check it by this method:
fun isInDozeMode(context: Context) : Boolean {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && powerManager.isDeviceIdleMode
}
But this method returns true even if i receive bluetooth (iBeacon) event just now.
Bluetooth is not directly affected by Doze mode:
Doze does not affect the ability to do bluetooth scans or run Handler-based timers, but it does affect the ability to use the Android AlarmManager system, which some beacon-based systems use to schedule bluetooth scans. For apps based on the Android Beacon Library, the disabling of Alarms does not cause problems in scanning for beacons because it only uses Alarms as a backup should Handler-based timers fail. Tests on a Nexus 9 running the third preview release of Android M (build number MPA44l) show that beacon detection continues normally under Doze.
See my blog post here. While that blog post was written for Android 6.0, subsequent doze changes added in 7.0 also do not affect Bluetooth scanning. See here.
Detect when the app enters/exits idle mode due to Doze
The OS will send a DEVICE_IDLE_MODE_CHANGED broadcast so we can track when the app has entered or exited idle mode.
Note: This broadcast will be sent when the device occasionally starts or ends the 10 minute idle maintenance window.
See: https://developer.android.com/reference/android/os/PowerManager.html#ACTION_DEVICE_IDLE_MODE_CHANGED)
I have an Asus P00A tablet (Android 7.0, API24) on which the BLE stops after some hours. (This affects any BLE app, not just my app using Android Beacon Library). Apps start working again if I manually switch off BLE then switch it back on.
The BluetoothMedic auto-fix system did not work for my tablet. It runs every 15 minutes but does not find a fault and so does not "power cycle" the Bluetooth. However, I hacked the BluetoothMedic class, adding this:
public void cycleBluetooth(Context context) {...}
and attached this to a button. I find this will restore BLE functionality. So I wondered what would happen if I unconditionally reset the BLE every 15 minutes. I added:
public static final int ALWAYS_RESET = 4;
and then call medic.enablePeriodicTests(context, BluetoothMedic.ALWAYS_RESET);
and add code inside BluetoothTestJob.onStartJob() which then calls BluetoothMedic.cycleBluetooth(). This behaves as expected and so far my app has run perfectly for 18 hours.
I am interested in any advice, such as:
1 Are there any tests other than the two in BluetoothMedic that I can run to detect that my tablet's Bluetooth has stopped? (I am happy to experiment).
2 Any comments on the hack I describe above? Should it be OK to unconditionally reset the Bluetooth every 15 minutes?
3 If the Bluetooth is reset ("power cycled") then is the rest of the Android Bluetooth Library OK with this? That is, will it carry on with monitoring and ranging that has been previously set up, or does the application code need to set take any action to get things going again? Note that this would apply to resets by the existing enablePowerCycleOnFailures() code as well as my ALWAYS_RESET hack above. (Maybe there are some crashes that could happen if the power cycling came at the wrong time?).
4 Could I suggest adding a callback so the application can learn if the Bluetooth has been cycled? Perhaps as a parameter to enablePowerCycleOnFailures()
5 I understand that background activities can be stopped by the OS, especially with Android 8. Would this also affect the regular 15 minute tests set up by enablePeriodicTests()?
The Android Beacon LIbrary's BluetoothMedic, as currently built, relies on the operating system's error code returned by a scan failure (or an advertising failure) to decide if the bluetooth stack is in a bad state warranting a power cycle.
For scans, if the onScanFailed callback is called with an error code of SCAN_FAILED_APPLICATION_REGISTRATION_FAILED which has the value of 2, the module considers it worthy of a power cycle..
For advertisements, if the onStartFailed callback is called with an error code of ADVERTISE_FAILED_INTERNAL_ERROR which has a value of 4, the module considers it worth of a power cycle..
These values were determined via experimentation, witnessing that on some devices, once an error callback is called with these values, bluetooth on the device would not work again without turning it off and back on. You can see the discussion of this in this thread.
You may want to see if there are other error codes on the Asus P00A that indicate a problem worthy of cycling bluetooth. To do this, wait for a failure, and see if attempts to start scanning call the onScanFailed callback with a distinct error code. If such error codes exist, this would be a better solution than cycling power to bluetooth regularly, as cycling power to bluetooth does break BLE GATT connections and the operation of bluetooth classic functions like speakers. The Android Beacon Library itself recovers from these power cycles just fine, although it will obviously not detect beacons until bluetooth is back on.
Because the BluetoothMedic uses the Android Job Scheduler for periodic tests, it is not affected by background limitations on Android 8+.
If you are interested in augmenting these functions in the library, please feel free to open an issue in the Github repo, and issue a Pull Request if you have code to share.
I am runnning an app or service with a active Bluetooth LE scanner and showing scan results on Log console. If I lock the phone in a table and not touching anymore. After a time it stops, and it doesn't give me more scan results.
If I press power button and the screen wake up it gives me more scan results. If i lock again the screen or wait to lock automatically it stops and not give me more scan results.
I test with service and an app that give me more results by Log and see the app is running but scanner LE stops and no give me more results while the screen is lock.
I have the app in "no optimized battery" for doze mode. I test forcing by command introducing the phone en doze mode and work fine it give me scan results.
In my Nexus 5 with Android 7.1.1 pass when running APP and lock the screen and not touch anymore the phone. The time is 30 minutes. The phone is in a table alone, only connected with microusb to see the log in android studio.
In other Moto G2 with android 7.1 pass exactly but the time is between 20 minutes and 40 minutes, it is more aleatory. The phone is in a table alone, only connected with microusb to see the log in android studio.
For have running well again, I need to force close the app manually and restart, otherwise only works when screen is active and no give me more results when screen is locked.
This is used for beacon results, first I use Android Beacon Library for this purpose and the result was the same.
I think it is a problem of android bluetooth component, because I have the same result with the Android Beacon Library or if I implement my own BLE Scanner, but I don't know how to solve this.
Are any form to use Bluetooth Scanner LE always running in Android when the phone is much time in lock state??
Thanks in advance.
Best regards.
Android 7.0 introduced a BLE scan timeout, where any scan running for 30 minutes or more is effectively stopped automatically and only resumed "opportunistically" which essentially means that if another process does a scan, it can get the results as well.
You can see this by setting up code to start a Bluetooth LE scan and leave it running indefinitely. After exactly 30 minutes, the scan will stop, and you will see entries like this in LogCat:
06-11 19:00:22.848 5123 5147 D BtGatt.ScanManager: clientIf set to scan opportunisticly: 6
06-11 19:00:22.848 5123 5147 D BtGatt.ScanManager: configureRegularScanParams() - queue=1
06-11 19:00:22.848 5123 5147 D BtGatt.ScanManager: configureRegularScanParams() - ScanSetting Scan mode=-1 mLastConfiguredScanSetting=2
06-11 19:00:22.848 5123 5147 D BtGatt.ScanManager: configureRegularScanParams() - queue emtpy, scan stopped
06-11 19:00:22.849 5123 5147 D BtGatt.ScanManager: stop scan
You can see the code that does this in the AOSP source here:
https://android.googlesource.com/platform/packages/apps/Bluetooth/+/android-7.0.0_r1/src/com/android/bluetooth/gatt/ScanManager.java#72
A workaround for this is to not keep scans going that long. You can simply stop them and restart them periodically.
We are making an app that uses BLE advertisements to create first a list of our industrial devices. Then of course something else happens but this is not relevant for the question. What is important is that we need to receive BLE advertisements continuously.
There is a service-like object that starts scan ble, waits about 2 seconds then stops it.
After 500 milliseconds it starts again.
This continues endless.
Here below the code snippet to start the scan, for completeness, just standard code, as one can see:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
bluetoothLeScanner.startScan(null, new ScanSettings.Builder().
setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build(), bleScannerCallback);
ok = true;
} else {
ok = mBluetoothAdapter.startLeScan(bleScannerCallbackPreLollipop);
}
return ok;
the bleScannerCallback implements the callback to receive the onScanResult().
What I'm experiencing right now is:
with some device, for example Samsung S6 with Android 5.1.1, within each scan cycle all devices in the proximity are received, i.e. onScanResult() runs with all BLE advertisements.
With some other device, like Tablet Nexus 9 with Android 7.0, everything runs fine for about 20 seconds, then for about 17/18 seconds NO advertisement is delivered through onScanResult(), then again ok for about 20 seconds, then again a break for about 17/18 seconds.
This process repeats infinitely, even with some regularity, it does not even seem random...
Is this a known issue?
It seems to appear specially with Android >= 6, our Samsung S6 with Android 5.1.1 runs all the times perfectly.
Obviously all the required Android permissions are in place, elsewhere it would not even run once.
It seems to me more a "feature" on the Android device to save some battery, unfortunately we need to scan continuously, at least in some condition, not really 24/7 but even not with about 20 seconds break every 20 seconds.
In the case this is the way it shall go in the future, does anyone know any other solution that allows to scan BLE devices continuously? Independently on the Android version...anyway the newer versions like >= 6.