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?
1 Answers
UPDATE 10/2019
Support is there! Enjoy the new API:
- BluetoothDevice.createL2capChannel(int)
- BluetoothDevice.createInsecureL2capChannel(int)
- BluetoothAdapter.listenUsingL2capChannel()
- BluetoothAdapter.listenUsingInsecureL2capChannel()
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:
- A
createL2capSocket
method in android 8 (source) - A
createL2capCoCSocket
method in android 9 (source) - A
createL2capChannel
in the master branch of the android project (future release I guess?) (source)
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.

- 800
- 8
- 21
-
Could you tell a bit more about the "very unsatisfying results"? In what way did it not work as you expected? – Emil Aug 17 '19 at 10:34
-
1Transfer was slow, and connecting was unreliable. Hopefully I'll have some time to test with Q soon – nsndvd Aug 27 '19 at 15:34
-
2I just tested in Android Q beta. Seems to work nice. I also tested on Oreo, but the transfer was slow because it only allows 1 credit at a time there, so max 1 packet per connection event. However there is a bug (in both versions) that if you send a packet of length 0 to Android, `read(byte[])` reports the length of the packet to be -1 instead of 0. – Emil Aug 27 '19 at 16:20
-
1Maybe you can update my answer with your fresh results ;) – nsndvd Aug 29 '19 at 07:13
-
I've python script that creates the L2CAP server on Linux and I'm using `BluetoothDevice.createInsecureL2capChannel(int)` method to create a socket on the app side, but getting IOException. Does anyone have an idea about this? – Harshvardhan Trivedi Dec 27 '19 at 10:07
-
@HarshvardhanTrivedi not really, what's the stacktrace? – nsndvd Dec 30 '19 at 12:07
-
I feel like I'm going crazy. I'm using BluetoothAdapter.listenUsingL2capChannel() to create a BluetoothServerSocket and I use BluetoothServerSocket.accept() in a seperate Thread to wait for incoming Connections. I share the server's PSM value with clients meant to connect. On client devices I run BluetoothDevice.createL2capChannel(SHARED_PSM_VALUE) and run connect() on the returned Socket. Anyway, the connect() method throws an IOException with not too many details (read failed, socket might...). Also, I've already tried the Insecure methods. Same result. Did you guys face something similar? – Nico Feulner Nov 22 '20 at 12:19
-
Sorry I haven't worked on this topic for a while.. I guess there could be many possible problems..The first that pops into my mind.. Are bluetooth and location enabled, and bluetooth and location permissions granted? – nsndvd Nov 24 '20 at 22:00
-
Thanks for your answer @nsndvd ! Yep, they are enabled and granted respectively. I did pretty much everything the same way I've always done it, when I used RFCOMM sockets. However, it just doesn't work using L2CAP. It is so strange. Especially cause it works when I replace the L2CAP method calls by RFCOMM method calls. – Nico Feulner Dec 12 '20 at 14:51
-
@NicoFeulner did you ever figure this out with L2CAP? I'm seeing the same thing, namely that RFCOMM works but L2CAP doesn't. I'd like to avoid using RFCOMM because we need to support iOS down the road. – kevmo314 Mar 24 '22 at 04:11
-
I haven't tried it again ever since but I had the same intention of supporting both iOS and Android. I thought about writing a Flutter library when I was into this topic. As it was a private project I could easily suspend my efforts and started working on other projects. Would still be interesting to know if it can somehow work (maybe thanks to API updates in newer versions of Android, I haven't checked it). Anyway, I haven't found a solution... – Nico Feulner Mar 24 '22 at 16:07