summaryrefslogtreecommitdiff
path: root/libs/androidfw
diff options
context:
space:
mode:
author Biswarup Pal <biswarupp@google.com> 2025-02-19 07:02:20 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-19 07:02:20 -0800
commit7290ef5f898fffa4ad700435fb00158bcaeb2302 (patch)
tree1c632eb4f10b6815d65371409595bb78d69024ea /libs/androidfw
parent3a032ce3db6ce5aca6d8a3c5a3aee19324c18112 (diff)
parentbc306b4c9c05009804ae3baabc61a4b87b56fe65 (diff)
Merge "Filter overlays based on constraints during resource resolution" into main
Diffstat (limited to 'libs/androidfw')
-rw-r--r--libs/androidfw/AssetManager2.cpp82
-rw-r--r--libs/androidfw/Idmap.cpp42
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h10
-rw-r--r--libs/androidfw/include/androidfw/Idmap.h43
4 files changed, 124 insertions, 53 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index f5e10d94452f..7a51c20f7672 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -44,6 +44,9 @@ namespace android {
namespace {
+constexpr int32_t kDefaultDisplayId = 0;
+constexpr int32_t kDefaultDeviceId = 0;
+
using EntryValue = std::variant<Res_value, incfs::verified_map_ptr<ResTable_map_entry>>;
/* NOTE: table_entry has been verified in LoadedPackage::GetEntryFromOffset(),
@@ -61,7 +64,7 @@ base::expected<EntryValue, IOError> GetEntryValue(
return table_entry->value();
}
-} // namespace
+} // namespace
struct FindEntryResult {
// The cookie representing the ApkAssets in which the value resides.
@@ -99,14 +102,15 @@ struct Theme::Entry {
Res_value value;
};
-AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) {
+AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration)
+ : display_id_(kDefaultDisplayId), device_id_(kDefaultDeviceId) {
configurations_.push_back(configuration);
// Don't invalidate caches here as there's nothing cached yet.
SetApkAssets(apk_assets, false);
}
-AssetManager2::AssetManager2() {
+AssetManager2::AssetManager2() : display_id_(kDefaultDisplayId), device_id_(kDefaultDeviceId) {
configurations_.emplace_back();
}
@@ -172,8 +176,7 @@ void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) {
// to take effect.
auto iter = target_assets_package_ids.find(loaded_idmap->TargetApkPath());
if (iter == target_assets_package_ids.end()) {
- LOG(INFO) << "failed to find target package for overlay "
- << loaded_idmap->OverlayApkPath();
+ LOG(INFO) << "failed to find target package for overlay " << loaded_idmap->OverlayApkPath();
} else {
uint8_t target_package_id = iter->second;
@@ -189,10 +192,11 @@ void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) {
<< " assigned package group";
PackageGroup& target_package_group = package_groups_[target_idx];
- target_package_group.overlays_.push_back(
- ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
- overlay_ref_table.get()),
- apk_assets_cookies[apk_assets]});
+ target_package_group.overlays_.push_back(ConfiguredOverlay{
+ loaded_idmap->GetTargetResourcesMap(target_package_id, overlay_ref_table.get()),
+ apk_assets_cookies[apk_assets],
+ IsAnyOverlayConstraintSatisfied(loaded_idmap->GetConstraints())
+ });
}
}
@@ -291,7 +295,7 @@ void AssetManager2::DumpToLog() const {
}
LOG(INFO) << "Package ID map: " << list;
- for (const auto& package_group: package_groups_) {
+ for (const auto& package_group : package_groups_) {
list = "";
for (const auto& package : package_group.packages_) {
const LoadedPackage* loaded_package = package.loaded_package_;
@@ -347,7 +351,6 @@ std::shared_ptr<const DynamicRefTable> AssetManager2::GetDynamicRefTableForCooki
const std::unordered_map<std::string, std::string>*
AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const {
-
if (package_id >= package_ids_.size()) {
return nullptr;
}
@@ -462,6 +465,28 @@ void AssetManager2::SetConfigurations(std::span<const ResTable_config> configura
}
}
+void AssetManager2::SetOverlayConstraints(int32_t display_id, int32_t device_id) {
+ bool changed = false;
+ if (display_id_ != display_id) {
+ display_id_ = display_id;
+ changed = true;
+ }
+ if (device_id_ != device_id) {
+ device_id_ = device_id;
+ changed = true;
+ }
+ if (changed) {
+ // Enable/disable overlays based on current constraints
+ for (PackageGroup& group : package_groups_) {
+ for (auto &overlay: group.overlays_) {
+ overlay.enabled = IsAnyOverlayConstraintSatisfied(
+ overlay.overlay_res_maps_.GetConstraints());
+ }
+ }
+ InvalidateCaches(static_cast<uint32_t>(-1));
+ }
+}
+
std::set<AssetManager2::ApkAssetsPtr> AssetManager2::GetNonSystemOverlays() const {
std::set<ApkAssetsPtr> non_system_overlays;
for (const PackageGroup& package_group : package_groups_) {
@@ -475,6 +500,8 @@ std::set<AssetManager2::ApkAssetsPtr> AssetManager2::GetNonSystemOverlays() cons
if (!found_system_package) {
auto op = StartOperation();
+ // Return all overlays, including the disabled ones as this is used for static info
+ // collection only.
for (const ConfiguredOverlay& overlay : package_group.overlays_) {
if (const auto& asset = GetApkAssets(overlay.cookie)) {
non_system_overlays.insert(std::move(asset));
@@ -651,7 +678,6 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
auto op = StartOperation();
-
// Retrieve the package group from the package id of the resource id.
if (UNLIKELY(!is_valid_resid(resid))) {
LOG(ERROR) << base::StringPrintf("Invalid resource ID 0x%08x.", resid);
@@ -672,7 +698,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
std::optional<FindEntryResult> final_result;
bool final_has_locale = false;
bool final_overlaid = false;
- for (auto & config : configurations_) {
+ for (auto& config : configurations_) {
// Might use this if density_override != 0.
ResTable_config density_override_config;
@@ -698,7 +724,8 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
}
if (!assets->IsLoader()) {
for (const auto& id_map : package_group.overlays_) {
- auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
+ auto overlay_entry = id_map.enabled ?
+ id_map.overlay_res_maps_.Lookup(resid) : IdmapResMap::Result();
if (!overlay_entry) {
// No id map entry exists for this target resource.
continue;
@@ -708,7 +735,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
ConfigDescription best_frro_config;
Res_value best_frro_value;
bool frro_found = false;
- for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
+ for (const auto& [config, value] : overlay_entry.GetInlineValue()) {
if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
&& config.match(*desired_config)) {
frro_found = true;
@@ -1011,7 +1038,7 @@ std::string AssetManager2::GetLastResourceResolution() const {
resid, resource_name_string.c_str(), conf.toString().c_str());
char str[40];
str[0] = '\0';
- for(auto iter = configurations_.begin(); iter < configurations_.end(); iter++) {
+ for (auto iter = configurations_.begin(); iter < configurations_.end(); iter++) {
iter->getBcp47Locale(str);
log_stream << base::StringPrintf(" %s%s", str, iter < configurations_.end() ? "," : "");
}
@@ -1504,7 +1531,7 @@ void AssetManager2::RebuildFilterList() {
package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
FilteredConfigGroup* group = nullptr;
for (const auto& type_entry : type_spec.type_entries) {
- for (auto & config : configurations_) {
+ for (auto& config : configurations_) {
if (type_entry.config.match(config)) {
if (!group) {
group = &package.filtered_configs_.editItemAt(type_id - 1);
@@ -1521,6 +1548,27 @@ void AssetManager2::RebuildFilterList() {
}
}
+bool AssetManager2::IsAnyOverlayConstraintSatisfied(const Idmap_constraints& constraints) const {
+ if (constraints.constraint_count == 0) {
+ // There are no constraints, return true.
+ return true;
+ }
+
+ for (uint32_t i = 0; i < constraints.constraint_count; i++) {
+ auto constraint = constraints.constraint_entries[i];
+ if (constraint.constraint_type == kOverlayConstraintTypeDisplayId &&
+ constraint.constraint_value == display_id_) {
+ return true;
+ }
+ if (constraint.constraint_type == kOverlayConstraintTypeDeviceId &&
+ constraint.constraint_value == device_id_) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void AssetManager2::InvalidateCaches(uint32_t diff) {
cached_resolved_values_.clear();
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index f0ef97e5bdcc..8d1de1af56d2 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -56,13 +56,6 @@ struct Idmap_header {
// without having to read/store each header entry separately.
};
-struct Idmap_constraint {
- // Constraint type can be TYPE_DISPLAY_ID or TYP_DEVICE_ID, please refer
- // to ConstraintType in OverlayConstraint.java
- uint32_t constraint_type;
- uint32_t constraint_value;
-};
-
struct Idmap_data_header {
uint32_t target_entry_count;
uint32_t target_inline_entry_count;
@@ -148,12 +141,13 @@ status_t OverlayDynamicRefTable::lookupResourceIdNoRewrite(uint32_t* resId) cons
return DynamicRefTable::lookupResourceId(resId);
}
-IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
- Idmap_target_inline_entries inline_entries,
+IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, const Idmap_constraints& constraints,
+ Idmap_target_entries entries, Idmap_target_inline_entries inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
const ConfigDescription* configs, uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table)
: data_header_(data_header),
+ constraints_(constraints),
entries_(entries),
inline_entries_(inline_entries),
inline_entry_values_(inline_entry_values),
@@ -254,7 +248,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size
}
return std::string_view(data, *len);
}
-} // namespace
+} // namespace
// O_PATH is a lightweight way of creating an FD, only exists on Linux
#ifndef O_PATH
@@ -262,9 +256,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size
#endif
LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
- const Idmap_constraint* constraints,
- uint32_t constraints_count,
- const Idmap_data_header* data_header,
+ const Idmap_data_header* data_header, const Idmap_constraints& constraints,
Idmap_target_entries target_entries,
Idmap_target_inline_entries target_inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
@@ -272,9 +264,8 @@ LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* head
std::unique_ptr<ResStringPool>&& string_pool,
std::string_view overlay_apk_path, std::string_view target_apk_path)
: header_(header),
- constraints_(constraints),
- constraints_count_(constraints_count),
data_header_(data_header),
+ constraints_(constraints),
target_entries_(target_entries),
target_inline_entries_(target_inline_entries),
inline_entry_values_(inline_entry_values),
@@ -328,16 +319,20 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie
return {};
}
- auto constraints_count = ReadType<uint32_t>(&data_ptr, &data_size, "constraints count");
- if (!constraints_count) {
+ auto constraint_count = ReadType<uint32_t>(&data_ptr, &data_size, "constraint count");
+ if (!constraint_count) {
+ LOG(ERROR) << "idmap doesn't have constraint count";
return {};
}
- auto constraints = *constraints_count > 0 ?
- ReadType<Idmap_constraint>(&data_ptr, &data_size, "constraints", *constraints_count)
+ auto constraint_entries = *constraint_count > 0 ?
+ ReadType<Idmap_constraint>(&data_ptr, &data_size, "constraints", dtohl(*constraint_count))
: nullptr;
- if (*constraints_count > 0 && !constraints) {
+ if (*constraint_count > 0 && !constraint_entries) {
+ LOG(ERROR) << "no constraint entries in idmap with non-zero constraints";
return {};
}
+ Idmap_constraints constraints{.constraint_count = *constraint_count,
+ .constraint_entries = constraint_entries};
// Parse the idmap data blocks. Currently idmap2 can only generate one data block.
auto data_header = ReadType<Idmap_data_header>(&data_ptr, &data_size, "data header");
@@ -405,10 +400,9 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie
// Can't use make_unique because LoadedIdmap constructor is private.
return std::unique_ptr<LoadedIdmap>(
- new LoadedIdmap(std::string(idmap_path), header, constraints, *constraints_count,
- data_header, target_entries, target_inline_entries,
- target_inline_entry_values,configurations, overlay_entries,
- std::move(idmap_string_pool),*overlay_path, *target_path));
+ new LoadedIdmap(std::string(idmap_path), header, data_header, constraints, target_entries,
+ target_inline_entries, target_inline_entry_values, configurations,
+ overlay_entries, std::move(idmap_string_pool), *overlay_path, *target_path));
}
UpToDate LoadedIdmap::IsUpToDate() const {
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 0fdeefa09e26..a47fe6a7f50d 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -171,6 +171,8 @@ class AssetManager2 {
default_locale_ = default_locale;
}
+ void SetOverlayConstraints(int32_t display_id, int32_t device_id);
+
// Returns all configurations for which there are resources defined, or an I/O error if reading
// resource data failed.
//
@@ -389,6 +391,9 @@ class AssetManager2 {
// The cookie of the overlay assets.
ApkAssetsCookie cookie;
+
+ // Enable/disable status of the overlay based on current constraints of AssetManager.
+ bool enabled;
};
// Represents a logical package, which can be made up of many individual packages. Each package
@@ -457,6 +462,8 @@ class AssetManager2 {
// promoted apk assets when the last operation ends.
void FinishOperation() const;
+ bool IsAnyOverlayConstraintSatisfied(const Idmap_constraints& constraints) const;
+
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
// The second pair element is the promoted version of the assets, that is held for the duration
@@ -480,6 +487,9 @@ class AssetManager2 {
// may need to be purged.
ftl::SmallVector<ResTable_config, 1> configurations_;
+ int32_t display_id_;
+ int32_t device_id_;
+
// Cached set of bags. These are cached because they can inherit keys from parent bags,
// which involves some calculation.
mutable std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 0c0856315d8f..939b62462560 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -59,13 +59,25 @@ inline UpToDate fromBool(bool value) {
class LoadedIdmap;
class IdmapResMap;
struct Idmap_header;
-struct Idmap_constraint;
+struct Idmap_constraints;
struct Idmap_data_header;
-struct Idmap_target_entry;
struct Idmap_target_entry_inline;
struct Idmap_target_entry_inline_value;
-struct Idmap_overlay_entry;
+// LINT.IfChange
+constexpr int32_t kOverlayConstraintTypeDisplayId = 0;
+constexpr int32_t kOverlayConstraintTypeDeviceId = 1;
+// LINT.ThenChange(../../../../core/java/android/content/om/OverlayConstraint.java)
+
+struct Idmap_constraint {
+ // Constraint type can be kOverlayConstraintTypeDisplayId or kOverlayConstraintTypeDeviceId
+ const uint32_t constraint_type;
+ const uint32_t constraint_value;
+};
+struct Idmap_constraints {
+ const uint32_t constraint_count = 0;
+ const Idmap_constraint* constraint_entries = nullptr;
+};
struct Idmap_target_entries {
const uint32_t* target_id = nullptr;
const uint32_t* overlay_id = nullptr;
@@ -169,14 +181,19 @@ class IdmapResMap {
return overlay_ref_table_;
}
+ inline Idmap_constraints GetConstraints() const {
+ return constraints_;
+ }
+
private:
- explicit IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
- Idmap_target_inline_entries inline_entries,
+ explicit IdmapResMap(const Idmap_data_header* data_header, const Idmap_constraints& constraints,
+ Idmap_target_entries entries, Idmap_target_inline_entries inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
const ConfigDescription* configs, uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table);
const Idmap_data_header* data_header_;
+ Idmap_constraints constraints_;
Idmap_target_entries entries_;
Idmap_target_inline_entries inline_entries_;
const Idmap_target_entry_inline_value* inline_entry_values_;
@@ -210,8 +227,9 @@ class LoadedIdmap {
// Returns a mapping from target resource ids to overlay values.
IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table) const {
- return IdmapResMap(data_header_, target_entries_, target_inline_entries_, inline_entry_values_,
- configurations_, target_assigned_package_id, overlay_ref_table);
+ return IdmapResMap(data_header_, constraints_, target_entries_, target_inline_entries_,
+ inline_entry_values_, configurations_, target_assigned_package_id,
+ overlay_ref_table);
}
// Returns a dynamic reference table for a loaded overlay package.
@@ -223,14 +241,17 @@ class LoadedIdmap {
// LoadedIdmap.
UpToDate IsUpToDate() const;
+ inline const Idmap_constraints GetConstraints() const {
+ return constraints_;
+ }
+
protected:
// Exposed as protected so that tests can subclass and mock this class out.
LoadedIdmap() = default;
const Idmap_header* header_;
- const Idmap_constraint* constraints_;
- uint32_t constraints_count_;
const Idmap_data_header* data_header_;
+ Idmap_constraints constraints_;
Idmap_target_entries target_entries_;
Idmap_target_inline_entries target_inline_entries_;
const Idmap_target_entry_inline_value* inline_entry_values_;
@@ -247,9 +268,7 @@ class LoadedIdmap {
DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
explicit LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
- const Idmap_constraint* constraints,
- uint32_t constraints_count,
- const Idmap_data_header* data_header,
+ const Idmap_data_header* data_header, const Idmap_constraints& constraints,
Idmap_target_entries target_entries,
Idmap_target_inline_entries target_inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values_,