From 5dcd9491454390b198db1d2ab45b0b418d926cde Mon Sep 17 00:00:00 2001 From: Christian Stromme Date: Wed, 7 Jun 2017 15:46:07 +0200 Subject: Android: Add lock to protect access to the platform interface Fixes dubious lock protecting the platform interface handle, and makes sure that we lock and hold a valid reference to the platform interface before accessing it. Since the platform interface is exposed we also need to expose the mutex protecting it. Change-Id: I1ec1219a75c589bc793676369b11fb403de20102 Reviewed-by: BogDan Vatra --- .../platforms/android/androidjniaccessibility.cpp | 1 + src/plugins/platforms/android/androidjniinput.cpp | 1 + src/plugins/platforms/android/androidjnimain.cpp | 50 +++++++++------------- src/plugins/platforms/android/androidjnimain.h | 2 + .../android/qandroidplatformintegration.cpp | 9 +++- 5 files changed, 32 insertions(+), 31 deletions(-) (limited to 'src/plugins/platforms/android') diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index eeaecd53b4..06624415d3 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -80,6 +80,7 @@ namespace QtAndroidAccessibility static void setActive(JNIEnv */*env*/, jobject /*thiz*/, jboolean active) { + QMutexLocker lock(QtAndroid::platformInterfaceMutex()); QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration(); if (platformIntegration) platformIntegration->accessibility()->setActive(active); diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index ef95b80dd4..f19b7d5484 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -272,6 +272,7 @@ namespace QtAndroidInput if (m_touchPoints.isEmpty()) return; + QMutexLocker lock(QtAndroid::platformInterfaceMutex()); QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration(); if (!platformIntegration) return; diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 06bca0354d..4f95e84283 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -83,7 +83,7 @@ static jmethodID m_setSurfaceGeometryMethodID = nullptr; static jmethodID m_destroySurfaceMethodID = nullptr; static int m_pendingApplicationState = -1; -static QBasicMutex m_pendingAppStateMtx; +static QBasicMutex m_platformMutex; static jclass m_bitmapClass = nullptr; static jmethodID m_createBitmapMethodID = nullptr; @@ -123,28 +123,26 @@ static const char m_qtTag[] = "Qt"; static const char m_classErrorMsg[] = "Can't find class \"%s\""; static const char m_methodErrorMsg[] = "Can't find method \"%s%s\""; -static void flushPendingApplicationState(); - namespace QtAndroid { + QBasicMutex *platformInterfaceMutex() + { + return &m_platformMutex; + } + void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration) { - QMutexLocker lock(&m_surfacesMutex); m_androidPlatformIntegration = androidPlatformIntegration; // flush the pending state if necessary. - if (m_androidPlatformIntegration) { - flushPendingApplicationState(); - m_androidPlatformIntegration->flushPendingUpdates(); - } else { - QMutexLocker locker(&m_pendingAppStateMtx); - m_pendingApplicationState = -1; - } + if (m_androidPlatformIntegration && (m_pendingApplicationState != -1)) + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(m_pendingApplicationState)); + + m_pendingApplicationState = -1; } QAndroidPlatformIntegration *androidPlatformIntegration() { - QMutexLocker locker(&m_surfacesMutex); return m_androidPlatformIntegration; } @@ -443,17 +441,6 @@ namespace QtAndroid } // namespace QtAndroid -// Force an update of the pending application state (state set before the platform plugin was created) -static void flushPendingApplicationState() -{ - QMutexLocker locker(&m_pendingAppStateMtx); - if (m_pendingApplicationState == -1) - return; - - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(m_pendingApplicationState)); - m_pendingApplicationState = -1; -} - static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/) { m_androidPlatformIntegration = nullptr; @@ -621,7 +608,7 @@ static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, m_scaledDensity = scaledDensity; m_density = density; - QMutexLocker lock(&m_surfacesMutex); + QMutexLocker lock(&m_platformMutex); if (!m_androidPlatformIntegration) { QAndroidPlatformIntegration::setDefaultDisplayMetrics(desktopWidthPixels, desktopHeightPixels, @@ -663,18 +650,22 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/) static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state) { - if (!m_main || !QtAndroid::androidPlatformIntegration()) { - QMutexLocker locker(&m_pendingAppStateMtx); - m_pendingApplicationState = Qt::ApplicationState(state); + QMutexLocker lock(&m_platformMutex); + if (!m_main || !m_androidPlatformIntegration) { + m_pendingApplicationState = state; return; } - flushPendingApplicationState(); - + // We're about to call user code from the Android thread, since we don't know + //the side effects we'll unlock first! + lock.unlock(); if (state == Qt::ApplicationActive) QtAndroidPrivate::handleResume(); else if (state == Qt::ApplicationInactive) QtAndroidPrivate::handlePause(); + lock.relock(); + if (!m_androidPlatformIntegration) + return; if (state <= Qt::ApplicationInactive) { // NOTE: sometimes we will receive two consecutive suspended notifications, @@ -722,6 +713,7 @@ static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint new Qt::ScreenOrientation native = orientations[nativeOrientation - 1]; QAndroidPlatformIntegration::setScreenOrientation(screenOrientation, native); + QMutexLocker lock(&m_platformMutex); if (m_androidPlatformIntegration) { QPlatformScreen *screen = m_androidPlatformIntegration->screen(); QWindowSystemInterface::handleScreenOrientationChange(screen->screen(), diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 170596082d..08f1d50fe3 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -58,9 +58,11 @@ class QWidget; class QString; class QWindow; class AndroidSurfaceClient; +class QBasicMutex; namespace QtAndroid { + QBasicMutex *platformInterfaceMutex(); QAndroidPlatformIntegration *androidPlatformIntegration(); void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration); void setQtThread(QThread *thread); diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 403badb2e1..7185b573cd 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -121,8 +121,13 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA void QAndroidPlatformNativeInterface::customEvent(QEvent *event) { - if (event->type() == QEvent::User) - QtAndroid::setAndroidPlatformIntegration(static_cast(QGuiApplicationPrivate::platformIntegration())); + if (event->type() != QEvent::User) + return; + + QMutexLocker lock(QtAndroid::platformInterfaceMutex()); + QAndroidPlatformIntegration *api = static_cast(QGuiApplicationPrivate::platformIntegration()); + QtAndroid::setAndroidPlatformIntegration(api); + api->flushPendingUpdates(); } QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶mList) -- cgit v1.2.3