From edd983071e0a90ee8665d2f45916fb575fc25857 Mon Sep 17 00:00:00 2001 From: Louis du Verdier Date: Thu, 24 Mar 2022 13:35:07 +0100 Subject: Android: Improve loading speed of individual assets This change improves the loading speed of files stored in Android assets folder by caching the information about files already opened. Prior to the change, when creating a QFile or QFileInfo to an asset file, the engine would first scan all the file's directory and parent directories in order to cache all this in FolderIterator::m_assetsCache. Due to the nature of Android assets, it might be very slow, depending on the number of images in this tree. In this patch, individual file accesses will stop using FolderIterator and will simply open what is asked, caching the information about the resource in order to avoid to have to call the expensive AAssetManager_open if the file is accessed again (e.g. by QFileInfo). Fixes: QTBUG-101161 Change-Id: Iaedf4cdf83d5116053b51895a6795d43bc60f942 Pick-to: 6.4 6.3 6.2 5.15 Reviewed-by: Rami Potinkara Reviewed-by: Ville Voutilainen --- .../android/qandroidassetsfileenginehandler.cpp | 64 ++++++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) (limited to 'src/plugins/platforms/android') diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index a25aa673d3..165f953357 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -231,9 +231,10 @@ public: { Q_UNUSED(permissions); - if (m_isFolder || (openMode & QIODevice::WriteOnly)) + if (!m_assetInfo || m_assetInfo->type != AssetItem::Type::File || (openMode & QIODevice::WriteOnly)) return false; - close(); + if (m_assetFile) + return true; m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER); return m_assetFile; } @@ -245,7 +246,6 @@ public: m_assetFile = 0; return true; } - m_isFolder = false; return false; } @@ -286,10 +286,12 @@ public: { FileFlags commonFlags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag); FileFlags flags; - if (m_assetFile) - flags = FileType | commonFlags; - else if (m_isFolder) - flags = DirectoryType | commonFlags; + if (m_assetInfo) { + if (m_assetInfo->type == AssetItem::Type::File) + flags = FileType | commonFlags; + else if (m_assetInfo->type == AssetItem::Type::Folder) + flags = DirectoryType | commonFlags; + } return type & flags; } @@ -324,21 +326,42 @@ public: return; close(); m_fileName = cleanedAssetPath(file); - switch (FolderIterator::fileType(m_fileName)) { - case AssetItem::Type::File: - open(QIODevice::ReadOnly, std::nullopt); - break; - case AssetItem::Type::Folder: - m_isFolder = true; - break; - case AssetItem::Type::Invalid: - break; + + { + QMutexLocker lock(&m_assetsInfoCacheMutex); + QSharedPointer *assetInfoPtr = m_assetsInfoCache.object(m_fileName); + if (assetInfoPtr) { + m_assetInfo = *assetInfoPtr; + return; + } } + + QSharedPointer *newAssetInfoPtr = new QSharedPointer(new AssetItem); + + m_assetInfo = *newAssetInfoPtr; + m_assetInfo->name = m_fileName; + m_assetInfo->type = AssetItem::Type::Invalid; + + m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER); + + if (m_assetFile) { + m_assetInfo->type = AssetItem::Type::File; + } else { + auto *assetDir = AAssetManager_openDir(m_assetManager, m_fileName.toUtf8()); + if (assetDir) { + if (AAssetDir_getNextFileName(assetDir)) + m_assetInfo->type = AssetItem::Type::Folder; + AAssetDir_close(assetDir); + } + } + + QMutexLocker lock(&m_assetsInfoCacheMutex); + m_assetsInfoCache.insert(m_fileName, newAssetInfoPtr); } Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override { - if (m_isFolder) + if (m_assetInfo && m_assetInfo->type == AssetItem::Type::Folder) return new AndroidAbstractFileEngineIterator(filters, filterNames, m_fileName); return nullptr; } @@ -348,9 +371,14 @@ private: AAssetManager *m_assetManager = nullptr; // initialize with a name that can't be used as a file name QString m_fileName = "."_L1; - bool m_isFolder = false; + QSharedPointer m_assetInfo; + + static QCache> m_assetsInfoCache; + static QMutex m_assetsInfoCacheMutex; }; +QCache> AndroidAbstractFileEngine::m_assetsInfoCache(std::max(200, qEnvironmentVariableIntValue("QT_ANDROID_MAX_FILEINFO_ASSETS_CACHE_SIZE"))); +QMutex AndroidAbstractFileEngine::m_assetsInfoCacheMutex; AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler() { -- cgit v1.2.3