From d4b169173ad7805369204277580d3942cb08174a Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Tue, 23 Feb 2016 17:49:53 -0800 Subject: [PATCH] AssetManager: Cache a pre-filtered list of configurations When we set the parameters for a ResTable, we can pre-filter which resources match and only look at that smaller list when getting entries. This helps A LOT with types that have many configurations, like strings and all their various locales. Bug:25499111 Change-Id: Ie6894c44bc67e16a10dbe028c8f3e119e5c29ac7 --- include/androidfw/ResourceTypes.h | 7 ++++ libs/androidfw/ResourceTypes.cpp | 68 +++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index d8801b8709ee5..16bea79941771 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -1896,6 +1896,13 @@ private: mutable Mutex mLock; + // Mutex that controls access to the list of pre-filtered configurations + // to check when looking up entries. + // When iterating over a bag, the mLock mutex is locked. While mLock is locked, + // we do resource lookups. + // Mutex is not reentrant, so we must use a different lock than mLock. + mutable Mutex mFilteredConfigLock; + status_t mError; ResTable_config mParams; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 3277c36c8a332..c73bb584be3a9 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -3146,6 +3147,9 @@ struct ResTable::Entry { StringPoolRef keyStr; }; +template +using SharedVector = std::shared_ptr>; + struct ResTable::Type { Type(const Header* _header, const Package* _package, size_t count) @@ -3158,6 +3162,10 @@ struct ResTable::Type const uint32_t* typeSpecFlags; IdmapEntries idmapEntries; Vector configs; + + // The set of configurations that match the current parameters. + // This will be swapped with a new set when the parameters change. + SharedVector filteredConfigs; }; struct ResTable::Package @@ -4430,18 +4438,44 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, void ResTable::setParameters(const ResTable_config* params) { - mLock.lock(); + AutoMutex _lock(mLock); + AutoMutex _lock2(mFilteredConfigLock); + if (kDebugTableGetEntry) { ALOGI("Setting parameters: %s\n", params->toString().string()); } mParams = *params; - for (size_t i=0; iclearBagCache(); + + for (size_t t = 0; t < packageGroup->types.size(); t++) { + TypeList& typeList = packageGroup->types.editItemAt(t); + for (size_t ts = 0; ts < typeList.size(); ts++) { + Type* type = typeList.editItemAt(ts); + + SharedVector newFilteredConfigs = + std::make_shared>(); + for (size_t ti = 0; ti < type->configs.size(); ti++) { + ResTable_config config; + config.copyFromDtoH(type->configs[ti]->config); + + if (config.match(mParams)) { + newFilteredConfigs->add(type->configs[ti]); + } + } + + if (kDebugTableNoisy) { + ALOGD("Updating pkg=%zu type=%zu with %zu filtered configs", + p, t, newFilteredConfigs->size()); + } + type->filteredConfigs = newFilteredConfigs; + } } - mPackageGroups[i]->clearBagCache(); } - mLock.unlock(); } void ResTable::getParameters(ResTable_config* params) const @@ -5974,9 +6008,29 @@ status_t ResTable::getEntry( specFlags = -1; } - const size_t numConfigs = typeSpec->configs.size(); + const Vector* candidateConfigs = &typeSpec->configs; + + SharedVector filteredConfigs; + if (config && memcmp(&mParams, config, sizeof(mParams)) == 0) { + // Grab the lock first so we can safely get the current filtered list. + AutoMutex _lock(mFilteredConfigLock); + + // This configuration is equal to the one we have previously cached for, + // so use the filtered configs. + + if (typeSpec->filteredConfigs) { + // Grab a reference to the shared_ptr so it doesn't get destroyed while + // going through this list. + filteredConfigs = typeSpec->filteredConfigs; + + // Use this filtered list. + candidateConfigs = filteredConfigs.get(); + } + } + + const size_t numConfigs = candidateConfigs->size(); for (size_t c = 0; c < numConfigs; c++) { - const ResTable_type* const thisType = typeSpec->configs[c]; + const ResTable_type* const thisType = candidateConfigs->itemAt(c); if (thisType == NULL) { continue; }