Android connection failed after 489 successful connections

Unfortunately, I have some problems with my Android phone. For my test environment, I am using Nexus 4 with Android 4.4.2.

I have a Java application on my PC that uses bluecove to connect SPP as a client. The program searches for a special service name and connects to my Android phone. Subsequently, it sends 72 bytes to my Android phone and waits for a response. When this response is received, the program sleeps for 3 seconds, and then starts again.

On my Android phone, I have an app with a bluetooth background listener that starts when it boots. This application is based on a demonstration of the BluetoothChat example. When receiving Bluetooth data, I check the incoming data and send a response.

Everything is working fine. But after 489 Bluetooth connections, the android application crashes with the following error fragment when the PC-java application is running:

getBluetoothService() called with no BluetoothManagerCallback Shutting down VM threadid=1: thread exiting with uncaught exception (group=0x41b34ba8) FATAL EXCEPTION: main Process: de.tum.lme.diamantum:remote_blue, PID: 21567 java.lang.NullPointerException: FileDescriptor must not be null at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:174) at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:905) at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:897) at android.bluetooth.IBluetooth$Stub$Proxy.createSocketChannel(IBluetooth.java:1355) at android.bluetooth.BluetoothSocket.bindListen(BluetoothSocket.java:349) at android.bluetooth.BluetoothAdapter.createNewRfcommSocketAndRecord(BluetoothAdapter.java:1055) at android.bluetooth.BluetoothAdapter.listenUsingRfcommWithServiceRecord(BluetoothAdapter.java:976) at com.test.btconn.BluetoothHandling$AcceptThread.<init>(BluetoothHandling.java:449) at com.test.btconn.BluetoothHandling.start(BluetoothHandling.java:216) at com.test.btconn.BluetoothListenerService.setupBtSockets(BluetoothListenerService.java:330) at com.test.btconn.BluetoothListenerService.manageBtState(BluetoothListenerService.java:249) at com.test.btconn.BluetoothListenerService.setBtStateDisconnected(BluetoothListenerService.java:383) at com.test.btconn.BluetoothListenerService.access$5(BluetoothListenerService.java:378) at com.test.btconn.BluetoothListenerService$2.handleMessage(BluetoothListenerService.java:421) 

Therefore, the application has problems with ParcelFileDescriptor, which is unexpectedly null. But why?

Everything described above also occurs when the pause time is changed on a PC-java application, using different data sizes for transferring and using different smartphones. Using the reflection "listenUsingRfcommWithServiceRecord" the same thing happens after 505 transfers. Also, using wakelock does not change anything.

By the way, I have the same behavior when using the BluetoothChat sample.

So, is there any hint of what's going on?

Update:

BluetoothServerSocket closes after each connection and BluetoothSocket if bluetooth status is 3.

+8
java android bluetooth spp
source share
4 answers

The problem is with the restriction of file descriptors on your device. There is a report for this problem.

When creating a Bluetooth socket, two new FDs will be received from the system fd new . It seems you are not closing your previous BT connections correctly, so the number of FDs used is constantly increasing until you reach the limit.

To avoid this, you will at least have to call close() on the BluetoothServerSocket, which you get from the call to listenUsingRfcommWithServiceRecord() after completing operations for it. You should also check if you are using other resources connected to the BT connection, and if possible, free them.


As suggested here, how to get the ParcelFileDescriptor BluetoothServerSocket to close. Beware: it can break things!

You need to access the mSocket field for BluetoothServerSocket to access the underlying BluetoothSocket. This BluetoothSocket contains the ParcelFileDescriptor in the mPfd field. And on this you can call close() . Since both fields are not visible, you will have to use Reflections:

 public void closePFD(BluetoothServerSocket closeMe) throws AllKindOfExceptionsThatYouHaveToHandle { Field mSocketFld = closeMe.getClass().getDeclaredField("mSocket"); mSocketFld.setAccessible(true); BluetoothSocket btsock = (BluetoothSocket)mSocketFld.get(closeMe); Field mPfdFld = btsock.getClass().getDeclaredField("mPfd"); mPfdFld.setAccessible(true); ParcelFileDescriptor pfd = (ParcelFileDescriptor)mPfdFld.get(btsock); pfd.close(); } 

This will close the BluetoothServerSocket. If you want to close only the BluetoothSocket from the BTServerSockets receiving method, you can leave the receiving part of mSocket as shown in jitain sharmas answer .

+14
source share

My solution for the question I asked:

 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, "ParcelFileDescriptor could not be cleanly closed."); } } 

