目前,我正在尝试使用 Android 4.3(构建 JWR66Y,我猜是第二个 4.3 更新)在我的 Nexus 7(2012)上打开 BluetoothSocket 时处理一个奇怪的异常。我看过一些相关的帖子(例如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-灯 - 用你的手机 - Oceanside.jpg)。我的 Android 2.3.7 手机连接没有任何问题,同事的 Xperia(Android 4.1.2)也可以。另一个 Google Nexus(我不知道是“One”还是“S”,但不是“4”)在 Android 4.3 上也失败了。
这是连接建立的片段。它在自己的线程中运行,在服务中创建。
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: read failed, socket might closed, read 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 中的错误?

