Matt
Matt

Reputation: 2036

"Service discovery failed" from Android Bluetooth Insecure Rfcomm

Does anyone know how to create an insecure RFCOMM connection between 2 Android devices at API level 2.3.3 while using an arbitrarily declared service name? (not random or changing service name, just a service name that I define myself)

Details

I am trying to create an insecure Rfcomm connection between 2 Android devices: Droid X2 and an Asus Transformer. I am assuming that both of these devices have functionality at the level of Android 2.3.3 to actually gain the ability to use insecure Rfcomm.

When I try to create the Bluetooth connection as described here, using the now public createInsecureRfcommSocketToServiceRecord() and listenUsingInsecureRfcommWithServiceRecord(SERVICE, UUID), I get a reported:

java.io.IOException: Service discovery failed
at android.bluetooth.BluetoothSocket$SdpHelper.doSdp(BluetoothSocket.java:377)
at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:201)
at com.s4d.bluenomad.DeviceConnections$ClientThread.run(DeviceConnections.java:406)

I found a related question where someone creating a normal connection was getting this error and used reflection to invoke a private method. However, I have no idea what private method would now correspond to initiating an "insecure" connection. I tried using the solution proposed in that related question, but I am asked by Android to pair the devices which is exactly what I need to avoid. I really do need the insecure approach.

I even tried a combination of the official and hacked solutions outlined here

Relevant Code Snippets

Creating ServerThread To Listen For Connections

Log.i(TAG, "Constructing a ServerThread");
// Use a temporary object that is later assigned to serverSocket,
// because serverSocket is final
BluetoothServerSocket tmp = null;
try {
    // MY_UUID is the app's UUID string, also used by the client code
    tmp = btAdapter.listenUsingInsecureRfcommWithServiceRecord(SERVICE_NAME, SERVICE_UUID);
    Log.i(TAG,"Started listening on insecure RFCOMM channel for service requests for: " + SERVICE_NAME);
} catch (IOException e) { }
serverSocket = tmp;

ServerThread Listening for Connections

BluetoothSocket socket;
while(true)
{
    try
    {
        socket = serverSocket.accept();
    }
    catch( IOException e)
    {
        break;
    }

    if( socket != null )
    {
        Log.i(TAG, "Received new socket connection requesting service: " + SERVICE_NAME);
    }
    else
    {
        Log.i(TAG, "Socket connection attempted, but socket received is NULL.");
    }
}

Creating ClientThread to Initiate Connections

Log.i(TAG, "Constructing a ClientThread");
BluetoothSocket tmp = null;
try {
    // MY_UUID is the app's UUID string, also used by the server code
    tmp = device.createInsecureRfcommSocketToServiceRecord(SERVICE_UUID);
    Log.i(TAG,"Created client socket on insecure RFCOMM channel for service requests for: " + SERVICE_NAME);
} 
catch (IOException e) 
{ 
    Log.i(TAG, "Failed to createInsecureRfcommSocket() against MAC: " + device.getAddress());
}
clientSocket = tmp;

ClientThread Connecting to Server

try
{
    clientSocket.connect();
}
catch( final IOException e)
{
    DeviceConnections.this.runOnUiThread(new Runnable()
    {

        @Override
        public void run() 
        {
            console.append("Client unable to connect to service.");
            Log.i(TAG, "Client socket unable to connect() to: " + clientSocket.getRemoteDevice().getAddress());
            e.printStackTrace();
        }

    });

}

I do get the log output "Client socket unable to connect() to: [MY_MAC_ADDRESS]", then I get the stacktrace for the "Service discovery failed" exception.

Upvotes: 13

Views: 23028

Answers (5)

tato.rodrigo
tato.rodrigo

Reputation: 2823

Android Bluetooth implementation is painful, because it may vary across devices.

I was experiencing the same issue. In my specific case, the error occured when at least one of the devices BluetoothAdapter.getScanMode() was set to BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE (i.e. the device is both discoverable and connectable from remote Bluetooth devices).

That is curious because the device should be connectable, but it was not.

If the device getScanMode() ==SCAN_MODE_CONNECTABLE, then no error occurs.

By now the the solution I found is to show a warning to the user, so they only connect to paired devices. If the devices are not paired, the user should use the Android settings and do the job.

Enabling bluetooth communication only for paired devices eliminates the need to be discoverable and then avoiding the "Service discovery failed".

Again, it is my specific case on my specific device. This may not be a general rule, but hope this helps anyone who is getting the same error.

Upvotes: 0

Shridutt
Shridutt

Reputation: 1

You should change 8ce255c0-200a-11e0-ac64-0800200c9a66 to any other UUID and you can use you service name because 8ce255c0-200a-11e0-ac64-0800200c9a66 is used for predefined Service BluetoothChatInsecure

Upvotes: 0

Matt
Matt

Reputation: 2036

It appears the problem was that before I called

clientSocket.connect()

I needed to call

btAdapter.cancelDiscovery()

I had seen this in documentation but it was listed as a "performance" issue - in my case it seems that this was actually a "functional" issue. Once I added the cancel discovery call, the socket connection worked immediately.

Upvotes: 15

Sourab Sharma
Sourab Sharma

Reputation: 2960

"Service Discovery Failed" simply means our device is not able to find service with same UUID in any other device.

The 2nd device has not called the "listenUsingInsecureRfcommWithServiceRecord" method, before you are trying to call the "createInsecureRfcommSocketToServiceRecord" from 1st device.

Make sure this code has been executed in 2nd device (like onResume(), or a button/optionsItem click) before you try to connect from 1st device.

 if ((mChatService != null) &&  (mBluetoothAdapter.isEnabled())) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
            }
        }

Upvotes: 3

Dennis Mathews
Dennis Mathews

Reputation: 6975

A few things to check

  • using the same and unique UUID both at the client and server.
  • Have the BLUETOOTH permission
  • Try with the standard well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB

Also it will help if you can paste the complete logs on the client and server side printing API error codes if any.

Upvotes: 5

Related Questions