So above is the method that I wrote to close the filedescriptor, and below when I used this code: Whenever the socket should be close:

 private synchronized void cleanClose() { if (socket != null) { try { clearFileDescriptor(); //clearLocalSocket(); socket.close(); } catch (IOException e) { Log.w(SensorTicker.TAG, "Socket could not be cleanly closed."); } } } 

I also tried using the clearLocalSocket () method, which I wrote but did not use for my problem. So I tried to close FileDescriptor. Hope this helps you and other people facing the same problem.

+4
source share

This is the BluetoothSocket.close () error in Android 4.2 - 4.4.4 (and 4.4w and L Preview) ... Internally, it calls mPfd.detachFd () and then does not actually release the base file descriptor. The fix is ​​to call mPfd.close () instead and set mPfd = null, which is exactly what Android 5.0 does.

You can basically fix this with other solutions posted here that call mPfd.close () and then call your BluetoothSocket.close () platform, but I found that this is not enough for me, and some strange things can happen things. I went a little further and then first flushed mSocket and set it to zero, then called mPfd.close () and set that to zero, and finally called BluetoothSocket.close (), which is needed to install mSocketState.

 public static void cleanClose(BluetoothSocket btSocket) { if(btSocket == null) return; if(Build.VERSION.SDK_INT >= 17 && Build.VERSION.SDK_INT <= 20) { try { cleanCloseFix(btSocket); } catch (Exception e) { Log.d(sLogName, "Exception during BluetoothSocket close bug fix: " + e.toString()); } //Go on to call BluetoothSocket.close() too, because our code didn't do quite everything } //Call BluetoothSocket.close() try { btSocket.close(); } catch (Exception e) { Log.d(sLogName, "Exception during BluetoothSocket close: " + e.toString()); } } private static void cleanCloseFix(BluetoothSocket btSocket) throws IOException { synchronized(btSocket) { Field socketField = null; LocalSocket mSocket = null; try { socketField = btSocket.getClass().getDeclaredField("mSocket"); socketField.setAccessible(true); mSocket = (LocalSocket)socketField.get(btSocket); } catch(Exception e) { Log.d(sLogName, "Exception getting mSocket in cleanCloseFix(): " + e.toString()); } if(mSocket != null) { mSocket.shutdownInput(); mSocket.shutdownOutput(); mSocket.close(); mSocket = null; try { socketField.set(btSocket, mSocket); } catch(Exception e) { Log.d(sLogName, "Exception setting mSocket = null in cleanCloseFix(): " + e.toString()); } } Field pfdField = null; ParcelFileDescriptor mPfd = null; try { pfdField = btSocket.getClass().getDeclaredField("mPfd"); pfdField.setAccessible(true); mPfd = (ParcelFileDescriptor)pfdField.get(btSocket); } catch(Exception e) { Log.d(sLogName, "Exception getting mPfd in cleanCloseFix(): " + e.toString()); } if(mPfd != null) { mPfd.close(); mPfd = null; try { pfdField.set(btSocket, mPfd); } catch(Exception e) { Log.d(sLogName, "Exception setting mPfd = null in cleanCloseFix(): " + e.toString()); } } } //synchronized } 
+1
source share

If you use bluetooth as the server in your application, I have faced the same problem as this one, except for my problem. I get null in the mPfd file descriptor when I reflect. I was able to close the file using this method, hope this can help.

I get the file via id / index from LoaclSocket to BluetoothSocket using ParceFileDescriptor. int mfd = 0; Field socketField = null; LocalSocket mSocket = null;

  try { socketField = btSocket.getClass().getDeclaredField("mSocket"); socketField.setAccessible(true); mSocket = (LocalSocket)socketField.get(btSocket); } catch(Exception e) { Log ( "Exception getting mSocket in cleanCloseFix(): " + e.toString()); } if(mSocket != null) { FileDescriptor fileDescriptor = mSocket.getFileDescriptor(); String in = fileDescriptor.toString(); //regular expression to get filedescriptor index id Pattern p = Pattern.compile("\\[(.*?)\\]"); Matcher m = p.matcher(in); while(m.find()) { Log ( "File Descriptor " + m.group(1)); mfd = Integer.parseInt(m.group(1)); break; } //Shutdown the socket properly mSocket.shutdownInput(); mSocket.shutdownOutput(); mSocket.close(); mSocket = null; try { socketField.set(btSocket, mSocket); } catch(Exception e) { Log ("Exception setting mSocket = null in cleanCloseFix(): " + e.toString()); } //Close the file descriptor when we have it from the Local Socket try { ParcelFileDescriptor parcelFileDescriptor = ParcelFileDescriptor.adoptFd(mfd); if (parcelFileDescriptor != null) { parcelFileDescriptor.close(); Log ( "File descriptor close succeed : FD = " + mfd); } } catch (Exception ex) { Log ( "File descriptor close exception " + ex.getMessage()); } } 
0
source share

All Articles