Solution 1 :
The Bluetooth chips used by Android devices have a limited number of BLE advertisements they can have active at the same time — it’s a hardware limitation. This is a global resource, so it is possible that other apps may be using some of the advertiser slots, too. Newer devices tend to have more advertising slots. My Pixel 3a has over 10. But an older Huawei P9 Lite only has two.
You need to do a few things:
- Call
advertiser.stopAdvertising(advertiseCallback)
to turn off your last advertisement before starting a new one, unless you really do want to have more than one running at a time. - Track multiple instances of advertiseCallback if you are going to have more than one advertiser going at a time.
- Implement the methods in the advertiseCallback to catch errors. If an advertiser fails to start because you have run out of limited resources, you can discard the advertiseCallback, as there is no need to stop it in the future.
- Design your app so it behaves appropriately if you have run out of available advertising slots.
Problem :
I’m using Samsung Galaxy S6 with Nougat. When I try to use advertising I get a few success callbacks but then it goes into a loop where I get ADVERTISE_FAILED_TOO_MANY_ADVERTISERS
or ADVERTISE_FAILED_ALREADY_STARTED
and even ADVERTISE_FAILED_INTERNAL_ERROR
. I noticed in my logs that it create a new instance of AdvertiseManager
but it limits at 4 and then it gets stuck with the failed callbacks. I try to disable the Bluetooth and then enable it, once in a while. It seems though it has no effect.
these are the logs: (once it reaches 4, it starts to fail constantly)
2020-06-08 11:00:18.125 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 0
2020-06-08 11:04:18.995 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 1
2020-06-08 11:08:19.988 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 2
2020-06-08 11:09:20.275 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 3
2020-06-08 11:13:21.082 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
2020-06-08 11:15:21.597 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
2020-06-08 11:18:22.089 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
2020-06-08 11:19:22.283 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
2020-06-08 11:20:22.634 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
2020-06-08 11:23:23.173 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
2020-06-08 11:24:23.463 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
2020-06-08 11:25:23.794 22871-22935/? D/BtGatt.AdvertiseManager: number of adv instance running = 4
This is how I start advertising:
public void startAdvertise(String serviceUUID) {
if(advertisingCounter == 0 && !bluetoothAdapter.isEnabled())
{
bluetoothAdapter.enable();
Log.e(TAG, "eddie startAdvertise: turning on bluetooth"); // TODO: remove
}
if(advertisingCounter == 3)
{
bluetoothAdapter.disable();
advertisingCounter = 0;
Log.e(TAG, "eddie startAdvertise: turning off bluetooth"); // TODO: remove
return;
}
if(bluetoothAdapter.isEnabled()) {
Log.e(TAG, "eddie startAdvertise: " + advertisingCounter); // TODO: remove
advertisingCounter ++;
if(advertiser == null)
advertiser = bluetoothAdapter.getBluetoothLeAdvertiser(); // if we turned the bluetooth on while the service is running
Config config = Config.getInstance(mContext);
ParcelUuid pUuid = new ParcelUuid(UUID.fromString(serviceUUID));
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
dataBuilder.addServiceUuid(pUuid);
dataBuilder.setIncludeDeviceName(false);
dataBuilder.setIncludeTxPowerLevel(true);
int currentTime = (int) (System.currentTimeMillis() / 1000);
byte[] key = CryptoManager.getInstance(mContext).mySelf.generateEphemeralId(currentTime, BLEScannerManager.sGeoHash);
dataBuilder.addServiceData(pUuid, key);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(config.getAdvertiseMode());
settingsBuilder.setTimeout((int) config.getAdvertiseDuration());
settingsBuilder.setTxPowerLevel(config.getAdvertiseTXPowerLevel());
settingsBuilder.setConnectable(false);
if(advertiser != null)
advertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), advertiseCallback);
}
}
Has anyone faced anything similar?