Lorteld
Lorteld

Reputation: 153

BluetoothChat app crashes upon onDestroy() in Android 4.4

I have developed a Bluetooth application which communicates with a serial port device and so far the communication (starting the connection, data exchange and terminating the thread) works fine.

However, I encountered a strange problem with Bluetooth connection while testing on Nexus 4 (Android 4.4.2). When I exit the app with a back button, onDestroy() fires as per normal but the app crashes with an error message "Unfortunately, has stopped."

I checked the log and there is no crash point. the following error shown

"01-29 16:57:11.372: A/libc(8684): Fatal signal 11 (SIGSEGV) at 0x00000008 (code=1), thread 8775 (Thread-327)"

`, followed by a very long debug stack trace.

I tried to use the sample Bluetooth app from Android developer website to test whether it is my own implementation issue, and the same crashing issue happens.

<!---- code -->
@Override
public void onDestroy() {
super.onDestroy();
// Stop the Bluetooth chat services
if (mChatService != null) mChatService.stop();
if(D) Log.e(TAG, "--- ON DESTROY ---");
}

In BluetoothChatService.java, this is the code for stop().

/**
 * Stop all threads
 */
public synchronized void stop() {
    if (D) Log.d(TAG, "stop");

    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    if (mSecureAcceptThread != null) {
        mSecureAcceptThread.cancel();
        mSecureAcceptThread = null;
    }

    if (mInsecureAcceptThread != null) {
        mInsecureAcceptThread.cancel();
        mInsecureAcceptThread = null;
    }
    setState(STATE_NONE);
}

This does not occur for Android 4.2.1 (Galaxy Nexus) and Android 4.3 (Samsung S4).

Any idea how to fix this? If it is a Android bug, is there any workaround for it?

Many thanks in advance.

Upvotes: 2

Views: 1572

Answers (3)

Ahassanein
Ahassanein

Reputation: 26

The problem is that your app attempts to access the socket after close(). Specifically, the call to available() on the socket's inputstream after the socket was closed causes the segfault. It helped me to make sure that the thread doesn't read anything from socket's stream. After that you could call mmSocket.close(). Basically, interrupt your thread before closing it and have your thread listen to the interrupt.

change your stop() method to the following:

public synchronized void stop() {
    if (D) Log.d(TAG, "stop");

   /* if (mConnectedThread.mmSocket.isConnected()){
        mConnectedThread.interrupt();
        mConnectThread.cancel();

    }*/

    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mConnectedThread != null) {
        mConnectedThread.interrupt();
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    if (mSecureAcceptThread != null) {
        mSecureAcceptThread.cancel();
        mSecureAcceptThread = null;
    }

    setState(STATE_NONE);
}

and to your ConnectedThread run() method add the following snippet of code:

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

Hope this helps! :)

Upvotes: 1

niky_d
niky_d

Reputation: 81

Try this: in the mConnectedThread class, make a flag like

private boolean stopThread = false;

and then in the run() method change the loop:

while (true) {...

into

while (!stopThread) {...

and then add this into the cancel() method:

stopThread = true;
try {
    mmSocket.close();
} catch ...

This should take care of your problem, don't know why they went with an infinite loop in the first place, because the cancel method will be called when it has to be called...

Hope this helps :).

Upvotes: 3

SunGa
SunGa

Reputation: 231

The source for this crash is null pointer exception at

private final void setStatus(int resId) {
    final ActionBar actionBar = getActionBar();
    actionBar.setSubtitle(resId);
}

but this occurs only when onDestroy() callback is being served. (BTW this call back occurs due to back button i.e. onPause(), followed by onStop(), followed by onDestroy().

I found 2 ways to handle this situation. 1) In BluetoothChat.java replace the code

private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MESSAGE_STATE_CHANGE:
            if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
            switch (msg.arg1) {
            case BluetoothChatService.STATE_CONNECTED:
                setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
                mConversationArrayAdapter.clear();
                break;
            case BluetoothChatService.STATE_CONNECTING:
                setStatus(R.string.title_connecting);
                break;
            case BluetoothChatService.STATE_LISTEN:
            case BluetoothChatService.STATE_NONE:
                setStatus(R.string.title_not_connected);
                break;
            }
            break;

by

private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MESSAGE_STATE_CHANGE:
            if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
            switch (msg.arg1) {
            case BluetoothChatService.STATE_CONNECTED:
                setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
                mConversationArrayAdapter.clear();
                break;
            case BluetoothChatService.STATE_CONNECTING:
                setStatus(R.string.title_connecting);
                break;
            case BluetoothChatService.STATE_LISTEN:
                setStatus(R.string.title_not_connected);
                break;
            case BluetoothChatService.STATE_NONE:
                //setStatus(R.string.title_not_connected);
                break;
            }
            break;

2) The other way is to shift the code

// Stop the Bluetooth chat services
if (mChatService != null) mChatService.stop();

from onDestroy() to onPause() call back function.

I am running my application on Android 4.2.2 therefore not sure if above solution is applicable for android 4.4.

Added The app also crash after change in screen orientation. To overcome this I have adopted portrait orientation for my app through Android Manifest file. But better solution may be possible with use of onSaveInstanceState(bundle).

Upvotes: 0

Related Questions