4

My application worked fine under Android 2.3.3 to 4.1.2, but since Android 4.2.2 and Android 4.3, I have a

fatal signal 11 (SIGSEGV) at 0x00....

when I close the bluetooth socket.

I've searching trough a lot of forums, and the main response is that the

BluetoothSocket.close();

is called from two different thread at the same time, but it's not the case in my code.

I'm using Samsung Galaxy Note 2 under A4.1.2 (works ok) and Nexus 4 for A4.2.2 and 4.3.

Thank you in advance for your suggestions !

EDIT 1 : here are the 2 threads that manipulate the Bluetooth socket.

the first :

    /**
 * This thread runs while attempting to make an outgoing connection with a
 * device. It runs straight through; the connection either succeeds or
 * fails.
 */
private class ConnectThread extends Thread {        
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    //private final UUID MY_UUID = java.util.UUID.randomUUID();

    public ConnectThread(BluetoothDevice device) {
        if(D) Log.d(TAG, "/S4B/ start connectThread ");
        mmDevice = device;
        BluetoothSocket connection = null;


        // Get a BluetoothSocket for a connection with the given BluetoothDevice
        try {
            if(D) Log.i(TAG,"/S4B/ Create RF Socket");
            Method m = device.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
            connection = (BluetoothSocket) m.invoke(device, 1);
            //connection = device.createRfcommSocketToServiceRecord(MY_UUID);
            Utils.pause(100);
        } catch (Exception e) {
            Log.e(TAG, "/S4B/ create() failed", e);
        }
        mmSocket = connection;
        if(D) Log.i(TAG,"/S4B/ Socket initialized");
    }

    public void run() {
        if(D) Log.i(TAG, "/S4B/ BEGIN mConnectThread");
        setName("ConnectThread");

        if (mmSocket != null) {
            // Always cancel discovery because it will slow down a connection
            if(mAdapter.isDiscovering()){   
                mAdapter.cancelDiscovery();
            }

            // Make a connection to the BluetoothSocket
            try {
                // This is a blocking call and will only return on a successful connection or an exception
                if(D) Log.i(TAG,"/S4B/ Start socket connection");
                mmSocket.connect();
                if(D) Log.i(TAG,"/S4B/ End of socket connection");
            } catch (Exception e) {
                Log.e(TAG, "/S4B/ socket connect failed", e);

                // Close the socket
                try {
                    mmSocket.close();
                    if(D) Log.i(TAG,"/S4B/ close socket");

                } catch (IOException e2) {
                    Log.e(TAG,"/S4B/ unable to close() socket during connection failure",e2);
                }
                //Turn off the bluetooth - the Bluetooth STATE_OFF Broadcast will be received in welcome.class
                connectionFailed();
                return;
            }

            // Reset the ConnectThread because we're done
            synchronized (BluetoothConnectionService.this) {
                mConnectThread = null;
            }

            // Start the connected thread
            connected(mmSocket, mmDevice);
        } else {
            BluetoothConnectionService.this.start();
            connectionFailed();
        }
    }

    public void cancel() {
        try {
            if (mmSocket != null) {
                mmSocket.close();
            }
        } catch (IOException e) {
            Log.e(TAG, "/S4B/ close() of connect socket failed", e);
        }
    }
}

and the second :

    /**
 * This thread runs during a connection with a remote device. It handles all
 * incoming and outgoing transmissions.
 */
