9

Context

I am building an Android app targeting 5.0+ that uses BLE to connect to multiple peripherals. Each of these peripherals has many (~10) characteristics. Ideally, I would like to subscribe to notifications of changes for every single one of these characteristics.

However, my understanding from reading around is that Android's Bluetooth implementations enforce a hard limit on the number of simultaneous notifications that can be active. This question identifies where the limit is defined within the Android Bluetooth implementation, and also notes how the limit has changed over time:

Max concurrent active notifications (BTA_GATTC_NOTIF_REG_MAX):

  • 4 on Android 4.3
  • 7 on Android 4.4
  • 15 on Android 5.0+

These numbers are confirmed by Dave Smith in this video where it is also suggested that:

  • these limits are global to the device (i.e. if some other app is subscribed to 2 notifications, the number available to my app is reduced by 2);
  • these limits should not vary based on anything other than Android OS level (i.e. they should be independent of manufacturer, actual hardware capabilities, etc.)

Problem

In testing on 5.0+ devices, however, I have found that I am apparently able to successfully subscribe to more than 15 notifications. So far I have observed this on:

  • Pixel XL running 7.1.1
  • Galaxy S6 running 6.0.1
  • Nexus 5 running 5.X

These notification subscriptions are successful by two measures:

  1. The GATT operation status is a GATT_SUCCESS;
  2. The app is able to receive notifications on characteristic changes from all target characteristics.

This is mixed news. On the one hand, more "real" notifications ==> less manual polling ==> better user experience. On the other hand, being unable to create conditions that cause "real" notification setup to fail means I can't easily write or test the manual fallback code that will surely(?) be required once this app is released to real users.

Questions

  • Is this limit-ignoring behavior expected? (I have not been able to find it described elsewhere.)
  • Are there any devices known to max out at exactly 15 notifications that I can use to test the unhappy path?
Community
  • 1
  • 1
stkent
  • 19,772
  • 14
  • 85
  • 111

1 Answers1

12

The APIs are quite badly designed. Just the fact that this implementation uses a fixed size array rather than a dynamic array is probably a legacy from when the library was written in C.

The internal C++ library actually returns an error when it fails to allocate a notification entry. Unfortunately that error is only logged and is not propagated to the Java layer of the consuming application (source). This means that developers have no way to determine (in code) when they hit the limit.

Anyway, the BTA_GATTC_NOTIF_REG_MAX limit is per BluetoothGatt object, so if another app is connected it should not interfere with your notification registrations. You can even have two BluetoothGatt objects in the same app connecting to the same device, and that way get double as many notification registration slots.

The max number of slots is defined here. It's incorrect that OS level is the only thing that defines this value, as manufacturers are free to change this value. For example I know that Samsung has in some of their devices increased the maximum number of connections (that is otherwise hardcoded to 7), so they might also have increased this value.

I can't explain how you succeeded in subscribing to more than 15 notifications on the Google phones. Did you configure more than 15 notifications on a single device or over many devices?

stkent
  • 19,772
  • 14
  • 85
  • 111
Emil
  • 16,784
  • 2
  • 41
  • 52
  • Thanks, great answer with a ton of useful information! In particular, I believe the assertion "the `BTA_GATTC_NOTIF_REG_MAX` limit is per `BluetoothGatt` object" explains why I was confused about not hitting said limit in practice - I previously thought the limit applied to all `BluetoothGatt` objects _combined_, rather than to each `BluetoothGatt` object individually. – stkent Mar 14 '17 at 13:40
  • Per Dave Smith: ["The code isn’t the easiest to interpret, but the limit is applied per “client interface”.](https://twitter.com/devunwired/status/841489232136925186) [It’s not entirely clear if a “client” is an app or a GATT callback. It’s most likely the latter, though."](https://twitter.com/devunwired/status/841489489633652740) This is consistent with your comments! – stkent Mar 14 '17 at 13:42
  • "You can even have two `BluetoothGatt` objects in the same app connecting to the same device, and that way get double as many notification registration slots." seems like a good trick to be aware of also. – stkent Mar 14 '17 at 13:45
  • 2
    Beware though of the limit of the maximum BluetoothGatt objects, which in current Android verison is 32 globally. Probably less due to internal usage. – Emil Mar 14 '17 at 14:24
  • Also good to know - luckily I don't think I'll be pushing up against _that_ limit this time around! Do you know where the value 32 is set? – stkent Mar 14 '17 at 14:56
  • 2
    Yes. It's set here: https://android.googlesource.com/platform/system/bt/+/f6d79c5d6c9cc829dcfa033d59bade4d83334df7/include/bt_target.h#737 – Emil Mar 14 '17 at 16:48
  • >The APIs are quite badly designed. Preach! – axa Feb 17 '23 at 04:38