diff options
| author | Assam Boudjelthia <assam.boudjelthia@qt.io> | 2025-07-13 04:47:15 +0300 |
|---|---|---|
| committer | Assam Boudjelthia <assam.boudjelthia@qt.io> | 2025-07-26 04:38:56 +0300 |
| commit | 082e632c614d7f2ea0214e5cb5a77ccf91a264a8 (patch) | |
| tree | 2ea80c004dded28bb349d83877de19bb6ec9ee15 /src | |
| parent | 72c8952c24ed16104ed9849a48f93ad609a9d806 (diff) | |
Android: silence spurious warnings from AndroidContentFileEngine
Move Java calls that might throw exceptions and handle them
with a try/catch by printing the appropriate error messages
where relevant and ignore the ones we don't necessarily need.
For certain operations like query we should check if we have
read permission for the URI first, and only then do the query,
because otherwise it's guaranteed to fail if there's no read
permission.
Pick-to: 6.10 6.9 6.8
Fixes: QTBUG-138013
Fixes: QTBUG-126531
Fixes: QTBUG-123319
Fixes: QTBUG-134912
Fixes: QTBUG-110240
Fixes: QTBUG-132403
Fixes: QTBUG-129324
Change-Id: I8457b6bfd9381bf1a62077520cf9a222311ded7a
Reviewed-by: Petri Virkkunen <petri.virkkunen@qt.io>
Diffstat (limited to 'src')
| -rw-r--r-- | src/android/jar/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/android/jar/src/org/qtproject/qt/android/QtContentFileEngine.java | 75 | ||||
| -rw-r--r-- | src/plugins/platforms/android/androidcontentfileengine.cpp | 25 |
3 files changed, 90 insertions, 11 deletions
diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt index 1b15d6bc6ee..b073dbea0ea 100644 --- a/src/android/jar/CMakeLists.txt +++ b/src/android/jar/CMakeLists.txt @@ -52,6 +52,7 @@ set(java_sources src/org/qtproject/qt/android/QtSignalListener.java src/org/qtproject/qt/android/BackgroundActionsTracker.java src/org/qtproject/qt/android/QtApkFileEngine.java + src/org/qtproject/qt/android/QtContentFileEngine.java ) qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android diff --git a/src/android/jar/src/org/qtproject/qt/android/QtContentFileEngine.java b/src/android/jar/src/org/qtproject/qt/android/QtContentFileEngine.java new file mode 100644 index 00000000000..051b0c26b1b --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtContentFileEngine.java @@ -0,0 +1,75 @@ +// Copyright (C) 2025 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 + +package org.qtproject.qt.android; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; + +import android.database.Cursor; + +import android.net.Uri; + +import android.util.Log; + +import android.os.ParcelFileDescriptor; +import android.os.Process; + +import java.util.Arrays; +import java.util.stream.Collectors; + +class QtContentFileEngine +{ + private static String QtTag = "QtContentFileEngine"; + + static Cursor query(ContentResolver contentResolver, Uri uri, String[] projection, + String selection, String[] selectionArgs, String sortOrder) + { + try { + // Check for read permission before doing any query + if (!hasPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)) + return null; + + return contentResolver.query(uri, projection, selection, selectionArgs, sortOrder); + } catch (Exception ignored) { + // Uncomment for debug only + // String projections = Arrays.stream(projection).collect(Collectors.joining(", ")); + // Log.w(QtTag, "Query for [" + projections + "] failed with " + ignored); + } + + return null; + } + + static ParcelFileDescriptor openFileDescriptor(ContentResolver contentResolver, + Uri uri, String openMode) + { + try { + int permissions = 0; + if (openMode.contains("w")) + permissions |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; + if (openMode.contains("r")) + permissions |= Intent.FLAG_GRANT_READ_URI_PERMISSION; + // Check for relevant permission before attempting to obtain a file description + if (!hasPermission(uri, permissions)) { + Log.w(QtTag, "openFileDescriptor(): No permission for URI " + uri); + return null; + } + + return contentResolver.openFileDescriptor(uri, openMode); + } catch (Exception e) { + Log.w(QtTag, "openFileDescriptor() failed with " + e); + } + + return null; + } + + static boolean hasPermission(Uri uri, int permission) + { + Context context = QtNative.getContext(); + int status = context.checkUriPermission(uri, Process.myPid(), Process.myUid(), permission); + + return status == PackageManager.PERMISSION_GRANTED; + } +} diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp index 7efe4d52d4c..46d78c688c5 100644 --- a/src/plugins/platforms/android/androidcontentfileengine.cpp +++ b/src/plugins/platforms/android/androidcontentfileengine.cpp @@ -19,6 +19,7 @@ using namespace Qt::StringLiterals; Q_DECLARE_JNI_CLASS(ParcelFileDescriptorType, "android/os/ParcelFileDescriptor"); Q_DECLARE_JNI_CLASS(CursorType, "android/database/Cursor"); +Q_DECLARE_JNI_CLASS(QtContentFileEngine, "org/qtproject/qt/android/QtContentFileEngine"); static QJniObject &contentResolverInstance() { @@ -76,11 +77,12 @@ bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode, openModeStr += u'a'; } - m_pfd = contentResolverInstance().callMethod< - QtJniTypes::ParcelFileDescriptorType, QtJniTypes::Uri, jstring>( + using namespace QtJniTypes; + m_pfd = QtContentFileEngine::callStaticMethod<ParcelFileDescriptorType>( "openFileDescriptor", - m_documentFile->uri().object(), - QJniObject::fromString(openModeStr).object<jstring>()); + contentResolverInstance().object<ContentResolver>(), + m_documentFile->uri().object<Uri>(), + openModeStr); if (!m_pfd.isValid()) return false; @@ -369,13 +371,14 @@ public: const QStringList &selectionArgs = {}, const QString &sortOrder = {}) { - auto cursor = contentResolverInstance().callMethod<QtJniTypes::CursorType>( - "query", - uri.object<QtJniTypes::Uri>(), - QJniArray(projection), - selection.isEmpty() ? nullptr : QJniObject::fromString(selection).object<jstring>(), - QJniArray(selectionArgs), - sortOrder.isEmpty() ? nullptr : QJniObject::fromString(sortOrder).object<jstring>()); + using namespace QtJniTypes; + auto cursor = QtContentFileEngine::callStaticMethod<CursorType>("query", + contentResolverInstance().object<ContentResolver>(), + uri.object<Uri>(), + QJniArray(projection), + selection.isEmpty() ? nullptr : selection, + QJniArray(selectionArgs), + sortOrder.isEmpty() ? nullptr : sortOrder); if (!cursor.isValid()) return {}; return std::make_unique<Cursor>(cursor); |