private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final DataInputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket) {
        Log.d(TAG, "/S4B/ Create ConnectedThread");
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the BluetoothSocket input and output streams
        try {
            if(D) Log.i(TAG,"/S4B/ Get input and output stream");
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
            isConnected = true;
        } catch (IOException e) {
            Log.e(TAG, "/S4B/ Temp sockets not created", e);
            isConnected = false;
        }

        mmInStream = new DataInputStream(tmpIn);
        mmOutStream = tmpOut;
    }

    public void run() {
        setName("ConnectedThread");
        Log.i(TAG, "/S4B/ BEGIN mConnectedThread");

        while (isConnected) {
            Utils.pause(50);
            isConnected = checkConnection();
        }

    }

    /**
     * Check if the connection is still alive
     * 
     * @return true or false
     */
    private boolean checkConnection() {
        synchronized (mmInStream) {
            try {
                int len = mmInStream.available();
                if (len > 0) {// Checks the available amount
                    byte b[] = new byte[len];
                    if(D) Log.i(TAG,"/S4B/ start mmInStream readFully");
                    mmInStream.readFully(b, 0, len);
                    mHandler.obtainMessage(MESSAGE_READ, len, -1, b).sendToTarget();
                }

                return true;

            } catch (IOException ioe) {
                Log.e(TAG, "/S4B/ check connection, disconnected", ioe);
                connectionLost();
                return false; // Connection is lost.
            }
        }
    }

    /**
     * Write to the connected OutStream.
     * 
     * @param buffer
     *            The bytes to write
     */
    public void write(byte[] buffer) {
        try {
            mmOutStream.write(buffer);
        } catch (IOException e) {
            Log.e(TAG, "/S4B/ Exception during write", e);
            connectionLost();
            return;
        }
        // Share the sent message back to the UI Activity
        mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
    }

    public void cancel() {
        try {
            mmSocket.close();
            Utils.pause(1000);
        } catch (IOException e) {

            Log.e(TAG, "/S4B/ close() of connect socket failed", e);
        }
    }
}

EDIT 2 : I tried to use only one thread to be sure that there is no access in parrallel to

BluetoothSocket

but the result is exactly the same. As soon as I call

BluetoothSocket.close();

I get the fatal signal 11 and the app crashes.

