androidbluetoothbluetooth-lowenergyl2cap

How can I instantiate a L2Cap socket in Android?


I see that a Bluetooth socket can be of type TYPE_L2CAP, but the constructor for BluetoothSocket seems to be private and I can only find a method to instantiate a socket of type RFCOMM. How can I obtain and use a L2CAP socket? Is it actually supported by Android?


Solution

  • UPDATE 10/2019

    Support is there! Enjoy the new API:

    UPDATE 03/2019 With the first Android Q beta out there it looks like support is finally coming. https://developer.android.com/sdk/api_diff/q-beta1/changes.html

    UPDATE 10/2018

    Got info that L2CAP CoC will be supported starting from Android Q.

    Unfortunately I'm unable to cite official sources for that.

    OLD ANSWER

    I'll post my own results, hoping to help others and maybe get hints if I am missing something.

    TL;DR: Looks like I can't

    No way to get a L2CAP CoC socket with public API

    This page from the Android documentation claims that “LE Connection-Oriented Channels” (l2cap channels) are available since Android 8.0. In the Android API there is a BluetoothSocket class that can have type L2_CAP. But there is no way to get a BluetoothSocket instance with such type, due to the private visibility of the elements of that class. That’s it for the public Android java API: stuck.

    So?

    Digging under the surface of the public java API. The source code for the android version 8+ offers a way to get a l2cap socket that is evolving in time:

    But in each released version this code is marked with the @hide annotation, which means that none of these methods is actually available for usage.

    Before Android 9 hidden methods were at least accessible, on some devices, with java reflection. That’s how we were able to test on android 8, with awful results.

    Since version 9 of the OS this is not possible anymore: the platform actively blocks attempts to improperly access APIs.

    Moreover..

    Beside the fact that the methods to instantiate a socket are not visible, there is evidence of the immaturity of the API also in the lack of methods to tune parameters of the l2cap connection.

    Going native?

    I don't have experience with NDK but I think it would be possible to write c code to exploit the same low level functions used by the hidden methods. Unless android is not blocking that kind of usage as well, which is likely. Also this usage would conflict with regular usages of the bluetooth stack on a phone: normal usages are normally all filtered by an Android service. Bypassing this service would lead to unpredictable consequences, and it’s not suitable for a productive app.

    Wrap it up

    Testing on Android 8.1 with reflection led to very unsatisfying results. The claim that “LE Connection-Oriented Channels” are available since Android 8.0 just can’t be confirmed, despite the efforts.

    In newer versions, the hidden methods for creating l2cap channels are evolving, and recently the hide annotation was removed. It’s hard to tell what this means in terms of time before we can have a device in our hands that supports this API. it’s likely that it will take years before l2cap channels will be reliable and available to a significant share of the android users.