Day 44: hints on Android API and BLE

Since last week (after having rewritten our protocol with a single characteristic), I struggled a lot with Android API for GATT connections. To help you to establish clean connections, here is what I have found.

A BluetoothGatt object is a kind of socket. You open it, then you connect and disconnect it as many times as you want, and then you close it.

In the Android API, the connection occurs as soon as the GATT is opened: it is the purpose of the BluetoothDevice.connectGatt method. BluetoothGatt.connect is only used for reconnections after a disconnection. On the contrary, the disconnect and close operations shouldn’t be done at the same time. Closing a GATT means forgetting it (it would be done by the Garbage Collector, but it is better to do it as soon as you don’t need it anymore, so that ressources can be freed), so what will happen if you receive a “onDisconnected” event for a GATT that you have already closed? A NullPointerException is thrown (see the Android logcat). Then BluetoothGatt.close must be used only after having received the confirmation that the GATT is disconnected (typically, in the onDisconnected callback).

Please note that the S110 SoftDevice (which we use on the nRF51822 chip) only accepts one GATT connection at a time, but it is only a matter of implementation, and not a standard behaviour with Bluetooth Low Energy. Consequently, your phone is able to open and maintain several GATT connections in the same time. And these connections may be established with the same BLE device (even a nRF51822). Technically, what you will have are several BluetoothGatt objects with different UUIDs (each connectGatt creates a new instance). But this is a bad behaviour, and if you maintain several BluetoothGatt objects towards the same nRF51822, after a few iterations you won’t be able to connect anymore. So don’t forget to close GATTs you won’t reconnect with, and keep track of already created GATTs so that you can reconnect them instead of creating new instances.

By the way, the life time of an Android application is not the life time of  your main activity. Even when the application is not visible anymore in the “Recent apps” panel, it may survive, and the only way to kill it properly (without debug options) is to “Force quit” it in the Application options. Consequently, be cautious when recreating a GATT object if you are not sure that the previous one was destroyed (which happens systematically when the app is killed).

A GATT connection must not be confused with pairing and bonding. Here is an extract of nRF51 documentation:

Bonding is when two devices that connect and follow procedures that allow them to cache information inorder to avoid repeating certain set-up procedures on subsequent reconnection(s).

The caching of information can span across layers in the system, for example, keys needed to secure the link on reconnection, GATT Server Configuration. Information with respect to a bonded peer is expected to be retained on power cycle of the device, and is maintained persistently.

In contrast to bonding, the Bluetooth specification defines procedure needed to establish secure link for ongoing session only, called Pairing. No information is cached for paired devices. Please refer to Volume 3 Part H, Section 6.5 of Bluetooth Core Specification 4.0 for more information.

To put it in a nutshell:

– GATT connections/disconnections are short term, when you have a few pieces of data to send.

– GATT objects are middle term, typically for the life time of your Android application.

– Pairing is for establishing secure connections.

– Bonding is long term, when you known your devices will often interact.

I hope I was clear enough, don’t hesitate to ask me if you have questions left, or to tell me if I was wrong on some point.

Commentaires fermés.