Laurent
  • 1,710
  • 4
  • 25
  • 46
  • Do you have access to the Threads, which manipulate the socket OR can you know where is it manipulated? – g00dy Aug 09 '13 at 13:38
  • Yes, I have access to the two threads which manipulate the BluetoothSocket. They are both private threads created in the class I use for Bluetooth connection management. – Laurent Aug 09 '13 at 13:39
  • Then maybe you should synchronize them too. They might be off the UI thread, but have access to common resources. Make them chech the progress of each other in order to avoid such collisions or Prepare a third Thread, which will serve only to monitor those two previous Threads and will do the management of the resources that they use. – g00dy Aug 09 '13 at 13:43
  • I've checked with Eclipse DDMS threads monitoring, and they never run in parallel. The ConnectedThread starts only after the ConnectThread is stoped. – Laurent Aug 09 '13 at 13:45
  • Can you estimate the execution time of this: `BluetoothSocket.close()` and then compare it to the timeframe between the end of the execution of Thread 1 and the Beginning-END execution of Thread2 ? – g00dy Aug 09 '13 at 13:46
  • In my actual scenario, I don't even call `BluetoothSocket.close();` in the first thread. I only call it on the second thread. Do you think they may be a conflict between other manipulations on the `BluetoothSocket`? And why didn't I have this issue with earlier version of Android ? Thx for your help ! :) – Laurent Aug 09 '13 at 13:54
  • This depends from the way Android interpret this and how it manages the socket. Whichever it is, I think that the lifecycle of the socket should be manipulated only by one side. – g00dy Aug 09 '13 at 14:03
  • I tried to merge the two Threads to works sequencially, but the result is the same. When I call `BluetoothSocket.close();` the app crashes... – Laurent Aug 09 '13 at 14:42
  • There's actually a bug logged here-> https://code.google.com/p/android/issues/detail?id=10551 . The official statement is : Bluetooth support was fully re-engineered for Android 4.2. Issues that existed on older versions probably don't exist any more. If this issue still exists on Android 4.2 or newer, please submit a separate report. **However** I've found a workaround this maybe - http://stackoverflow.com/questions/14280623/android-bluetooth-connection-doesnt-close-after-application-crash . – g00dy Aug 09 '13 at 14:46
  • Thx again for your help, but I can't see how this workaround could work in my case ? (maybe I did not understand it correctly). In his case, the problem is that the application close but the bluetooth socket is still open. So he catch the "uncaught exception" and close the socket in there. In my case, I have a crash when I close the socket. I'm not even sure than I can caught it with "UncaughtExceptionHandler" as long as there is no thrown exception... – Laurent Aug 12 '13 at 07:20
  • Well, I think you'll hav to try to catchit, otherwize (if not possible), then you'll have to submit the information in the bug report (the link I pasted before), since it was stated as "fixed" there for 4.2 and above. – g00dy Aug 12 '13 at 07:26
  • Any idea how to catch `fatal signal 11`error ? :( – Laurent Aug 12 '13 at 08:14
  • Well, that's one of the toughest problems actually. It meant segmentation violation. Those problems are catchable with a debugger, so you'll have to try manually this time or before that, try creating an "UncaughtExceptionHandler", like explained in the link I pasted, if you fail to catch it, you'll have to debug and when the error occurs print the backtrace of it. There's no other way around this :( – g00dy Aug 12 '13 at 08:22
  • I played a lot with the code, tried everything that cross my mind, and now, the fatal signal appear when I open the socket for the second time. It's like that : I connect to the socket -> ok, I close the socket -> ok, I reconnect to the socket -> crash o_O – Laurent Aug 12 '13 at 13:09
  • Ok, I understand all this, but did you try debugging it and printing the stack trace. This isn't something which can be blindly guessed, you'll hav to debug and get all the info available :( – g00dy Aug 12 '13 at 13:19
  • Yes, I only try "solution" in debug. Now I have the 2 following lines before the `fatal signal 11` : `BluetoothAdapter - geBluetoothService() called with no BluetoothManagerCallback`and `BluetoothSocket - connect(), SocketState: INIT, mPfd: {ParcelFileDescriptior: FileDescriptor[45]`... but it doesn't help me that far... – Laurent Aug 12 '13 at 13:26
  • 1
    Read through this and return here with the results -> http://stackoverflow.com/questions/1083154/how-can-i-catch-sigsegv-segmentation-fault-and-get-a-stack-trace-under-jni-on. I know i'm being anoying, but so is the problem too. :( – g00dy Aug 12 '13 at 13:36
  • haha, you're not anoying at all ! You're helping me !!! thx ;) – Laurent Aug 12 '13 at 13:38
  • I'm most probably more anoying than you, but the first line of the answer is : **Edit: From Jelly Bean onwards you can't get the stack trace, because READ_LOGS went away. :-(** Is it still relevant to go through the process ? – Laurent Aug 12 '13 at 13:41
  • **READ_LOGS went away** - you got that right, but this Manifest permission is for an application, which is compiled up to the `.apk` stage, which simply means, that you can't make an application which is a `LogCat` application (e.g. to read your system logs runtime and from an application). In your case- you got the LogCat in the Eclipse - so you're ok there :) and most importantly - you don't need this permission to look at the LogCat, when you're debugging, this will not make **any** sense whasoever. – g00dy Aug 12 '13 at 14:10

3 Answers3

7

I ran into this problem as well. However, for me close() was not the cause. The problem was accessing the socket after close(). Specifically, the call to available() on the socket's inputstream after the socket was closed caused the segfault.

Jawa
  • 2,336
  • 6
  • 34
  • 39
markrileybot
  • 86
  • 1
  • 2
  • Thanks a lot @markrileybot for your answer.. This solved my problem in Grand 2 device with Android 4.4.2 version.. I have added more details in my answer http://stackoverflow.com/a/29529974/1994950 and mentioned your help.. thank you again – Kushal Apr 09 '15 at 04:48
5

I had the exact same problem. It helped to me before closing socket call

mConnectedThread.interrupt()

from outer class, and to ConnectedThread run() method add

public void run() {
    ...
    while (condition) {
        if (isInterrupted())
            return;
        ...
    }
    ...
}

to make sure thread doesn't read anything from socket's stream. After that you could call mmSocket.close()

grayfox
  • 51
  • 1
  • 4
4

I faced same problem with Android 4.4.2 in Galaxy Grand 2 device

I fixed the problem with help of answer given by @markrileybot answer

I was accessing the socket.available() method after close() call is done by my code.

To add more to @markrileybot answer :

I had also added condition before calling socket.close() :

public void cancel() {
    try {
        if(mmSocket.isConnected())    // this is condition
        mmSocket.close();
        Utils.pause(1000);
    } catch (IOException e) {

        Log.e(TAG, "/S4B/ close() of connect socket failed", e);
    }
}

1 If you are sharing same socket between multiple threads, then this condition should be added which will prevent calling close() if socket is already closed (not connected)

2 Before calling socket.available() or socket.write(), we should check socket.isConnected() and if it returns true then only we should process further

Community
  • 1
  • 1
Kushal
  • 8,100
  • 9
  • 63
  • 82