7

My understanding is that the SDP is a list of UUIDs that other devices can fetch.

According to this PDF from MIT, "A more general way to think of SDP is as an information database." Does this mean I can add multiple values to SDP? Since Android has BluetoothDevice.fetchUuidsWithSdp(), how do I set the UUIDs of a device?

Also, what does each section of an UUID mean? UUIDs look like 00000000-0000-1000-8000-00805F9B34FB, but what information does this convey?

Leo Jiang
  • 24,497
  • 49
  • 154
  • 284

1 Answers1

17

An UUID identifies a service that is available on a particular device. So if you call BluetoothDevice.fetchUUidsWithSdp() your BroadcastReceiver will receive the relevant Intent ACTION_UUID containing the device and the service UUID. The bluetooth specification defines some common UUIDs.

If you don't want to connect to one of these well known services but intent to implement your own bluetooth application, then you have to just generate your own UUID (use uuidgen from a unix console or an online generator) that identifies your application/service. You can create an UUID instance in java like this UUID uuid = UUID.fromString("785da8ea-1220-11e5-9493-1697f925ec7b");.

So if you create the server side for your bluetooth application on Android you typically do this

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("YourHumanReadableServiceName", uuid);

And this is where you "set" your UUID. The Android bluetooth API creates the SDP-entry consisting of YOUR application's UUID and name for you. Other devices can now retrieve this entry. Androids bluetooth stack will now associate a bluetooth channel to your BluetoothServerSocket. If you want to connect to this ServerSocket, the connecting side usually connects doing this:

// you will most likely already have this instance from a discovery or paired device list
BluetoothDevice serverDevice = adapter.getRemoteDevice(bluetoothMacAddress);
// connect to your ServerSocket using the uuid
BluetoothSocket socket = serverDevice.createRfcommSocketToServiceRecord(uuid);
socket.connect();

Android will again do the heavy lifting for you: It checks the SDP-Records on the remote device, looks up the bluetooth channel that corresponds to your service's UUID and connects using this information.

There is a common code snippet spooking around here on SO that advices you to use "reflection" to get to a hidden API looking similar to this code:

 try {
     // this is the way to go
     socket = device.createRfcommSocketToServiceRecord(uuid);
     socket.connect( );
 } catch ( IOException exception ) {
     // don't do that! You will bypass SDP and things will go sideways.
     Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
     socket = (BluetoothSocket) m.invoke(device, 1);
     socket.connect();
 }

Most people try this and it "just works" in their dev environment but you should know what you do using this. You actively bypass the SDP lookup that retrieves the right bluetooth channel to be used with your service and you will end up connecting to channel 1. If you have more than one Service running on the device, things WILL go sideways in this cases and you will end up in debugging hell ;-)

I developed a small middleware called Blaubot to create small networks using bluetooth/wifi/nfc and experienced all sorts of problems on the devices I used to test with (12 models). It was often the case that the bluetooth stack was not fully functional anymore in cases where it got some load or after many connects/disconnects (which you usually will have, if you are developing your app). In these cases the device.createRfcommSocketToServiceRecord(uuid) would occasionally fail and only turning the bluetooth adapter off and on again helped to bring the bluetooth adapters back to life (in some cases only after a full power cycle). If this happens and you use the reflection method, you will probably not have much fun with bluetooth.

But if you know this and keep concurrent calls to the BluetoothAdapter within bounds, bluetooth connections and the adapters will be pretty stable.

hgross
  • 690
  • 6
  • 15
  • Do you know if I can add multiple SDP records? I tried using `adapter.listenUsingRfcommWithServiceRecord` multiple times, but only one of them can be seen by other devices. – Leo Jiang Jun 14 '15 at 05:40
  • That is exactly how you do it. The UUID should be discoverable by other devices as long as your `BluetoothServerSocket` lives. Have you tried to connect to both from another device? If this works, your problem may be the discovery. – hgross Jun 14 '15 at 11:57
  • I think my app is using the cached data, I'll try `fetchUuidsWithSdp` and see if it works. – Leo Jiang Jun 14 '15 at 19:30
  • Yes, that is a thing. The SDP records are cached for some time so if you change values like service or device names you will get the cached values for some time. Power cycle should help. – hgross Jun 16 '15 at 22:54
  • 1
    @hna When I am using `listenUsingRfcommWithServiceRecord` for some reason the UUID is flipped when I am scanning it from another device. For example when I am setting it to: `785da8ea-1220-11e5-9493-1697f925ec7b` I am getting `7bec25f9-97114-9394-e511-2012eaa85d78`. Notice every 2 characters. Do you know why it could behave like that? – mtfk Feb 23 '18 at 06:32
  • @hgross Is there a way to "bypass" the SDP auto channel selection using with RFCOMMs? I am trying to mimic how a free android app called RoboRemo can automatically connect to a paired device via RFCOMMs by simply selecting the same channel its listening on regardless of UUID. – Stigma Jun 22 '21 at 05:35
  • I think this is what happens in our case, you may probably help us TIA: https://stackoverflow.com/q/69041213/12204620 – Bitwise DEVS Sep 03 '21 at 07:59