How do Bluetooth SDP and UUIDs work? (specifically for Android) - android

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?

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.

Related

Manually set bluetooth server port in Android

I have a working Bluetooth server running (Android app). I would like to set a specific Bluetooth port for it to listen to. The reason for that is that for the client to connect, it takes about 10-15 seconds because it needs to first discover the server (i do a scan ).
the code to create the server is the following:
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
UUID my_uuid = UUID.fromString("12345678-f6ff-4f6f-1f1f-f8f8f8fffff8");
try {
BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("myBluetoothServer", my_uuid);
sock1 = serverSocket.accept();
i_s = sock1.getInputStream();
o_s = new OutputStreamWriter(socket.getOutputStream());
new Thread(writter).start();
...
Question: how to specify a fixed port number for the server?
I have been looking here, of course, but it is not easy to find,:
https://developer.android.com/reference/android/bluetooth/BluetoothSocket?hl=ur
I am looking for something like serverSocket.setPort(myPortNumber) (pseudo - code)
The concept of port does not exist for Bluetooth Sockets since they are not regular TCP/IP sockets. They are just abstracted to behave like one.
As you figured out from your code, what you specify is a UUID which is a service identifier. The process to connect to a Bluetooth server goes like this:
Bluetooth Device scan: You can't skip this part, since you need a valid BluetoothDevice object
Service Discovery for a discovered Device: This is the part where you "check" if that Bluetooth Device is running the service that you are looking for (Your service UUID) So you shouldn't skip this part either, unless you want to connect to all surrounding Bluetooth devices.

accept() and connect() methods in bluetooth socket

I am getting bluetooth socket connection problem and so tried various alternatives to connect.
It is like if first fails then second and if second also fails then third and so the main UI blocks during the process.
The exceptions are like -
"Service discovery failed" OR "Host is down"
My all three alternatives -
1) Connect with a connect() function
m = bdDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
socket = (BluetoothSocket) m.invoke(bdDevice, Integer.valueOf(i));
mBluetoothAdapter.cancelDiscovery();
socket.connect();
2) Connect with a accept() function
m = bdDevice.getClass().getMethod ("listenUsingRfcommOn", new Class [] {int.class});
BluetoothServerSocket returnValue =
(BluetoothServerSocket) m.invoke(bdDevice, new Object [] {29});
socket = returnValue.accept();
3) Connect with a well know SPP UUID
private final UUID my_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
socket = bdDevice.createInsecureRfcommSocketToServiceRecord(my_UUID);
mBluetoothAdapter.cancelDiscovery();
socket.connect();
The second alternative is recently added and so I am not sure that how is it different from first and third one. All will block the UI until connect, all can through IOException.
1) You are connecting as a client to your SPP device. Therefore your device must be expecting a connection before you can actually connect.
2) You are accepting the connection as the server. Your bluetooth device will be responsible for firing the connection requests.
3) You are connecting to a device that uses a particular UUID as it's Serial Port Profile (SPP). Think of this as similar to ports in http protocol. The 00001101-0000-1000-8000-00805F9B34FB, is one of the most common ones. More info : https://developer.bluetooth.org/TechnologyOverview/Pages/SPP.aspx
Additionally, if you are thinking on supporting multiple OS / handset versions. You might see those error messages after an initial broken comm. Android's bluetooth stack (bluez) was totally replaced on 4.2, but you might need to still handle previous known bugs.
Reflection in this case is a good thing (some parts of the bluetooth API wasn't public in older versions). But, in my experience, API level < 17; using createInsecureRfcommSocket instead of createRfcommSocket is much more reliable.
Hope this helps. But if you are building an app for a custom bluetooth spp device of yours, explaining how that devices handles comms could help pointing out the exact root of your problem. Although, bluetooth on Android is never straight forward.

the differences between createRfcommSocketToServiceRecord and createRfcommSocket

What are the differences between these two ways below connecting to a bluetooth Device:
1)
UUID uuid = UUID.fromString(Values.SPP_UUID); //Standard SerialPortService ID
mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
2)
Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
mmSocket = (BluetoothSocket) m.invoke(mmDevice, 1);
I find the first way cannot work all the time, sometimes it will work, but after I close the bluetooth device, it won't work again. The second way is always work well. I know it is just open the channel one to communicate with bluetooth, but I do not know how it can do that to connect to a bluetooth device without using uuid?
Think of it a bit like the difference between opening a TCP connection to a port you specify by number, and opening one to a port you look up by name from /etc/services.
createRfcommSocketToServiceRecord takes the UUID you pass and uses SDP to decide what radio channel to use for the connection. It also checks to make sure that a server is listening on the remote endpoint, with the same UUID. In this way, it's the most reliable way to get a connection: it'll always use the correct channel, and if opening the connection succeeds, you know something at the other end can understand your protocol.
In contrast, createRfcommSocket just connects to the channel you tell it. There's no way to know whether anything is listening on the remote endpoint: you only know the device is there. Also, your choice of radio channel may be completely inappropriate. That's why this function is not published in the API, and the other function is preferred.
createRfcommSocket may appear at first to be more reliable, but it's because it's not checking for the presence of a listener at the other endpoint: it's ignoring some error cases. This might be alright for experimenting, but it's no use for a production system, because often the user will forget to start the server on the other endpoint, and your app will fail in confusing ways.
Of course, as createRfcommSocket isn't published in the API, you've no guarantee it will continue to work at all in future releases of Android.

