Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android bluetooth connection fails after 489 successful connections

unfortunately, I have some problems with android's bluetooth. For my test environment I use a Nexus 4 with Android 4.4.2.

I have a Java Application on my PC, which uses bluecove in order to make a SPP connection as client. The programme is looking for a special service name and connects with my android phone. Afterwards it sends 72 bytes to my android phone and waits for an answer. When getting that answer the programme sleeps for 3 seconds and than starts again.

On my android phone I have an application with background bluetooth listener which starts at boot. This application is based on BluetoothChat sample demo. When receiving bluetooth data I check incoming data and send back an answer.

All that is working fine. But after 489 bluetooth connections the android app fails with following error snippet while PC-java-app is going on:

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)

So the app has a problem with the ParcelFileDescriptor, which is suddenly null. But why?

All the described above also happens when changing pause-time on PC-java-app, using various data sizes for transmitting and using different smartphones. When using reflection "listenUsingRfcommWithServiceRecord" the same happens after 505 transmissions. Also using wakelock changes nothing.

By the way, I got the same behaviour when using BluetoothChat sample.

So, has anybody a hint, what happens?

Update:

BluetoothServerSocket is closed after each connection and BluetoothSocket if bluetooth state is 3.

like image 768
user3073364 Avatar asked Feb 25 '14 17:02

user3073364


2 Answers

The problem seems connected to the limit of file descriptors on your device. There is a report for that issue here

During the creation of a Bluetooth socket a new fd is two new FDs are acquired from the system. It seems you are not closing your previous BT connections correctly so the number of used FDs steadily increases until you hit the limit.

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


As it was requested here is how to force the closing of the ParcelFileDescriptor of the BluetoothServerSocket. Beware: it may break things!

You will have to access the mSocket field of the BluetoothServerSocket to access the underlying BluetoothSocket. This BluetoothSocket holds the ParcelFileDescriptor in the field mPfd. And on that you can call close(). As 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 just the BluetoothSocket from the BTServerSockets accept method you can leave out the part of getting mSocket as seen in jitain sharmas answer.

like image 178
Dawnkeeper Avatar answered Nov 15 '22 20:11

Dawnkeeper


My fix for the question i have 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 i have written to close the filedescriptor, and the below when i have used this code: Whenever, socket has to 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 have also tried with the clearLocalSocket() method i have written, but no used for my problem. So i tried to close the FileDescriptor. Hope it will help you and others facing the same issue.

like image 34
jitain sharma Avatar answered Nov 15 '22 21:11

jitain sharma