title: IOException: read failed, socket might closed - Bluetooth on Android 4.3
body: <p>Currently I am trying to deal with a strange Exception when opening a BluetoothSocket on my Nexus 7 (2012), with Android 4.3 (Build JWR66Y, I guess the second 4.3 update). I have seen some related postings (e.g. <a href="https://stackoverflow.com/questions/13648373/bluetoothsocket-connect-throwing-exception-read-failed" title="another SO questionquot;">https://stackoverflow.com/questions/13648373/bluetoothsocket-connect-throwing-exception-read-failed</a>), but none seems to provide a workaround for this issue. Also, as suggested in these threads, re-pairing does not help, and constantly trying to connect (through a stupid loop) also has no effect.</p>
  
  <p>I am dealing with an embedded device (a noname OBD-II car adapter, similar to <a href="http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE-LIGHTS-WITH-YOUR-PHONE-Oceanside.jpg" rel="noreferrer" title="these">http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE-LIGHTS-WITH-YOUR-PHONE-Oceanside.jpg</a>). My Android 2.3.7 phone does not have any issues connecting, and the Xperia of a colleague (Android 4.1.2) also works. Another Google Nexus (I dont know if 'One' or 'S', but not '4') also fails with Android 4.3.</p>
  
  <p>Here is the Snippet of the connection establishment. It is running in its own Thread, created within a Service.</p>
  
  <pre><code>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&lt;UUID&gt; 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&lt;?&gt; cl = BluetoothDevice.class;
  
          Class&lt;?&gt;[] 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&lt;UUID&gt;();
                      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 &gt;= 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;
      }
  
  }
  </code></pre>
  
  <p>The code is failing at <code>bluetoothSocket.connect()</code>. I am getting a <code>java.io.IOException: read failed, socket might closed, read ret: -1</code>. This is the corresponding source at GitHub: <a href="https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504" rel="noreferrer" title="BluetoothSocket.java#L504">https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504</a>
  Its called through readInt(), called from <a href="https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319" rel="noreferrer" title="BluetoothSocket.java#L319">https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319</a></p>
  
  <p>Some metadata dump of the used socket resulted in the following information. These are exactly the same on Nexus 7 and my 2.3.7 phone.</p>
  
  <pre><code>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
  </code></pre>
  
  <p>I have some other OBD-II adapters (more expansives) and they all work. Is there any chance, that I am missing something or might this be a bug in Android?</p>