diff options
author | Alex Blasche <alexander.blasche@digia.com> | 2014-02-26 11:08:41 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-02-27 13:00:50 +0100 |
commit | ccaeb6539d2f7e9ac756a7f2017c9f9e8813e265 (patch) | |
tree | 496ce956fc9408ef3fb50d34d8a4c094f3de22b9 /src/bluetooth/android/inputstreamthread.cpp | |
parent | 9d6057f3fa0b51ee2d36ad931072d2a3c816d0a6 (diff) |
Fix crash when interrupting QBluetoothSocket's input stream thread
The previous QThread did not always properly resume when
InputStream.read() was interrupted by BluetoothSocket.close().
This patch converts the QThread to a Java thread which works
as the Android API docs suggested.
Task-number: QTBUG-37061
Change-Id: Id6ac9b57a28f3b532cbe49ff1dfdc9d1e6432aaa
Reviewed-by: Nedim Hadzic <nedimhadzija@gmail.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
Diffstat (limited to 'src/bluetooth/android/inputstreamthread.cpp')
-rw-r--r-- | src/bluetooth/android/inputstreamthread.cpp | 110 |
1 files changed, 40 insertions, 70 deletions
diff --git a/src/bluetooth/android/inputstreamthread.cpp b/src/bluetooth/android/inputstreamthread.cpp index df32ee62..7f5029d9 100644 --- a/src/bluetooth/android/inputstreamthread.cpp +++ b/src/bluetooth/android/inputstreamthread.cpp @@ -40,6 +40,7 @@ ** ****************************************************************************/ +#include <QtCore/QLoggingCategory> #include <QtAndroidExtras/QAndroidJniEnvironment> #include "android/inputstreamthread_p.h" @@ -47,34 +48,29 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) InputStreamThread::InputStreamThread(QBluetoothSocketPrivate *socket) - : QThread(), m_stop(false) + : QObject(), m_socket_p(socket), expectClosure(false) { - m_socket_p = socket; } -void InputStreamThread::run() +bool InputStreamThread::run() { - qint32 byte; - Q_UNUSED(byte) - while (1) { - { - QMutexLocker locker(&m_mutex); - if (m_stop) - break; - } - readFromInputStream(); - } + QMutexLocker lock(&m_mutex); - QAndroidJniEnvironment env; - if (m_socket_p->inputStream.isValid()) - m_socket_p->inputStream.callMethod<void>("close"); + javaInputStreamThread = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread"); + if (!javaInputStreamThread.isValid() || !m_socket_p->inputStream.isValid()) + return false; + + javaInputStreamThread.callMethod<void>("setInputStream", "(Ljava/io/InputStream;)V", + m_socket_p->inputStream.object<jobject>()); + javaInputStreamThread.setField<jlong>("qtObject", reinterpret_cast<long>(this)); + javaInputStreamThread.setField<jboolean>("logEnabled", QT_BT_ANDROID().isDebugEnabled()); + + javaInputStreamThread.callMethod<void>("start"); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } + return true; } bool InputStreamThread::bytesAvailable() const @@ -83,68 +79,42 @@ bool InputStreamThread::bytesAvailable() const return m_socket_p->buffer.size(); } -//This runs inside the thread. -void InputStreamThread::readFromInputStream() +qint64 InputStreamThread::readData(char *data, qint64 maxSize) { - QAndroidJniEnvironment env; - - int bufLen = 1000; // Seems to magical number that also low-end products can survive. - jbyteArray nativeArray = env->NewByteArray(bufLen); - + QMutexLocker locker(&m_mutex); - jint ret = m_socket_p->inputStream.callMethod<jint>("read", "([BII)I", nativeArray, 0, bufLen); + if (!m_socket_p->buffer.isEmpty()) + return m_socket_p->buffer.read(data, maxSize); - if (env->ExceptionCheck() || ret < 0) { - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - env->DeleteLocalRef(nativeArray); - QMutexLocker lock(&m_mutex); - m_stop = true; + return 0; +} - /* - * We cannot distinguish IOException due to valid closure or due to other error - * Therefore we always have to throw an error and a disconnect signal - * A genuine disconnect wouldn't need the error signal. - * For now we always signal error which implicitly emits disconnect() too. - */ +//inside the java thread +void InputStreamThread::javaThreadErrorOccurred(int errorCode) +{ + QMutexLocker lock(&m_mutex); - emit error(); - return; - } + if (!expectClosure) + emit error(errorCode); + else + emit error(-1); //magic error, -1 means error was expected due to expected close() +} - if (ret == 0) { - qDebug() << "Nothing to read"; - env->DeleteLocalRef(nativeArray); - return; - } +//inside the java thread +void InputStreamThread::javaReadyRead(jbyteArray buffer, int bufferLength) +{ + QAndroidJniEnvironment env; QMutexLocker lock(&m_mutex); - char *writePtr = m_socket_p->buffer.reserve(bufLen); - env->GetByteArrayRegion(nativeArray, 0, ret, reinterpret_cast<jbyte*>(writePtr)); - env->DeleteLocalRef(nativeArray); - m_socket_p->buffer.chop(bufLen - ret); + char *writePtr = m_socket_p->buffer.reserve(bufferLength); + env->GetByteArrayRegion(buffer, 0, bufferLength, reinterpret_cast<jbyte*>(writePtr)); emit dataAvailable(); } -void InputStreamThread::stop() -{ - QMutexLocker locker(&m_mutex); - m_stop = true; -} - -qint64 InputStreamThread::readData(char *data, qint64 maxSize) +void InputStreamThread::prepareForClosure() { - QMutexLocker locker(&m_mutex); - - if (m_stop) - return -1; - - if (!m_socket_p->buffer.isEmpty()) - return m_socket_p->buffer.read(data, maxSize); - - return 0; + QMutexLocker lock(&m_mutex); + expectClosure = true; } QT_END_NAMESPACE |