Android A11Y: Only access the main thread when it is not blocked
When the qtMainLoopThread calls QSGThreadedRenderLoop::polishAndSync(),
it waits for the QSGRenderThread.
In the QSGRenderThread, QAndroidPlatformOpenGLWindow::eglSurface()
calls QtAndroid::createSurface() and waits for the "android main
thread" to return a valid surface.
When the "android main thread" now calls "runInObjectContext" (e.g. by
calling QtAndroidAccessibility::childIdListForAccessibleObject()) it
waits for the qtMainLoopThread and the program is stuck in a deadlock.
To prevent this, we protect all BlockedQueuedConnection from the
"android main thread" to the qtMainLoopThread by acquiring the
AndroidDeadlockProtector.
When QAndroidPlatformOpenGLWindow::eglSurface() already acquired the
AndroidDeadlockProtector we abort the current A11y call with an emtpy
or default value.
Note: b8a9527544 already tried to fix
this by checking "getSurfaceCount() != 0", but there are situations,
where a new surface is being created while an old surface is still
present.
Task-number: QTBUG-105958
Pick-to: 6.5 6.4 6.3 6.2 5.15
Change-Id: Ie40e8654c99aace9e69b0b8412952fa22c89f071
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
bb10
parent
0ba063f436
commit
b832a5ac72
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "androiddeadlockprotector.h"
|
||||
#include "androidjniaccessibility.h"
|
||||
#include "androidjnimain.h"
|
||||
#include "qandroidplatformintegration.h"
|
||||
|
|
@ -61,6 +62,14 @@ namespace QtAndroidAccessibility
|
|||
template <typename Func, typename Ret>
|
||||
void runInObjectContext(QObject *context, Func &&func, Ret *retVal)
|
||||
{
|
||||
AndroidDeadlockProtector protector;
|
||||
if (!protector.acquire()) {
|
||||
__android_log_print(ANDROID_LOG_WARN, m_qtTag,
|
||||
"Could not run accessibility call in object context, accessing "
|
||||
"main thread could lead to deadlock");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!QtAndroid::blockEventLoopsWhenSuspended()
|
||||
|| QGuiApplication::applicationState() != Qt::ApplicationSuspended) {
|
||||
QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal);
|
||||
|
|
|
|||
Loading…
Reference in New Issue