Android Find the UUID of a specific bluetooth device

I'm starting to work on Bluetooth in Android recently.
I want to build an application that can read the data recorded by a sensor through bluetooth.
I have some sample code, but looks like I need another UUID of a different device.It looks like this:
private static final UUID MY_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
Later on in the code, it uses this UUID to make a connection:
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
I have done some research online, like [here][1]. I think I need a different UUID number for the new device I'm working on. How do I get the UUID number?
On the device, there are two lines of number saying:
SN: 1201L0023
BT: 10:00:E8:C5:16:85
Thanks in advance!
Jake
UUIDs are not tied to particular devices. They identify software services. Some UUIDs for defined profiles are set by BT. The UUIDs used with RFCOMM sockets like your example are arbitrary. You just need both sides to use the same one. In general, devices connect and then use service discovery protocol to find out what services (UUIDs) are supported on the remote device.

Connecting to a specific bluetooth port on a bluetooth device using Android

Is there any way for Android to connect to a Bluetooth device using a specific port instead of using service UUID?
I know this option is available in other platforms which provide Bluetooth support (Java ME for example by specifying a "btspp://" style URL).
Thanks!
Ok, it's been a while, but I found a solution to the problem. I actually intended to give up and use UUID, but I kept getting a Service Discovery Failed (IO)exception, and when I tried to find a solution to the service discovery issue, I found the solution to my original question... Ain't life something?:)
Anyways, this is the link I stumbled upon, though you should note there is a mistake in the answer (they actually simply connected to port 1, instead of using a service UUID).
And after this short history lesson, here is the solution:
Using reflection, it is possible to create the Rfcomm socket connecting to a port number instead of UUID:
int bt_port_to_connect = 5; // just an example, could be any port number you wish
BluetoothDevice device = ... ; // get the bluetooth device (e.g., using bt discovery)
BluetoothSocket deviceSocket = null;
...
// IMPORTANT: we create a reference to the 'createInsecureRfcommSocket' method
// and not(!) to the 'createInsecureRfcommSocketToServiceRecord' (which is what the
// android SDK documentation publishes
Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
deviceSocket = (BluetoothSocket) m.invoke(device,bt_port_to_connect);
A few things to notice:
since we're using Invoke, the first parameter is the object we're invoking the method on, the second parameter of invoke is actually the first function parameter)
There is also a secure version available ('createRfcommSocket'), which accepts a bluetooth channel number as a single parameter (again, since this is invoke style, you'll need to pass the object to invoke the method on, as mentioned in -1- )
I found what appears to be a link to these functions' prototypes
Good luck to all.
Bluetooth Android connections are exclusively done via UUID. Each Bluetooth device has a UUID for every service it runs (see Bluetooth SDP).
You just give Android the UUID to watch for and, in client mode, it will find a socket to connect to automatically (including port). In server mode, it will wait for the specified device to initiate a connection using the specified UUID.
The BluetoothSocket object is also valid when connection is established (use getInput/Output Stream)
See Server Socket documentation and Client Socket documentation.
If you really want to check everything, you can see what Android decodes from the other device's SDP and the UUID you provided.
Use this tutorial to get the Bluetooth interface (very easy to do).
Then the code should look something like this:
IBluetooth ib =getIBluetooth();
Int otherDevicePort = ib.getRemoteServiceChannel(otherDeviceAddress, UUID);
I'm using bluecove which allow me to do so with the function Connector.open().
I use the following url:
btspp://" + phoneID + ":" + phonePort
N.b.: Some options can be added (e.g.: authenticate=false; or encrypt=false;).
With phoneID being the the being the Bluetooth address and phonePort the port number.
How to find the Bluetooth address?
From this link:
From the Home screen, open the app drawer, then open “Settings“.
Select “System“. (Skip this step on some models)
Scroll down to the bottom and tap “About Phone“, “About device“, or “About tablet“.
Scroll down to the bottom and tap “Status“.
Scroll down and the “Bluetooth address” will be shown in the list.
How to find the port number?
I haven't been able to find which port is supposed to be used yet...
I used 5 and it works but I need to research why and if I want to change the phone I will need to know if I also need to change the port.

Categories

Resources