What to keep in mind when developing your BLE Android app

BLE is native supported on Android from v4.3. It has been continuously improved as Android evolving. It's getting more and more complex with additional features. It's important that a Bluetooth app should work smoothly on all Android versions, from 4.3 to the latest one. One may find it's tricky to keep track of all the issues from earlier Android versions and the changes in BLE APIs of different API levels.

To help you with this, our app developers have provided a note, discussing about most important changes and added features on newer Android version 5 and 6, including some testings we have done on different Android phones regarding BLE performance.

Some interesting topic:

  1. Required permissions for BLE app.

  2. Scanning: different scan mode, report delay, callback type, etc

  3. Connection: autoConnect, connection parameter update, MTU, number packets per connection parameters.

  4. GATT server, advertising, how to set it up.

This document is strongly recommended to whom developing Android apps:

BLE_on_Android_v1.0.1.pdf

(Updated 05Dec2016)

Question and issue, please post as a separated case and post the link here.

Parents
  • Hi, thanks for the long comment. Here's my reply:

    1. I have fixed chapter numbering. It was broken when the document got the Nordic'y look&feel and no one noticed. Sorry!
    2. I had some problems with the URL with double slash as Word apparently "fixes" the URL to have just one, but "/-/" trick works. Also not quite my fault, except I did not notice. Also is fixed now.
    3. "In chapter 3, connecting to a BLE device using an address directly, as of Android Nougat it is no longer true that it will assume it is a public address. It varies between Android builds but it sometimes set the bit to random address." - my source in Google says it's still a thing. How do you know it varies between builds? Are you talking about the different public 7.1-betas or something more internal?
    4. "I wonder about the sentence "the logic being that random addresses can change any time, and if it is hardcoded, it must be a public one". Is that something someone at Google has confirmed or is that just an assumption? Actually I think this is an afterthought when they added BLE support since they didn't need to care about address type before. There are still other bugs where they mess up with the address type in their code..." - I got this information from Google and it seems logical. If an app wants to connect to a BLE device that has never (since Bluetooth restart) been scanned before and it knows the address, it most probably mean that it's a public address, despite the fact that public addresses are super rare, as I can imagine. Here's what I got:

    Message received 5 Oct 2016: Only the MAC address is used to identify a device (no type). When an address is passed to lower levels in C, the system tries to match it with a security record which contains the address type. If such record does not exist a PUBLIC address is assumed - how could someone have a random address without scanning? It's a known problem and fixing it is in our backlog. Currently the best way to connect is to scan and use the returned BluetoothDevice object. Mind, that the security record is forgotten when Bluetooth adapter is restarted (unless it's a PUBLIC address or the device is bonded).

    Since then I also got the information, that in OOB pairing using NFC the address type encoded in the NFC message is also ignored in Android 7.1. The fix has already been made on AOSP and will be available in Android 7.2, or whatever comes next.

    1. "Also, a third condition is that it also works without the need to scan before if the device is bonded (I've tested static random addresses and public addresses, not sure about random resolvable addresses)" - true, I added The device has a PUBLIC address or is bonded, or

    2. "It definitely attempts to connect to this device (with a HCI LE Create Connection). The only difference regarding that is that the address is provided by the white list instead of in the HCI LE Create Connection command. Also the standard configuration (which may be different between Android phone vendors) is to use more active scanning parameters when using autoConnect=false which leads to faster connection setups." - as far as I remember in a test I made using a BLE sniffer, when I was trying to connect to an advertising HTC One M8 phone form a Nexus with autoConnect=true, there was no Connection Req at all. However, this chapter based only on my experience so I will change it to what you wrote. Thank you.

    3. "There are more differences:.[...]" - let me just copy the whole paragraph to the PDF :) Although, as you wrote in the second URL, the race condition is now fixed.

    4. "Regarding older devices where overflow is not handled well, as well as on iOS, an easy workaround is to send each 15th packet or so as a Write With Response. Then you don't need to create any special acknowledgement logic on the peripheral side. It of course reduces speed a bit, but rather that than dropped packets." - Nice idea. Added to the PDF.

    5. "In chapter 4.5. With Qualcomm Bluetooth chips, that is used in for example Nexus 5X, I've measured 12 packets per connection event." - wow, that's hell of a chip. Almost as good as Nordic's :)

    6. "When referring to particular lines in Android source code, link to a specific commit rather than master. Otherwise the links will soon not be valid anymore. If you link to a file as a whole I guess you may link to a file in the master branch however." - true... usually I gave a commit link + link to the most recent version. But it is true they may change.

    7. "There are some race conditions in the Android SDK if you call methods too quickly after each other. See code.google.com/.../detail. If you need to have stable long-running connectivity to Android devices you should avoid restarting advertising immediately after a connection loss but rather wait a small time in between to prevent that the Android stack hangs. See code.google.com/.../detail - yes, adding delays help. If you check the source code for the Android DFU library I add a lot of those. For some devices it's enough to run a method from UI thread (I assume the small delay is enough, doesn't have to be the UI thread)

    Thanks again for your long response. I'll update the PDF next week.

