Фатальный сигнал 11 SIGSEGV при закрытии BluetoothSocket на Android 4.2.2 и 4.3

Мое приложение работало нормально под Android 2.3.3 до 4.1.2, но, начиная с Android 4.2.2 и Android 4.3, у меня есть

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

когда я закрываю разъем Bluetooth.

Я искал через много форумов, и основной ответ заключается в том, что

BluetoothSocket.close();

вызывается из двух разных потоков одновременно, но в моем коде это не так.

Я использую Samsung Galaxy Note 2 под A4.1.2 (работает нормально) и Nexus 4 для A4.2.2 и 4.3.

Заранее спасибо за ваши предложения!

РЕДАКТИРОВАТЬ 1: вот два потока, которые управляют разъемом Bluetooth.

первый:

    /**
 * 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);
        }
    }
}

а второй:

    /**
 * 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);
        }
    }
}

РЕДАКТИРОВАТЬ 2: Я пытался использовать только один поток, чтобы убедиться, что нет доступа параллельно

BluetoothSocket

но результат точно такой же. Как только я позвоню

BluetoothSocket.close();

Я получаю фатальный сигнал 11 и приложение вылетает.

3 ответа

Решение

Я столкнулся с этой проблемой также. Однако для меня close() не было причиной. Проблема была в доступе к сокету после close(), В частности, призыв к available() на входном потоке сокета после закрытия сокета возникла ошибка.

У меня была точно такая же проблема. Это помогло мне до закрытия сокета вызова

mConnectedThread.interrupt()

из внешнего класса и в метод ConnectedThread run() добавьте

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

чтобы убедиться, что поток ничего не читает из потока сокета. После этого вы можете вызвать mmSocket.close()

Я столкнулся с той же проблемой с Android 4.4.2 в Galaxy Grand 2 устройство

Я исправил проблему с помощью ответа @markrileybot answer

Я имел доступ к socket.available() метод после close() звонок делается по моему коду.

Чтобы добавить больше к ответу @markrileybot:

Я также добавил условие перед звонком 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 Если вы используете один и тот же сокет multiple threadsзатем следует добавить это условие, которое будет препятствовать вызову close() если сокет уже закрыт (not connected)

2 Перед звонком socket.available() или же socket.write()мы должны проверить socket.isConnected() и если он вернется true тогда только мы должны обрабатывать дальше

Другие вопросы по тегам