Android: Fix deadlock when calling requestPermission
The hang happend when using QtAndroidPrivate::requestPermissions before the QApplication::exec. Android UI calls "sendRequestPermissionsResult" which was blocking until the event is delivered, but the qt main loop is blocked and waits for the main surface to be created by the Android UI thread which is already blocked. With this patch sendRequestPermissionsResult won't block for the result to be delivered. Change-Id: I48ada65fe9ea63471ab46d8a9d839ba1b91d17b3 Reviewed-by: Christian Stromme <christian.stromme@qt.io>
This commit is contained in:
parent
d31deab632
commit
e8ea1edd89
@ -80,13 +80,13 @@ class PermissionsResultClass : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
PermissionsResultClass(const QtAndroidPrivate::PermissionsResultFunc &func) : m_func(func) {}
|
PermissionsResultClass(const QtAndroidPrivate::PermissionsResultFunc &func) : m_func(func) {}
|
||||||
Q_INVOKABLE void sendResult(const QtAndroidPrivate::PermissionsHash &result) { m_func(result); }
|
Q_INVOKABLE void sendResult(const QtAndroidPrivate::PermissionsHash &result) { m_func(result); delete this;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QtAndroidPrivate::PermissionsResultFunc m_func;
|
QtAndroidPrivate::PermissionsResultFunc m_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QHash<int, QSharedPointer<PermissionsResultClass>> PendingPermissionRequestsHash;
|
typedef QHash<int, PermissionsResultClass*> PendingPermissionRequestsHash;
|
||||||
Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
|
Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
|
||||||
static QBasicMutex g_pendingPermissionRequestsMutex;
|
static QBasicMutex g_pendingPermissionRequestsMutex;
|
||||||
static int nextRequestCode()
|
static int nextRequestCode()
|
||||||
@ -131,11 +131,11 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ
|
|||||||
// show an error or something ?
|
// show an error or something ?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto request = std::move(*it);
|
auto request = *it;
|
||||||
g_pendingPermissionRequests->erase(it);
|
g_pendingPermissionRequests->erase(it);
|
||||||
locker.unlock();
|
locker.unlock();
|
||||||
|
|
||||||
Qt::ConnectionType connection = QThread::currentThread() == request->thread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
|
Qt::ConnectionType connection = QThread::currentThread() == request->thread() ? Qt::DirectConnection : Qt::QueuedConnection;
|
||||||
QtAndroidPrivate::PermissionsHash hash;
|
QtAndroidPrivate::PermissionsHash hash;
|
||||||
const int size = env->GetArrayLength(permissions);
|
const int size = env->GetArrayLength(permissions);
|
||||||
std::unique_ptr<jint[]> results(new jint[size]);
|
std::unique_ptr<jint[]> results(new jint[size]);
|
||||||
@ -147,7 +147,7 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ
|
|||||||
QtAndroidPrivate::PermissionsResult::Denied;
|
QtAndroidPrivate::PermissionsResult::Denied;
|
||||||
hash[permission] = value;
|
hash[permission] = value;
|
||||||
}
|
}
|
||||||
QMetaObject::invokeMethod(request.data(), "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
|
QMetaObject::invokeMethod(request, "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
|
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
|
||||||
@ -410,6 +410,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
|
|||||||
g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative));
|
g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative));
|
||||||
env->DeleteLocalRef(jQtNative);
|
env->DeleteLocalRef(jQtNative);
|
||||||
|
|
||||||
|
qRegisterMetaType<QtAndroidPrivate::PermissionsHash>();
|
||||||
return JNI_OK;
|
return JNI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,13 +492,13 @@ void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permis
|
|||||||
const int requestCode = nextRequestCode();
|
const int requestCode = nextRequestCode();
|
||||||
if (!directCall) {
|
if (!directCall) {
|
||||||
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
|
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
|
||||||
(*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
|
(*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] {
|
runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] {
|
||||||
if (directCall) {
|
if (directCall) {
|
||||||
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
|
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
|
||||||
(*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
|
(*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJNIEnvironmentPrivate env;
|
QJNIEnvironmentPrivate env;
|
||||||
|
@ -52,8 +52,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <QtCore/private/qglobal_p.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <QtCore/private/qglobal_p.h>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -117,7 +119,7 @@ namespace QtAndroidPrivate
|
|||||||
Q_CORE_EXPORT void runOnAndroidThreadSync(const Runnable &runnable, JNIEnv *env, int timeoutMs = INT_MAX);
|
Q_CORE_EXPORT void runOnAndroidThreadSync(const Runnable &runnable, JNIEnv *env, int timeoutMs = INT_MAX);
|
||||||
Q_CORE_EXPORT void runOnUiThread(QRunnable *runnable, JNIEnv *env);
|
Q_CORE_EXPORT void runOnUiThread(QRunnable *runnable, JNIEnv *env);
|
||||||
Q_CORE_EXPORT void requestPermissions(JNIEnv *env, const QStringList &permissions, const PermissionsResultFunc &callbackFunc, bool directCall = false);
|
Q_CORE_EXPORT void requestPermissions(JNIEnv *env, const QStringList &permissions, const PermissionsResultFunc &callbackFunc, bool directCall = false);
|
||||||
Q_CORE_EXPORT QHash<QString, PermissionsResult> requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs = INT_MAX);
|
Q_CORE_EXPORT PermissionsHash requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs = INT_MAX);
|
||||||
Q_CORE_EXPORT PermissionsResult checkPermission(const QString &permission);
|
Q_CORE_EXPORT PermissionsResult checkPermission(const QString &permission);
|
||||||
Q_CORE_EXPORT bool shouldShowRequestPermissionRationale(const QString &permission);
|
Q_CORE_EXPORT bool shouldShowRequestPermissionRationale(const QString &permission);
|
||||||
|
|
||||||
@ -145,4 +147,6 @@ namespace QtAndroidPrivate
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QtAndroidPrivate::PermissionsHash)
|
||||||
|
|
||||||
#endif // QJNIHELPERS_H
|
#endif // QJNIHELPERS_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user