From e8ea1edd89729d4caeffa70dd8cf76a686294987 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 11 Apr 2017 13:17:21 +0300 Subject: 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 --- src/corelib/kernel/qjnihelpers.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/corelib/kernel/qjnihelpers.cpp') diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index 93bc477e7d..cb4b93905e 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -80,13 +80,13 @@ class PermissionsResultClass : public QObject Q_OBJECT public: 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: QtAndroidPrivate::PermissionsResultFunc m_func; }; -typedef QHash> PendingPermissionRequestsHash; +typedef QHash PendingPermissionRequestsHash; Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests); static QBasicMutex g_pendingPermissionRequestsMutex; static int nextRequestCode() @@ -131,11 +131,11 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ // show an error or something ? return; } - auto request = std::move(*it); + auto request = *it; g_pendingPermissionRequests->erase(it); 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; const int size = env->GetArrayLength(permissions); std::unique_ptr results(new jint[size]); @@ -147,7 +147,7 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ QtAndroidPrivate::PermissionsResult::Denied; 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) @@ -410,6 +410,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) g_jNativeClass = static_cast(env->NewGlobalRef(jQtNative)); env->DeleteLocalRef(jQtNative); + qRegisterMetaType(); return JNI_OK; } @@ -491,13 +492,13 @@ void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permis const int requestCode = nextRequestCode(); if (!directCall) { QMutexLocker locker(&g_pendingPermissionRequestsMutex); - (*g_pendingPermissionRequests)[requestCode] = QSharedPointer::create(callbackFunc); + (*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc); } runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] { if (directCall) { QMutexLocker locker(&g_pendingPermissionRequestsMutex); - (*g_pendingPermissionRequests)[requestCode] = QSharedPointer::create(callbackFunc); + (*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc); } QJNIEnvironmentPrivate env; -- cgit v1.2.3