gpt4 book ai didi

android - IOException : read failed, 套接字可能已关闭 - Android 4.3 上的蓝牙

转载 作者:IT老高 更新时间:2023-10-28 13:06:28 26 4
gpt4 key购买 nike

目前,我正在尝试在我的 Nexus 7(2012)上打开蓝牙套接字时处理一个奇怪的异常,使用 Android 4.3(构建 JWR66Y,我猜是第二个 4.3 更新)。我看过一些相关的帖子(例如 https://stackoverflow.com/questions/13648373/bluetoothsocket-connect-throwing-exception-read-failed ),但似乎没有一个为这个问题提供解决方法。此外,正如这些线程中所建议的那样,重新配对并没有帮助,并且不断尝试连接(通过愚蠢的循环)也没有任何效果。

我正在处理一个嵌入式设备(一个不知名的 OBD-II 车载适配器,类似于 http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE-LIGHTS-WITH-YOUR-PHONE-Oceanside.jpg)。我的 Android 2.3.7 手机连接没有任何问题,同事的 Xperia(Android 4.1.2)也可以。另一个 Google Nexus(我不知道是“One”还是“S”,但不是“4”)在 Android 4.3 上也失败了。

这是连接建立的 fragment 。它在自己的线程中运行,在服务中创建。

private class ConnectThread extends Thread {

private static final UUID EMBEDDED_BOARD_SPP = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");

private BluetoothAdapter adapter;
private boolean secure;
private BluetoothDevice device;
private List<UUID> uuidCandidates;
private int candidate;
protected boolean started;

public ConnectThread(BluetoothDevice device, boolean secure) {
logger.info("initiliasing connection to device "+device.getName() +" / "+ device.getAddress());
adapter = BluetoothAdapter.getDefaultAdapter();
this.secure = secure;
this.device = device;

setName("BluetoothConnectThread");

if (!startQueryingForUUIDs()) {
this.uuidCandidates = Collections.singletonList(EMBEDDED_BOARD_SPP);
this.start();
} else{
logger.info("Using UUID discovery mechanism.");
}
/*
* it will start upon the broadcast receive otherwise
*/
}

private boolean startQueryingForUUIDs() {
Class<?> cl = BluetoothDevice.class;

Class<?>[] par = {};
Method fetchUuidsWithSdpMethod;
try {
fetchUuidsWithSdpMethod = cl.getMethod("fetchUuidsWithSdp", par);
} catch (NoSuchMethodException e) {
logger.warn(e.getMessage());
return false;
}

Object[] args = {};
try {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID");

uuidCandidates = new ArrayList<UUID>();
for (Parcelable uuid : uuidExtra) {
uuidCandidates.add(UUID.fromString(uuid.toString()));
}

synchronized (ConnectThread.this) {
if (!ConnectThread.this.started) {
ConnectThread.this.start();
ConnectThread.this.started = true;
unregisterReceiver(this);
}

}
}

};
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
registerReceiver(receiver, new IntentFilter("android.bluetooth.device.action.UUID"));

fetchUuidsWithSdpMethod.invoke(device, args);
} catch (IllegalArgumentException e) {
logger.warn(e.getMessage());
return false;
} catch (IllegalAccessException e) {
logger.warn(e.getMessage());
return false;
} catch (InvocationTargetException e) {
logger.warn(e.getMessage());
return false;
}

return true;
}

public void run() {
boolean success = false;
while (selectSocket()) {

if (bluetoothSocket == null) {
logger.warn("Socket is null! Cancelling!");
deviceDisconnected();
openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
}

// Always cancel discovery because it will slow down a connection
adapter.cancelDiscovery();

// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
bluetoothSocket.connect();
success = true;
break;

} catch (IOException e) {
// Close the socket
try {
shutdownSocket();
} catch (IOException e2) {
logger.warn(e2.getMessage(), e2);
}
}
}

if (success) {
deviceConnected();
} else {
deviceDisconnected();
openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
}
}

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

BluetoothSocket tmp;
UUID uuid = uuidCandidates.get(candidate++);
logger.info("Attempting to connect to SDP "+ uuid);
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
uuid);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
uuid);
}
bluetoothSocket = tmp;
return true;
} catch (IOException e) {
logger.warn(e.getMessage() ,e);
}

return false;
}

}

代码在 bluetoothSocket.connect() 处失败。我收到 java.io.IOException: 读取失败,套接字可能已关闭,读取 ret: -1。这是 GitHub 上的相应来源:https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504它通过readInt()调用,从https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319调用

使用的套接字的一些元数据转储导致以下信息。这些在 Nexus 7 和我的 2.3.7 手机上完全相同。

Bluetooth Device 'OBDII'
Address: 11:22:33:DD:EE:FF
Bond state: 12 (bonded)
Type: 1
Class major version: 7936
Class minor version: 7936
Class Contents: 0
Contents: 0

我还有一些其他的 OBD-II 适配器(更扩展的),它们都可以工作。有没有可能我遗漏了什么或者这可能是 Android 中的错误?

最佳答案

我终于找到了解决方法。魔法隐藏在 BluetoothDevice 类的底层(参见 https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037)。

现在,当我收到该异常时,我会实例化一个备用 BluetoothSocket,类似于下面的源代码。如您所见,通过反射调用隐藏方法 createRfcommSocket。我不知道为什么隐藏此方法。源代码将其定义为 public 虽然...

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() 然后不再失败。我仍然遇到了一些问题。基本上,这有时会阻塞并失败。在这种情况下,重新启动 SPP 设备(关闭/插入)会有所帮助。有时,即使设备已经绑定(bind),我也会在 connect() 之后收到另一个配对请求。

更新:

这是一个完整的类,包含一些嵌套类。对于真正的实现,这些可以作为单独的类进行。

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);
}

}
}

关于android - IOException : read failed, 套接字可能已关闭 - Android 4.3 上的蓝牙,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18657427/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com