Ioexception: Read Failed, Socket Might Closed - Bluetooth on Android 4.3

IOException: read failed, socket might closed - Bluetooth on Android 4.3

I have finally found a workaround. The magic is hidden under the hood of the BluetoothDevice class (see https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037).

Now, when I receive that exception, I instantiate a fallback BluetoothSocket, similar to the source code below. As you can see, invoking the hidden method createRfcommSocket via reflections. I have no clue why this method is hidden. The source code defines it as public though...

Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};

Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};

fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
fallbackSocket.connect();

connect() then does not fail any longer. I have experienced a few issues still. Basically, this sometimes blocks and fails. Rebooting the SPP-Device (plug off / plug in) helps in such cases. Sometimes I also get another Pairing request after connect() even when the device is already bonded.

UPDATE:

here is a complete class, containing some nested classes. for a real implementation these could be held as seperate classes.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.List;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

public class BluetoothConnector {

private BluetoothSocketWrapper bluetoothSocket;
private BluetoothDevice device;
private boolean secure;
private BluetoothAdapter adapter;
private List<UUID> uuidCandidates;
private int candidate;


/**
* @param device the device
* @param secure if connection should be done via a secure socket
* @param adapter the Android BT adapter
* @param uuidCandidates a list of UUIDs. if null or empty, the Serial PP id is used
*/
public BluetoothConnector(BluetoothDevice device, boolean secure, BluetoothAdapter adapter,
List<UUID> uuidCandidates) {
this.device = device;
this.secure = secure;
this.adapter = adapter;
this.uuidCandidates = uuidCandidates;

if (this.uuidCandidates == null || this.uuidCandidates.isEmpty()) {
this.uuidCandidates = new ArrayList<UUID>();
this.uuidCandidates.add(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
}
}

public BluetoothSocketWrapper connect() throws IOException {
boolean success = false;
while (selectSocket()) {
adapter.cancelDiscovery();

try {
bluetoothSocket.connect();
success = true;
break;
} catch (IOException e) {
//try the fallback
try {
bluetoothSocket = new FallbackBluetoothSocket(bluetoothSocket.getUnderlyingSocket());
Thread.sleep(500);
bluetoothSocket.connect();
success = true;
break;
} catch (FallbackException e1) {
Log.w("BT", "Could not initialize FallbackBluetoothSocket classes.", e);
} catch (InterruptedException e1) {
Log.w("BT", e1.getMessage(), e1);
} catch (IOException e1) {
Log.w("BT", "Fallback failed. Cancelling.", e1);
}
}
}

if (!success) {
throw new IOException("Could not connect to device: "+ device.getAddress());
}

return bluetoothSocket;
}

private boolean selectSocket() throws IOException {
if (candidate >= uuidCandidates.size()) {
return false;
}

BluetoothSocket tmp;
UUID uuid = uuidCandidates.get(candidate++);

Log.i("BT", "Attempting to connect to Protocol: "+ uuid);
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(uuid);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
}
bluetoothSocket = new NativeBluetoothSocket(tmp);

return true;
}

public static interface BluetoothSocketWrapper {

InputStream getInputStream() throws IOException;

OutputStream getOutputStream() throws IOException;

String getRemoteDeviceName();

void connect() throws IOException;

String getRemoteDeviceAddress();

void close() throws IOException;

BluetoothSocket getUnderlyingSocket();

}


public static class NativeBluetoothSocket implements BluetoothSocketWrapper {

private BluetoothSocket socket;

public NativeBluetoothSocket(BluetoothSocket tmp) {
this.socket = tmp;
}

@Override
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}

@Override
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}

@Override
public String getRemoteDeviceName() {
return socket.getRemoteDevice().getName();
}

@Override
public void connect() throws IOException {
socket.connect();
}

@Override
public String getRemoteDeviceAddress() {
return socket.getRemoteDevice().getAddress();
}

@Override
public void close() throws IOException {
socket.close();
}

@Override
public BluetoothSocket getUnderlyingSocket() {
return socket;
}

}

public class FallbackBluetoothSocket extends NativeBluetoothSocket {

private BluetoothSocket fallbackSocket;

public FallbackBluetoothSocket(BluetoothSocket tmp) throws FallbackException {
super(tmp);
try
{
Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};
fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
}
catch (Exception e)
{
throw new FallbackException(e);
}
}

@Override
public InputStream getInputStream() throws IOException {
return fallbackSocket.getInputStream();
}

@Override
public OutputStream getOutputStream() throws IOException {
return fallbackSocket.getOutputStream();
}


@Override
public void connect() throws IOException {
fallbackSocket.connect();
}


@Override
public void close() throws IOException {
fallbackSocket.close();
}

}

public static class FallbackException extends Exception {

/**
*
*/
private static final long serialVersionUID = 1L;

public FallbackException(Exception e) {
super(e);
}

}
}

Buetooth connection failed: read failed, socket might closed or timeout, read ret: -1

Try to use ,

createInsecureRfcommSocketToServiceRecord(MY_UUID)

in place of

createRfcommSocketToServiceRecord(MY_UUID)

This should fix the problem. Share your debugging results , if this doesn't fix the issue.

Also , don't generate random UUID(s), try the one below.

UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

Bluetooth connect failed. java.io.IOException: read failed, socket might closed or timeout, read ret: -1

In my situation,the bluetooth settings that comes with the system works.

So, I look the source code of the bluetooth settings.

And Copy the libframeworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth into my project.

Use reflect to invoke the hide Class and function or variable.

Finally, it works.

I wish this could help.

AGAIN: read failed, socket might closed or timeout

I found my answer in another Question!. this link:

Android Connect Bluetooth device automatically after pairing programmatically

In Question discripe how connect(and it's answer complete it)

Note: before Test sure devices are Unpair

Android bluetooth connection throwing read failed, socket might closed or timeout, read ret android

I found the answer in the following question:-

IOException: read failed, socket might closed - Bluetooth on Android 4.3

Actually I had to use reflection only on the fall back, ie, inside the catch when the connect fails.



Related Topics



Leave a reply



Submit