summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/androidfw/AssetManager2.cpp31
-rw-r--r--libs/androidfw/AttributeResolution.cpp7
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h12
3 files changed, 36 insertions, 14 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 3e54dc67db76..d349628c2ab4 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -963,14 +963,25 @@ base::expected<AssetManager2::SelectedValue, NullOrIOError> AssetManager2::GetRe
}
base::expected<std::monostate, NullOrIOError> AssetManager2::ResolveReference(
- AssetManager2::SelectedValue& value) const {
+ AssetManager2::SelectedValue& value, bool cache_value) const {
if (value.type != Res_value::TYPE_REFERENCE || value.data == 0U) {
// Not a reference. Nothing to do.
return {};
}
- uint32_t combined_flags = value.flags;
- uint32_t resolve_resid = value.data;
+ const uint32_t original_flags = value.flags;
+ const uint32_t original_resid = value.data;
+ if (cache_value) {
+ auto cached_value = cached_resolved_values_.find(value.data);
+ if (cached_value != cached_resolved_values_.end()) {
+ value = cached_value->second;
+ value.flags |= original_flags;
+ return {};
+ }
+ }
+
+ uint32_t combined_flags = 0U;
+ uint32_t resolve_resid = original_resid;
constexpr const uint32_t kMaxIterations = 20;
for (uint32_t i = 0U;; i++) {
auto result = GetResource(resolve_resid, true /*may_be_bag*/);
@@ -981,9 +992,15 @@ base::expected<std::monostate, NullOrIOError> AssetManager2::ResolveReference(
if (result->type != Res_value::TYPE_REFERENCE ||
result->data == Res_value::DATA_NULL_UNDEFINED ||
result->data == resolve_resid || i == kMaxIterations) {
- // This reference can't be resolved, so exit now and let the caller deal with it.
+ result->flags |= combined_flags;
+ if (cache_value) {
+ cached_resolved_values_[original_resid] = *result;
+ }
+
+ // Add the original flags after caching the result so queries with a different set of original
+ // flags do not include these original flags.
value = *result;
- value.flags |= combined_flags;
+ value.flags |= original_flags;
return {};
}
@@ -1353,6 +1370,8 @@ void AssetManager2::InvalidateCaches(uint32_t diff) {
++iter;
}
}
+
+ cached_resolved_values_.clear();
}
uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
@@ -1533,7 +1552,7 @@ base::expected<std::monostate, NullOrIOError> Theme::ResolveAttributeReference(
return base::unexpected(std::nullopt);
}
- auto resolve_result = asset_manager_->ResolveReference(*result);
+ auto resolve_result = asset_manager_->ResolveReference(*result, true /* cache_value */);
if (resolve_result.has_value()) {
result->flags |= value.flags;
value = *result;
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 71919fdbb736..347b4ec8346c 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -39,8 +39,7 @@ class XmlAttributeFinder
: public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
public:
explicit XmlAttributeFinder(const ResXMLParser* parser)
- : BackTrackingAttributeFinder(
- 0, parser != nullptr ? parser->getAttributeCount() : 0),
+ : BackTrackingAttributeFinder(0, parser != nullptr ? parser->getAttributeCount() : 0),
parser_(parser) {}
inline uint32_t GetAttribute(size_t index) const {
@@ -178,7 +177,7 @@ base::expected<std::monostate, IOError> ResolveAttrs(Theme* theme, uint32_t def_
value = *attr_value;
DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
- const auto result = assetmanager->ResolveReference(value);
+ const auto result = assetmanager->ResolveReference(value, true /* cache_value */);
if (UNLIKELY(IsIOError(result))) {
return base::unexpected(GetIOError(result.error()));
}
@@ -310,7 +309,7 @@ base::expected<std::monostate, IOError> ApplyStyle(Theme* theme, ResXMLParser* x
value = *attr_value;
DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
- auto result = assetmanager->ResolveReference(value);
+ auto result = assetmanager->ResolveReference(value, true /* cache_value */);
if (UNLIKELY(IsIOError(result))) {
return base::unexpected(GetIOError(result.error()));
}
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 4e993b0838a2..a92694c94b9f 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -264,11 +264,14 @@ class AssetManager2 {
// Resolves the resource referenced in `value` if the type is Res_value::TYPE_REFERENCE.
//
// If the data type is not Res_value::TYPE_REFERENCE, no work is done. Configuration flags of the
- // values pointed to by the reference are OR'd into `value.flags`.
+ // values pointed to by the reference are OR'd into `value.flags`. If `cache_value` is true, then
+ // the resolved value will be cached and used when attempting to resolve the resource id specified
+ // in `value`.
//
// Returns a null error if the resource could not be resolved, or an I/O error if reading
// resource data failed.
- base::expected<std::monostate, NullOrIOError> ResolveReference(SelectedValue& value) const;
+ base::expected<std::monostate, NullOrIOError> ResolveReference(SelectedValue& value,
+ bool cache_value = false) const;
// Retrieves the best matching bag/map resource with ID `resid`.
//
@@ -446,13 +449,14 @@ class AssetManager2 {
// a number of times for each view during View inspection.
mutable std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_;
+ // Cached set of resolved resource values.
+ mutable std::unordered_map<uint32_t, SelectedValue> cached_resolved_values_;
+
// Whether or not to save resource resolution steps
bool resource_resolution_logging_enabled_ = false;
struct Resolution {
-
struct Step {
-
enum class Type {
INITIAL,
BETTER_MATCH,