La conexión al dispositivo Bluetooth falla en el sueño profundo

Estoy intentando conectarme a un dispositivo Bluetooth emparejado cada 25 segundos, progtwigdo a través de AlarmManager que activa un WakefulBroadcastReceiver para iniciar un servicio para hacer la conexión. Una vez que el dispositivo se pone en reposo, todo funciona bien durante las primeras horas, pero comienza a fallar después de aproximadamente 4-5 horas, cuando asumo que el dispositivo entra en un sueño profundo .

Obtengo una NullPointerException de ParcelFileDescriptor, que indica que “FileDescriptor no debe ser nulo”. He intentado buscar este error e incluso he revisado el código en ParcelFileDescriptor.java, pero estoy en un callejón sin salida. Estoy ejecutando esto en un Nexus 10, con Android 4.4.2. El código que intenta conectarse es el siguiente:

public GatewaySocket getSocket() throws IOException { if (!BluetoothAdapter.checkBluetoothAddress(macAddress)) return new GatewaySocket("Address " + macAddress + " is not a valid Bluetooth MAC Address"); BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter(); if (bluetooth == null) return new GatewaySocket("Sorry, no Bluetooth adapter available"); BluetoothDevice device = bluetooth.getRemoteDevice(macAddress); BluetoothSocket btSocket = null; try { btSocket = device.createRfcommSocketToServiceRecord(uuid); } catch (Exception e) { log(3, "" + this, "Error closing socket on connection: " + e); } if (btSocket == null) return new GatewaySocket("Unable to launch insecure connection to " + device); try { btSocket.connect(); } catch (IOException ex) { try { btSocket.close(); } catch (IOException ex2) { // do nothing } throw (ex); } GatewaySocket socket = new GatewaySocket(btSocket, btSocket.getInputStream(), btSocket.getOutputStream()); return socket; } 

GatewaySocket es una subclase delgada de BluetoothSocket. El error se produce en la línea btSocket.connect (), con el siguiente seguimiento de stack:

 01-10 09:13:57.796: W/BluetoothAdapter(3591): getBluetoothService() called with no BluetoothManagerCallback 01-10 09:13:57.801: D/BTIF_SOCK(979): service_uuid: 00001101-0000-1000-8000-00805f9b34fb 01-10 09:13:57.801: E/bt-btif(979): SOCK_THREAD_FD_RD signaled when rfc is not connected, slot id:4374, channel:-1 01-10 09:13:57.801: W/System.err(3591): java.lang.NullPointerException: FileDescriptor must not be null 01-10 09:13:57.806: W/System.err(3591): at android.os.ParcelFileDescriptor.(ParcelFileDescriptor.java:174) 01-10 09:13:57.806: W/System.err(3591): at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:905) 01-10 09:13:57.806: W/System.err(3591): at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:897) 01-10 09:13:57.806: W/System.err(3591): at android.bluetooth.IBluetooth$Stub$Proxy.connectSocket(IBluetooth.java:1322) 01-10 09:13:57.806: W/System.err(3591): at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:308) 01-10 09:13:57.806: W/System.err(3591): at com.gateway.service.AndroidGMConversation.getSocket(AndroidGMConversation.java:162) 01-10 09:13:57.806: W/System.err(3591): at com.gateway.GatewayManagerConversation.converse(GatewayManagerConversation.java:81) 01-10 09:13:57.806: W/System.err(3591): at com.gateway.GatewayManagerConversation.run(GatewayManagerConversation.java:72) 01-10 09:13:57.806: W/System.err(3591): at java.lang.Thread.run(Thread.java:841) 01-10 09:13:57.806: V/PS(3591): Finished with device 06:92:25:0A:A5:50 

¡Cualquier sugerencia sera apreciada!

Encontré la solución después de pasar por las clases de la biblioteca de Bluetooth y descubrí que no cierra el FileDescriptor al llamar a bluetoothsocket.close(); a pesar de que llama al método dispatch() sobre FileDescriptor, que no lo cierra.

Simplemente llame a este método antes de bluetoothsocket.close();

 private synchronized void clearFileDescriptor(){ try{ Field field = BluetoothSocket.class.getDeclaredField("mPfd"); field.setAccessible(true); ParcelFileDescriptor mPfd = (ParcelFileDescriptor)field.get(socket); if(null == mPfd){ return; } mPfd.close(); }catch(Exception e){ Log.w(SensorTicker.TAG, "LocalSocket could not be cleanly closed."); } } 

Espero que esto resolverá el problema de otros también. Pero debe ser manejado por la clase BluetoothSocket sobre el método de cierre.

Esto se parece al error BluetoothSocket.close () en Android 4.2 – 4.4.4, que parece estar arreglado en 5.0. Básicamente, no está liberando el descriptor de archivo subyacente, por lo que se filtra hasta que alcanza el límite de su dispositivo, y luego suceden cosas extrañas. Debe obtener el ParcelFileDescriptor desde el BluetoothSocket y cerrarlo usted mismo.

Echa un vistazo a mi respuesta aquí para el código de solución: https://stackoverflow.com/a/27873675/1893015