Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"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.

like image 609
Matt Avatar asked Dec 15 '11 05:12

Matt


3 Answers

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.

like image 135
Matt Avatar answered Nov 20 '22 20:11

Matt


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.

like image 24
Dennis Mathews Avatar answered Nov 20 '22 20:11

Dennis Mathews


"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();
            }
        }
like image 3
Sourab Sharma Avatar answered Nov 20 '22 18:11

Sourab Sharma