summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-02-20 11:39:09 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-27 13:00:40 +0100
commit9d6057f3fa0b51ee2d36ad931072d2a3c816d0a6 (patch)
treeabd3b315377daadd57f2c5356c5512b1020fe349
parentae1a2b8b0149b473190623910a98096c3f117328 (diff)
Android: Fix crash in QBluetoothServer::close()
Java's BluetoothSocketServer.accept() is meant to be interrupted via BluetoothSocketServer.close(). Unfortunately if the surrounding thread is a QThread the returning accept call crashes the thread. This does not happen if it is a Java Thread. This commit changes the server's private backend to a Java thread. Task-number: QTBUG-36754 Change-Id: I5aacc5444bbcd1275a11743b6aa04d2b11a5b22b Reviewed-by: Nedim Hadzic <nedimhadzija@gmail.com> Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
-rw-r--r--src/android/bluetooth/bluetooth.pri4
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java153
-rw-r--r--src/bluetooth/android/jni_android.cpp31
-rw-r--r--src/bluetooth/android/serveracceptancethread.cpp202
-rw-r--r--src/bluetooth/android/serveracceptancethread_p.h26
-rw-r--r--src/bluetooth/qbluetoothserver.cpp2
-rw-r--r--src/bluetooth/qbluetoothserver_android.cpp42
-rw-r--r--src/bluetooth/qbluetoothsocket_android.cpp3
8 files changed, 302 insertions, 161 deletions
diff --git a/src/android/bluetooth/bluetooth.pri b/src/android/bluetooth/bluetooth.pri
index 5c2cb8f8..d3fdd0d0 100644
--- a/src/android/bluetooth/bluetooth.pri
+++ b/src/android/bluetooth/bluetooth.pri
@@ -5,7 +5,9 @@ PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/bluetooth
JAVACLASSPATH += $$PWD/src/
JAVASOURCES += \
- $$PATHPREFIX/QtBluetoothBroadcastReceiver.java
+ $$PATHPREFIX/QtBluetoothBroadcastReceiver.java \
+ $$PATHPREFIX/QtBluetoothSocketServer.java
+
# install
target.path = $$[QT_INSTALL_PREFIX]/jar
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java
new file mode 100644
index 00000000..ee365a49
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.util.Log;
+import java.io.IOException;
+import java.util.UUID;
+
+public class QtBluetoothSocketServer extends Thread
+{
+
+ /* Pointer to the Qt object that "owns" the Java object */
+ long qtObject = 0;
+ public boolean logEnabled = false;
+
+ private static final String TAG = "QtBluetooth";
+ private boolean m_isSecure = false;
+ private UUID m_uuid;
+ private String m_serviceName;
+ private BluetoothServerSocket m_serverSocket = null;
+
+ //error codes
+ public static final int QT_NO_BLUETOOTH_SUPPORTED = 0;
+ public static final int QT_LISTEN_FAILED = 1;
+ public static final int QT_ACCEPT_FAILED = 2;
+
+ public QtBluetoothSocketServer()
+ {
+ setName("QtSocketServerThread");
+ }
+
+ public void setServiceDetails(String uuid, String serviceName, boolean isSecure)
+ {
+ m_uuid = UUID.fromString(uuid);
+ m_serviceName = serviceName;
+ m_isSecure = isSecure;
+
+ }
+
+ public void run()
+ {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter == null) {
+ errorOccurred(qtObject, QT_NO_BLUETOOTH_SUPPORTED);
+ return;
+ }
+
+ try {
+ if (m_isSecure) {
+ m_serverSocket = adapter.listenUsingRfcommWithServiceRecord(m_serviceName, m_uuid);
+ if (logEnabled)
+ Log.d(TAG, "Using secure socket listener");
+ } else {
+ m_serverSocket = adapter.listenUsingInsecureRfcommWithServiceRecord(m_serviceName, m_uuid);
+ if (logEnabled)
+ Log.d(TAG, "Using insecure socket listener");
+ }
+ } catch (IOException ex) {
+ if (logEnabled)
+ Log.d(TAG, "Server socket listen() failed:" + ex.toString());
+ ex.printStackTrace();
+ errorOccurred(qtObject, QT_LISTEN_FAILED);
+ return;
+ }
+
+ BluetoothSocket s = null;
+ if (m_serverSocket != null) {
+ try {
+ while (!isInterrupted()) {
+ //this blocks until we see incoming connection
+ //or close() is called
+ if (logEnabled)
+ Log.d(TAG, "Waiting for new incoming socket");
+ s = m_serverSocket.accept();
+
+ if (logEnabled)
+ Log.d(TAG, "New socket accepted");
+ newSocket(qtObject, s);
+ }
+ } catch (IOException ex) {
+ if (logEnabled)
+ Log.d(TAG, "Server socket accept() failed:" + ex.toString());
+ ex.printStackTrace();
+ errorOccurred(qtObject, QT_ACCEPT_FAILED);
+ }
+ }
+
+ Log.d(TAG, "Leaving server socket thread.");
+ }
+
+ public void close()
+ {
+ if (!isAlive())
+ return;
+
+ try {
+ //ensure closing of thread if we are not currently blocking on accept()
+ interrupt();
+
+ //interrupts accept() call above
+ if (m_serverSocket != null)
+ m_serverSocket.close();
+ } catch (IOException ex) {
+ Log.d(TAG, "Closing server socket close() failed:" + ex.toString());
+ ex.printStackTrace();
+ }
+ }
+
+ public static native void errorOccurred(long qtObject, int errorCode);
+ public static native void newSocket(long qtObject, BluetoothSocket socket);
+}
diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp
index eb1fc2dd..ce0f19ca 100644
--- a/src/bluetooth/android/jni_android.cpp
+++ b/src/bluetooth/android/jni_android.cpp
@@ -46,6 +46,7 @@
#include <QtBluetooth/qbluetoothglobal.h>
#include <QtAndroidExtras/QAndroidJniObject>
#include "android/androidbroadcastreceiver_p.h"
+#include "android/serveracceptancethread_p.h"
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
@@ -55,9 +56,28 @@ void QtBroadcastReceiver_jniOnReceive(JNIEnv *env, jobject /*javaObject*/,
reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceive(env, context, intent);
}
+static void QtBluetoothSocketServer_errorOccurred(JNIEnv */*env*/, jobject /*javaObject*/,
+ jlong qtObject, jint errorCode)
+{
+ reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaThreadErrorOccurred(errorCode);
+}
+
+static void QtBluetoothSocketServer_newSocket(JNIEnv */*env*/, jobject /*javaObject*/,
+ jlong qtObject, jobject socket)
+{
+ reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaNewSocket(socket);
+}
+
static JNINativeMethod methods[] = {
{"jniOnReceive", "(JLandroid/content/Context;Landroid/content/Intent;)V",
- (void *) QtBroadcastReceiver_jniOnReceive},
+ (void *) QtBroadcastReceiver_jniOnReceive},
+};
+
+static JNINativeMethod methods_server[] = {
+ {"errorOccurred", "(JI)V",
+ (void *) QtBluetoothSocketServer_errorOccurred},
+ {"newSocket", "(JLandroid/bluetooth/BluetoothSocket;)V",
+ (void *) QtBluetoothSocketServer_newSocket},
};
static const char logTag[] = "QtBluetooth";
@@ -75,8 +95,15 @@ static bool registerNatives(JNIEnv *env)
jclass clazz;
FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
+
if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives failed");
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for BraodcastReceiver failed");
+ return false;
+ }
+
+ FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer");
+ if (env->RegisterNatives(clazz, methods_server, sizeof(methods_server) / sizeof(methods_server[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for SocketServer failed");
return false;
}
diff --git a/src/bluetooth/android/serveracceptancethread.cpp b/src/bluetooth/android/serveracceptancethread.cpp
index 88a92478..d46fff7c 100644
--- a/src/bluetooth/android/serveracceptancethread.cpp
+++ b/src/bluetooth/android/serveracceptancethread.cpp
@@ -47,11 +47,9 @@
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
ServerAcceptanceThread::ServerAcceptanceThread(QObject *parent) :
- QThread(parent), m_stop(false), maxPendingConnections(1)
+ QObject(parent), maxPendingConnections(1)
{
- btAdapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
- "getDefaultAdapter",
- "()Landroid/bluetooth/BluetoothAdapter;");
+ qRegisterMetaType<QBluetoothServer::Error>("QBluetoothServer::Error");
}
ServerAcceptanceThread::~ServerAcceptanceThread()
@@ -71,161 +69,121 @@ void ServerAcceptanceThread::setServiceDetails(const QBluetoothUuid &uuid,
secFlags = securityFlags;
}
+bool ServerAcceptanceThread::hasPendingConnections() const
+{
+ QMutexLocker lock(&m_mutex);
+ return (pendingSockets.count() > 0);
+}
+
+/*
+ * Returns the next pending connection or an invalid JNI object.
+ * Note that even a stopped thread may still have pending
+ * connections. Pending connections are only terminated upon
+ * thread restart or destruction.
+ */
+QAndroidJniObject ServerAcceptanceThread::nextPendingConnection()
+{
+ QMutexLocker lock(&m_mutex);
+ if (pendingSockets.isEmpty())
+ return QAndroidJniObject();
+ else
+ return pendingSockets.takeFirst();
+}
+
+void ServerAcceptanceThread::setMaxPendingConnections(int maximumCount)
+{
+ QMutexLocker lock(&m_mutex);
+ maxPendingConnections = maximumCount;
+}
+
void ServerAcceptanceThread::run()
{
- m_mutex.lock();
+ QMutexLocker lock(&m_mutex);
- qCDebug(QT_BT_ANDROID) << "Starting ServerSocketAccept thread";
if (!validSetup()) {
qCWarning(QT_BT_ANDROID) << "Invalid Server Socket setup";
- m_mutex.unlock();
return;
}
- shutdownPendingConnections();
-
- m_stop = false;
-
- QString tempUuid = m_uuid.toString();
- tempUuid.chop(1); //remove trailing '}'
- tempUuid.remove(0,1); //remove first '{'
-
- QAndroidJniEnvironment env;
- QAndroidJniObject inputString = QAndroidJniObject::fromString(tempUuid);
- QAndroidJniObject uuidObject = QAndroidJniObject::callStaticObjectMethod(
- "java/util/UUID", "fromString",
- "(Ljava/lang/String;)Ljava/util/UUID;",
- inputString.object<jstring>());
- inputString = QAndroidJniObject::fromString(m_serviceName);
- if (((int)secFlags) == 0) { //no form of security flag set
- qCDebug(QT_BT_ANDROID) << "InSecure listening";
- btServerSocket = btAdapter.callObjectMethod("listenUsingInsecureRfcommWithServiceRecord",
- "(Ljava/lang/String;Ljava/util/UUID;)Landroid/bluetooth/BluetoothServerSocket;",
- inputString.object<jstring>(),
- uuidObject.object<jobject>());
- } else {
- qCDebug(QT_BT_ANDROID) << "Secure listening";
- btServerSocket = btAdapter.callObjectMethod("listenUsingRfcommWithServiceRecord",
- "(Ljava/lang/String;Ljava/util/UUID;)Landroid/bluetooth/BluetoothServerSocket;",
- inputString.object<jstring>(),
- uuidObject.object<jobject>());
- }
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- qCWarning(QT_BT_ANDROID) << "Cannot setup rfcomm socket listener";
- m_mutex.unlock();
- return;
+ if (isRunning()) {
+ stop();
+ shutdownPendingConnections();
}
- if (!btServerSocket.isValid()) {
- qCWarning(QT_BT_ANDROID) << "Invalid BluetoothServerSocket";
- m_mutex.unlock();
+ javaThread = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer");
+ if (!javaThread.isValid())
return;
- }
-
- while (!m_stop) {
- m_mutex.unlock();
-
- qCDebug(QT_BT_ANDROID) << "Waiting for new incoming socket";
- QAndroidJniEnvironment env;
-
- //this call blocks until we see an incoming connection
- QAndroidJniObject socket = btServerSocket.callObjectMethod("accept",
- "()Landroid/bluetooth/BluetoothSocket;");
- qCDebug(QT_BT_ANDROID) << "New socket accepted: ->" << socket.isValid();
- bool exceptionOccurred = false;
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- exceptionOccurred = true;
- }
+ javaThread.setField<jlong>("qtObject", reinterpret_cast<long>(this));
+ javaThread.setField<jboolean>("logEnabled", QT_BT_ANDROID().isDebugEnabled());
- m_mutex.lock();
-
- if (exceptionOccurred || m_stop) {
- //if m_stop is true there is nothing really to be done but exit
- m_stop = true;
- } else if (socket.isValid()){
- if (pendingSockets.count() < maxPendingConnections) {
- pendingSockets.append(socket);
- emit newConnection();
- } else {
- qCWarning(QT_BT_ANDROID) << "Refusing connection due to limited pending socket queue";
- socket.callMethod<void>("close");
- if (env->ExceptionCheck()) {
- qCWarning(QT_BT_ANDROID) << "Error during refusal of new socket";
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
-
-
- }
- } else {
- //should never happen as invalid socket should cause exception
- qCWarning(QT_BT_ANDROID) << "Invalid state during server socket accept";
- }
- }
+ QString tempUuid = m_uuid.toString();
+ tempUuid.chop(1); //remove trailing '}'
+ tempUuid.remove(0,1); //remove first '{'
- m_uuid = QBluetoothUuid();
- m_serviceName = QString();
- btServerSocket = QAndroidJniObject();
- m_mutex.unlock();
+ QAndroidJniObject uuidString = QAndroidJniObject::fromString(tempUuid);
+ QAndroidJniObject serviceNameString = QAndroidJniObject::fromString(m_serviceName);
+ bool isSecure = !(secFlags == QBluetooth::NoSecurity);
+ javaThread.callMethod<void>("setServiceDetails", "(Ljava/lang/String;Ljava/lang/String;Z)V",
+ uuidString.object<jstring>(),
+ serviceNameString.object<jstring>(),
+ isSecure);
+ javaThread.callMethod<void>("start");
}
void ServerAcceptanceThread::stop()
{
- QMutexLocker lock(&m_mutex);
- m_stop = true;
-
- QAndroidJniEnvironment env;
- if (btServerSocket.isValid()) {
+ if (javaThread.isValid()) {
qCDebug(QT_BT_ANDROID) << "Closing server socket";
- btServerSocket.callMethod<void>("close");
- if (env->ExceptionCheck()) {
- qCWarning(QT_BT_ANDROID) << "Exception during closure of server socket";
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- qCDebug(QT_BT_ANDROID) << "Closing server socket111";
+ javaThread.callMethod<void>("close");
}
}
-bool ServerAcceptanceThread::hasPendingConnections() const
+bool ServerAcceptanceThread::isRunning() const
{
- QMutexLocker lock(&m_mutex);
- return (pendingSockets.count() > 0);
+ if (javaThread.isValid())
+ return javaThread.callMethod<jboolean>("isAlive");
+
+ return false;
}
-/*
- * Returns the next pending connection or an invalid JNI object.
- * Note that even a stopped thread may still have pending
- * connections. Pending connections are only terminated upon
- * thread restart or destruction.
- */
-QAndroidJniObject ServerAcceptanceThread::nextPendingConnection()
+//Runs inside the java thread
+void ServerAcceptanceThread::javaThreadErrorOccurred(int errorCode)
{
- QMutexLocker lock(&m_mutex);
- if (pendingSockets.isEmpty())
- return QAndroidJniObject();
- else
- return pendingSockets.takeFirst();
+ qCDebug(QT_BT_ANDROID) << "JavaThread error:" << errorCode;
+ emit error(QBluetoothServer::InputOutputError);
}
-void ServerAcceptanceThread::setMaxPendingConnections(int maximumCount)
+//Runs inside the Java thread
+void ServerAcceptanceThread::javaNewSocket(jobject s)
{
QMutexLocker lock(&m_mutex);
- maxPendingConnections = maximumCount;
+
+ QAndroidJniObject socket(s);
+ if (!socket.isValid())
+ return;
+
+ if (pendingSockets.count() < maxPendingConnections) {
+ qCDebug(QT_BT_ANDROID) << "New incoming java socket detected";
+ pendingSockets.append(socket);
+ emit newConnection();
+ } else {
+ QAndroidJniEnvironment env;
+ qCWarning(QT_BT_ANDROID) << "Refusing connection due to limited pending socket queue";
+ socket.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ qCWarning(QT_BT_ANDROID) << "Error during refusal of new socket";
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ }
}
-//must be run inside the lock but doesn't lock by itself
bool ServerAcceptanceThread::validSetup() const
{
return (!m_uuid.isNull() && !m_serviceName.isEmpty());
}
-//must be run inside the lock but doesn't lock by itself
void ServerAcceptanceThread::shutdownPendingConnections()
{
while (!pendingSockets.isEmpty()) {
diff --git a/src/bluetooth/android/serveracceptancethread_p.h b/src/bluetooth/android/serveracceptancethread_p.h
index 1297e48f..18142d64 100644
--- a/src/bluetooth/android/serveracceptancethread_p.h
+++ b/src/bluetooth/android/serveracceptancethread_p.h
@@ -43,50 +43,50 @@
#define SERVERACCEPTANCETHREAD_H
#include <QtCore/QMutex>
-#include <QtCore/QThread>
#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtBluetooth/QBluetoothServer>
#include <QtBluetooth/QBluetoothUuid>
#include "qbluetooth.h"
-class ServerAcceptanceThread : public QThread
+class ServerAcceptanceThread : public QObject
{
Q_OBJECT
public:
- enum AndroidError {
- AndroidNoError
- };
-
explicit ServerAcceptanceThread(QObject *parent = 0);
~ServerAcceptanceThread();
void setServiceDetails(const QBluetoothUuid &uuid, const QString &serviceName,
QBluetooth::SecurityFlags securityFlags);
- virtual void run();
- void stop();
+
bool hasPendingConnections() const;
QAndroidJniObject nextPendingConnection();
void setMaxPendingConnections(int maximumCount);
+ void javaThreadErrorOccurred(int errorCode);
+ void javaNewSocket(jobject socket);
+
+ void run();
+ void stop();
+ bool isRunning() const;
+
signals:
void newConnection();
- void error(ServerAcceptanceThread::AndroidError);
+ void error(QBluetoothServer::Error);
private:
bool validSetup() const;
void shutdownPendingConnections();
QList<QAndroidJniObject> pendingSockets;
- QAndroidJniObject btAdapter;
- QAndroidJniObject btServerSocket;
mutable QMutex m_mutex;
QString m_serviceName;
QBluetoothUuid m_uuid;
- bool m_stop;
- AndroidError lastError;
int maxPendingConnections;
QBluetooth::SecurityFlags secFlags;
+ QAndroidJniObject javaThread;
+
};
#endif // SERVERACCEPTANCETHREAD_H
diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp
index a7ceff64..8665e33e 100644
--- a/src/bluetooth/qbluetoothserver.cpp
+++ b/src/bluetooth/qbluetoothserver.cpp
@@ -145,7 +145,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QBluetoothSocket *QBluetoothServer::nextPendingConnection()
- Returns a pointer to aQBluetoothSocket for the next pending connection. It is the callers
+ Returns a pointer to the QBluetoothSocket for the next pending connection. It is the callers
responsibility to delete the pointer.
*/
diff --git a/src/bluetooth/qbluetoothserver_android.cpp b/src/bluetooth/qbluetoothserver_android.cpp
index a2d08757..c7c798d3 100644
--- a/src/bluetooth/qbluetoothserver_android.cpp
+++ b/src/bluetooth/qbluetoothserver_android.cpp
@@ -59,8 +59,8 @@ QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol
: socket(0),maxPendingConnections(1), securityFlags(QBluetooth::NoSecurity), serverType(sType),
m_lastError(QBluetoothServer::NoError)
{
- thread = new ServerAcceptanceThread();
- thread->setMaxPendingConnections(maxPendingConnections);
+ thread = new ServerAcceptanceThread();
+ thread->setMaxPendingConnections(maxPendingConnections);
}
QBluetoothServerPrivate::~QBluetoothServerPrivate()
@@ -71,10 +71,6 @@ QBluetoothServerPrivate::~QBluetoothServerPrivate()
__fakeServerPorts.remove(this);
- if (thread->isRunning()) {
- thread->stop();
- thread->wait();
- }
thread->deleteLater();
thread = 0;
}
@@ -82,33 +78,33 @@ QBluetoothServerPrivate::~QBluetoothServerPrivate()
bool QBluetoothServerPrivate::initiateActiveListening(
const QBluetoothUuid& uuid, const QString &serviceName)
{
- Q_UNUSED(uuid);
- Q_UNUSED(serviceName);
qCDebug(QT_BT_ANDROID) << "Initiate active listening" << uuid.toString() << serviceName;
if (uuid.isNull() || serviceName.isEmpty())
return false;
//no change of SP profile details -> do nothing
- if (uuid == m_uuid && serviceName == m_serviceName)
+ if (uuid == m_uuid && serviceName == m_serviceName && thread->isRunning())
return true;
m_uuid = uuid;
m_serviceName = serviceName;
thread->setServiceDetails(m_uuid, m_serviceName, securityFlags);
- Q_ASSERT(!thread->isRunning());
- thread->start();
- Q_ASSERT(thread->isRunning());
+ thread->run();
+ if (!thread->isRunning())
+ return false;
return true;
}
bool QBluetoothServerPrivate::deactivateActiveListening()
{
- thread->stop();
- thread->wait();
-
+ if (isListening()) {
+ //suppress last error signal due to intended closure
+ thread->disconnect();
+ thread->stop();
+ }
return true;
}
@@ -121,12 +117,12 @@ void QBluetoothServer::close()
{
Q_D(QBluetoothServer);
- d->thread->stop();
- d->thread->wait();
-
- if (d->thread)
- d->thread->disconnect();
__fakeServerPorts.remove(d);
+ if (d->thread->isRunning()) {
+ //suppress last error signal due to intended closure
+ d->thread->disconnect();
+ d->thread->stop();
+ }
}
bool QBluetoothServer::listen(const QBluetoothAddress &localAdapter, quint16 port)
@@ -202,7 +198,11 @@ bool QBluetoothServer::listen(const QBluetoothAddress &localAdapter, quint16 por
return false;
}
- connect(d->thread, SIGNAL(newConnection()), this, SIGNAL(newConnection()));
+ connect(d->thread, SIGNAL(newConnection()),
+ this, SIGNAL(newConnection()));
+ connect(d->thread, SIGNAL(error(QBluetoothServer::Error)),
+ this, SIGNAL(error(QBluetoothServer::Error)), Qt::QueuedConnection);
+
return true;
}
diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp
index fa0ca6ad..9f04c69e 100644
--- a/src/bluetooth/qbluetoothsocket_android.cpp
+++ b/src/bluetooth/qbluetoothsocket_android.cpp
@@ -97,7 +97,6 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr
Q_Q(QBluetoothSocket);
Q_UNUSED(openMode);
- qDebug() << "GGGGConnecting to" << address.toString() << uuid.toString();
if (!adapter.isValid()) {
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
errorString = QBluetoothSocket::tr("Device does not support Bluetooth");
@@ -412,6 +411,8 @@ bool QBluetoothSocketPrivate::setSocketDescriptor(const QAndroidJniObject &socke
return false;
}
+ remoteDevice = socketObject.callObjectMethod("getRemoteDevice", "()Landroid/bluetooth/BluetoothDevice;");
+
if (inputThread) {
inputThread->stop();
inputThread->wait();