summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAssam Boudjelthia <assam.boudjelthia@qt.io>2025-07-13 04:47:15 +0300
committerAssam Boudjelthia <assam.boudjelthia@qt.io>2025-07-26 04:38:56 +0300
commit082e632c614d7f2ea0214e5cb5a77ccf91a264a8 (patch)
tree2ea80c004dded28bb349d83877de19bb6ec9ee15 /src
parent72c8952c24ed16104ed9849a48f93ad609a9d806 (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.txt1
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtContentFileEngine.java75
-rw-r--r--src/plugins/platforms/android/androidcontentfileengine.cpp25
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);