Comment
  • Hi, thanks for the long comment. Here's my reply:

    1. I have fixed chapter numbering. It was broken when the document got the Nordic'y look&feel and no one noticed. Sorry!
    2. I had some problems with the URL with double slash as Word apparently "fixes" the URL to have just one, but "/-/" trick works. Also not quite my fault, except I did not notice. Also is fixed now.
    3. "In chapter 3, connecting to a BLE device using an address directly, as of Android Nougat it is no longer true that it will assume it is a public address. It varies between Android builds but it sometimes set the bit to random address." - my source in Google says it's still a thing. How do you know it varies between builds? Are you talking about the different public 7.1-betas or something more internal?
    4. "I wonder about the sentence "the logic being that random addresses can change any time, and if it is hardcoded, it must be a public one". Is that something someone at Google has confirmed or is that just an assumption? Actually I think this is an afterthought when they added BLE support since they didn't need to care about address type before. There are still other bugs where they mess up with the address type in their code..." - I got this information from Google and it seems logical. If an app wants to connect to a BLE device that has never (since Bluetooth restart) been scanned before and it knows the address, it most probably mean that it's a public address, despite the fact that public addresses are super rare, as I can imagine. Here's what I got:

    Message received 5 Oct 2016: Only the MAC address is used to identify a device (no type). When an address is passed to lower levels in C, the system tries to match it with a security record which contains the address type. If such record does not exist a PUBLIC address is assumed - how could someone have a random address without scanning? It's a known problem and fixing it is in our backlog. Currently the best way to connect is to scan and use the returned BluetoothDevice object. Mind, that the security record is forgotten when Bluetooth adapter is restarted (unless it's a PUBLIC address or the device is bonded).

    Since then I also got the information, that in OOB pairing using NFC the address type encoded in the NFC message is also ignored in Android 7.1. The fix has already been made on AOSP and will be available in Android 7.2, or whatever comes next.

    1. "Also, a third condition is that it also works without the need to scan before if the device is bonded (I've tested static random addresses and public addresses, not sure about random resolvable addresses)" - true, I added The device has a PUBLIC address or is bonded, or

    2. "It definitely attempts to connect to this device (with a HCI LE Create Connection). The only difference regarding that is that the address is provided by the white list instead of in the HCI LE Create Connection command. Also the standard configuration (which may be different between Android phone vendors) is to use more active scanning parameters when using autoConnect=false which leads to faster connection setups." - as far as I remember in a test I made using a BLE sniffer, when I was trying to connect to an advertising HTC One M8 phone form a Nexus with autoConnect=true, there was no Connection Req at all. However, this chapter based only on my experience so I will change it to what you wrote. Thank you.

    3. "There are more differences:.[...]" - let me just copy the whole paragraph to the PDF :) Although, as you wrote in the second URL, the race condition is now fixed.

    4. "Regarding older devices where overflow is not handled well, as well as on iOS, an easy workaround is to send each 15th packet or so as a Write With Response. Then you don't need to create any special acknowledgement logic on the peripheral side. It of course reduces speed a bit, but rather that than dropped packets." - Nice idea. Added to the PDF.

    5. "In chapter 4.5. With Qualcomm Bluetooth chips, that is used in for example Nexus 5X, I've measured 12 packets per connection event." - wow, that's hell of a chip. Almost as good as Nordic's :)

    6. "When referring to particular lines in Android source code, link to a specific commit rather than master. Otherwise the links will soon not be valid anymore. If you link to a file as a whole I guess you may link to a file in the master branch however." - true... usually I gave a commit link + link to the most recent version. But it is true they may change.

    7. "There are some race conditions in the Android SDK if you call methods too quickly after each other. See code.google.com/.../detail. If you need to have stable long-running connectivity to Android devices you should avoid restarting advertising immediately after a connection loss but rather wait a small time in between to prevent that the Android stack hangs. See code.google.com/.../detail - yes, adding delays help. If you check the source code for the Android DFU library I add a lot of those. For some devices it's enough to run a method from UI thread (I assume the small delay is enough, doesn't have to be the UI thread)

    Thanks again for your long response. I'll update the PDF next week.

Children
No Data