summaryrefslogtreecommitdiff
path: root/libs/androidfw/AssetManager2.cpp
diff options
context:
space:
mode:
author Xin Li <delphij@google.com> 2019-09-04 13:33:59 -0700
committer Xin Li <delphij@google.com> 2019-09-04 13:33:59 -0700
commite199ca954dff7fdfb06e6280695d34a957ed5efc (patch)
tree78be7fa3d9855c2a536e80ed4e7360845a968791 /libs/androidfw/AssetManager2.cpp
parent1bc876bb5b2b8506fe5e47421456c36ba4eefdea (diff)
parent9e89d13906739e856ed809ba81c32415770717c6 (diff)
DO NOT MERGE - Merge Android 10 into master
Bug: 139893257 Change-Id: I9e3c4fe5406c9913d50fe3b07d7f7cef7a246b96
Diffstat (limited to 'libs/androidfw/AssetManager2.cpp')
-rw-r--r--libs/androidfw/AssetManager2.cpp601
1 files changed, 510 insertions, 91 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 04cc5bb30ade..d20aecaaf0f6 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -20,7 +20,9 @@
#include <algorithm>
#include <iterator>
+#include <map>
#include <set>
+#include <sstream>
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
@@ -33,6 +35,12 @@
#endif
#endif
+#ifdef __ANDROID__
+#define ANDROID_LOG(x) LOG(x)
+#else
+#define ANDROID_LOG(x) std::stringstream()
+#endif
+
#include "androidfw/ResourceUtils.h"
namespace android {
@@ -161,6 +169,13 @@ void AssetManager2::DumpToLog() const {
LOG(INFO) << base::StringPrintf("PG (%02x): ",
package_group.dynamic_ref_table.mAssignedPackageId)
<< list;
+
+ for (size_t i = 0; i < 256; i++) {
+ if (package_group.dynamic_ref_table.mLookupTable[i] != 0) {
+ LOG(INFO) << base::StringPrintf(" e[0x%02x] -> 0x%02x", (uint8_t) i,
+ package_group.dynamic_ref_table.mLookupTable[i]);
+ }
+ }
}
}
@@ -194,6 +209,27 @@ const DynamicRefTable* AssetManager2::GetDynamicRefTableForCookie(ApkAssetsCooki
return nullptr;
}
+const std::unordered_map<std::string, std::string>*
+ AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const {
+
+ if (package_id >= package_ids_.size()) {
+ return nullptr;
+ }
+
+ const size_t idx = package_ids_[package_id];
+ if (idx == 0xff) {
+ return nullptr;
+ }
+
+ const PackageGroup& package_group = package_groups_[idx];
+ if (package_group.packages_.size() == 0) {
+ return nullptr;
+ }
+
+ const auto loaded_package = package_group.packages_[0].loaded_package_;
+ return &loaded_package->GetOverlayableMap();
+}
+
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
const int diff = configuration_.diff(configuration);
configuration_ = configuration;
@@ -209,10 +245,19 @@ std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_
ATRACE_NAME("AssetManager::GetResourceConfigurations");
std::set<ResTable_config> configurations;
for (const PackageGroup& package_group : package_groups_) {
+ bool found_system_package = false;
for (const ConfiguredPackage& package : package_group.packages_) {
if (exclude_system && package.loaded_package_->IsSystem()) {
+ found_system_package = true;
+ continue;
+ }
+
+ if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) {
+ // Overlays must appear after the target package to take effect. Any overlay found in the
+ // same package as a system package is able to overlay system resources.
continue;
}
+
package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
}
}
@@ -224,10 +269,19 @@ std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
ATRACE_NAME("AssetManager::GetResourceLocales");
std::set<std::string> locales;
for (const PackageGroup& package_group : package_groups_) {
+ bool found_system_package = false;
for (const ConfiguredPackage& package : package_group.packages_) {
if (exclude_system && package.loaded_package_->IsSystem()) {
+ found_system_package = true;
+ continue;
+ }
+
+ if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) {
+ // Overlays must appear after the target package to take effect. Any overlay found in the
+ // same package as a system package is able to overlay system resources.
continue;
}
+
package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
}
}
@@ -256,6 +310,9 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con
// Start from the back.
for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) {
const ApkAssets* apk_assets = *iter;
+ if (apk_assets->IsOverlay()) {
+ continue;
+ }
auto func = [&](const StringPiece& name, FileType type) {
AssetDir::FileInfo info;
@@ -282,6 +339,13 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
Asset::AccessMode mode,
ApkAssetsCookie* out_cookie) const {
for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
+ // Prevent RRO from modifying assets and other entries accessed by file
+ // path. Explicitly asking for a path in a given package (denoted by a
+ // cookie) is still OK.
+ if (apk_assets_[i]->IsOverlay()) {
+ continue;
+ }
+
std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
if (asset) {
if (out_cookie != nullptr) {
@@ -308,6 +372,7 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
bool /*stop_at_first_match*/,
+ bool ignore_configuration,
FindEntryResult* out_entry) const {
// Might use this if density_override != 0.
ResTable_config density_override_config;
@@ -331,7 +396,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
const uint8_t package_idx = package_ids_[package_id];
if (package_idx == 0xff) {
- LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid);
+ ANDROID_LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.",
+ package_id, resid);
return kInvalidCookie;
}
@@ -346,9 +412,12 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
uint32_t best_offset = 0u;
uint32_t type_flags = 0u;
+ Resolution::Step::Type resolution_type;
+ std::vector<Resolution::Step> resolution_steps;
+
// If desired_config is the same as the set configuration, then we can use our filtered list
// and we don't need to match the configurations, since they already matched.
- const bool use_fast_path = desired_config == &configuration_;
+ const bool use_fast_path = !ignore_configuration && desired_config == &configuration_;
for (size_t pi = 0; pi < package_count; pi++) {
const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
@@ -377,8 +446,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
// If the package is an overlay, then even configurations that are the same MUST be chosen.
const bool package_is_overlay = loaded_package->IsOverlay();
- const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
if (use_fast_path) {
+ const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
const size_t type_count = candidate_configs.size();
for (uint32_t i = 0; i < type_count; i++) {
@@ -386,21 +455,34 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
// We can skip calling ResTable_config::match() because we know that all candidate
// configurations that do NOT match have been filtered-out.
- if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
- (package_is_overlay && this_config.compare(*best_config) == 0)) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const ResTable_type* type_chunk = filtered_group.types[i];
- const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- continue;
- }
+ if (best_config == nullptr) {
+ resolution_type = Resolution::Step::Type::INITIAL;
+ } else if (this_config.isBetterThan(*best_config, desired_config)) {
+ resolution_type = Resolution::Step::Type::BETTER_MATCH;
+ } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+ resolution_type = Resolution::Step::Type::OVERLAID;
+ } else {
+ continue;
+ }
+
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const ResTable_type* type = filtered_group.types[i];
+ const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ best_cookie = cookie;
+ best_package = loaded_package;
+ best_type = type;
+ best_config = &this_config;
+ best_offset = offset;
- best_cookie = cookie;
- best_package = loaded_package;
- best_type = type_chunk;
- best_config = &this_config;
- best_offset = offset;
+ if (resource_resolution_logging_enabled_) {
+ resolution_steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
}
}
} else {
@@ -411,26 +493,48 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
// ResTable_config, we must copy it.
const auto iter_end = type_spec->types + type_spec->type_count;
for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config this_config;
- this_config.copyFromDtoH((*iter)->config);
-
- if (this_config.match(*desired_config)) {
- if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
- (package_is_overlay && this_config.compare(*best_config) == 0)) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- continue;
- }
+ ResTable_config this_config{};
- best_cookie = cookie;
- best_package = loaded_package;
- best_type = *iter;
- best_config_copy = this_config;
- best_config = &best_config_copy;
- best_offset = offset;
+ if (!ignore_configuration) {
+ this_config.copyFromDtoH((*iter)->config);
+ if (!this_config.match(*desired_config)) {
+ continue;
}
+
+ if (best_config == nullptr) {
+ resolution_type = Resolution::Step::Type::INITIAL;
+ } else if (this_config.isBetterThan(*best_config, desired_config)) {
+ resolution_type = Resolution::Step::Type::BETTER_MATCH;
+ } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+ resolution_type = Resolution::Step::Type::OVERLAID;
+ } else {
+ continue;
+ }
+ }
+
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ best_cookie = cookie;
+ best_package = loaded_package;
+ best_type = *iter;
+ best_config_copy = this_config;
+ best_config = &best_config_copy;
+ best_offset = offset;
+
+ if (ignore_configuration) {
+ // Any configuration will suffice, so break.
+ break;
+ }
+
+ if (resource_resolution_logging_enabled_) {
+ resolution_steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
}
}
}
@@ -452,55 +556,136 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
out_entry->entry_string_ref =
StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
+
+ if (resource_resolution_logging_enabled_) {
+ last_resolution.resid = resid;
+ last_resolution.cookie = best_cookie;
+ last_resolution.steps = resolution_steps;
+
+ // Cache only the type/entry refs since that's all that's needed to build name
+ last_resolution.type_string_ref =
+ StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
+ last_resolution.entry_string_ref =
+ StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+ }
+
return best_cookie;
}
-bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
- FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry);
+void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
+ resource_resolution_logging_enabled_ = enabled;
+
+ if (!enabled) {
+ last_resolution.cookie = kInvalidCookie;
+ last_resolution.resid = 0;
+ last_resolution.steps.clear();
+ last_resolution.type_string_ref = StringPoolRef();
+ last_resolution.entry_string_ref = StringPoolRef();
+ }
+}
+
+std::string AssetManager2::GetLastResourceResolution() const {
+ if (!resource_resolution_logging_enabled_) {
+ LOG(ERROR) << "Must enable resource resolution logging before getting path.";
+ return std::string();
+ }
+
+ auto cookie = last_resolution.cookie;
if (cookie == kInvalidCookie) {
- return false;
+ LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
+ return std::string();
}
+ uint32_t resid = last_resolution.resid;
+ std::vector<Resolution::Step>& steps = last_resolution.steps;
+
+ ResourceName resource_name;
+ std::string resource_name_string;
+
const LoadedPackage* package =
apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
- if (package == nullptr) {
- return false;
+
+ if (package != nullptr) {
+ ToResourceName(last_resolution.type_string_ref,
+ last_resolution.entry_string_ref,
+ package->GetPackageName(),
+ &resource_name);
+ resource_name_string = ToFormattedResourceString(&resource_name);
}
- out_name->package = package->GetPackageName().data();
- out_name->package_len = package->GetPackageName().size();
+ std::stringstream log_stream;
+ log_stream << base::StringPrintf("Resolution for 0x%08x ", resid)
+ << resource_name_string
+ << "\n\tFor config -"
+ << configuration_.toString();
+
+ std::string prefix;
+ for (Resolution::Step step : steps) {
+ switch (step.type) {
+ case Resolution::Step::Type::INITIAL:
+ prefix = "Found initial";
+ break;
+ case Resolution::Step::Type::BETTER_MATCH:
+ prefix = "Found better";
+ break;
+ case Resolution::Step::Type::OVERLAID:
+ prefix = "Overlaid";
+ break;
+ }
- out_name->type = entry.type_string_ref.string8(&out_name->type_len);
- out_name->type16 = nullptr;
- if (out_name->type == nullptr) {
- out_name->type16 = entry.type_string_ref.string16(&out_name->type_len);
- if (out_name->type16 == nullptr) {
- return false;
+ if (!prefix.empty()) {
+ log_stream << "\n\t" << prefix << ": " << *step.package_name;
+
+ if (!step.config_name.isEmpty()) {
+ log_stream << " -" << step.config_name;
+ }
}
}
- out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len);
- out_name->entry16 = nullptr;
- if (out_name->entry == nullptr) {
- out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len);
- if (out_name->entry16 == nullptr) {
- return false;
- }
+ return log_stream.str();
+}
+
+bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
+ FindEntryResult entry;
+ ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+ true /* stop_at_first_match */,
+ true /* ignore_configuration */, &entry);
+ if (cookie == kInvalidCookie) {
+ return false;
}
- return true;
+
+ const uint8_t package_idx = package_ids_[get_package_id(resid)];
+ if (package_idx == 0xff) {
+ LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.",
+ get_package_id(resid), resid);
+ return false;
+ }
+
+ const PackageGroup& package_group = package_groups_[package_idx];
+ auto cookie_iter = std::find(package_group.cookies_.begin(),
+ package_group.cookies_.end(), cookie);
+ if (cookie_iter == package_group.cookies_.end()) {
+ return false;
+ }
+
+ long package_pos = std::distance(package_group.cookies_.begin(), cookie_iter);
+ const LoadedPackage* package = package_group.packages_[package_pos].loaded_package_;
+ return ToResourceName(entry.type_string_ref,
+ entry.entry_string_ref,
+ package->GetPackageName(),
+ out_name);
}
bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
+ ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+ false /* stop_at_first_match */,
+ true /* ignore_configuration */, &entry);
if (cookie != kInvalidCookie) {
*out_flags = entry.type_flags;
- return cookie;
+ return true;
}
- return kInvalidCookie;
+ return false;
}
ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
@@ -508,8 +693,8 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
ResTable_config* out_selected_config,
uint32_t* out_flags) const {
FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, density_override, false /* stop_at_first_match */, &entry);
+ ApkAssetsCookie cookie = FindEntry(resid, density_override, false /* stop_at_first_match */,
+ false /* ignore_configuration */, &entry);
if (cookie == kInvalidCookie) {
return kInvalidCookie;
}
@@ -567,22 +752,42 @@ ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_valu
return cookie;
}
+const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) {
+ auto cached_iter = cached_bag_resid_stacks_.find(resid);
+ if (cached_iter != cached_bag_resid_stacks_.end()) {
+ return cached_iter->second;
+ } else {
+ auto found_resids = std::vector<uint32_t>();
+ GetBag(resid, found_resids);
+ // Cache style stacks if they are not already cached.
+ cached_bag_resid_stacks_[resid] = found_resids;
+ return found_resids;
+ }
+}
+
const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
auto found_resids = std::vector<uint32_t>();
- return GetBag(resid, found_resids);
+ auto bag = GetBag(resid, found_resids);
+
+ // Cache style stacks if they are not already cached.
+ auto cached_iter = cached_bag_resid_stacks_.find(resid);
+ if (cached_iter == cached_bag_resid_stacks_.end()) {
+ cached_bag_resid_stacks_[resid] = found_resids;
+ }
+ return bag;
}
const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) {
- ATRACE_NAME("AssetManager::GetBag");
-
auto cached_iter = cached_bags_.find(resid);
if (cached_iter != cached_bags_.end()) {
return cached_iter->second.get();
}
FindEntryResult entry;
- ApkAssetsCookie cookie =
- FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
+ ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+ false /* stop_at_first_match */,
+ false /* ignore_configuration */,
+ &entry);
if (cookie == kInvalidCookie) {
return nullptr;
}
@@ -629,6 +834,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
new_entry->key = new_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
+ new_entry->style = resid;
new_entry->value.copyFrom_dtoh(map_entry->value);
status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
if (err != NO_ERROR) {
@@ -687,6 +893,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->value.copyFrom_dtoh(map_entry->value);
+ new_entry->style = resid;
status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
if (err != NO_ERROR) {
LOG(ERROR) << base::StringPrintf(
@@ -723,6 +930,7 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->value.copyFrom_dtoh(map_entry->value);
+ new_entry->style = resid;
status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
if (err != NO_ERROR) {
LOG(ERROR) << base::StringPrintf("Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.",
@@ -852,6 +1060,8 @@ void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
}
void AssetManager2::InvalidateCaches(uint32_t diff) {
+ cached_bag_resid_stacks_.clear();
+
if (diff == 0xffffffffu) {
// Everything must go.
cached_bags_.clear();
@@ -869,6 +1079,17 @@ void AssetManager2::InvalidateCaches(uint32_t diff) {
}
}
+uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) {
+ for (auto& package_group : package_groups_) {
+ for (auto& package2 : package_group.packages_) {
+ if (package2.loaded_package_ == package) {
+ return package_group.dynamic_ref_table.mAssignedPackageId;
+ }
+ }
+ }
+ return 0;
+}
+
std::unique_ptr<Theme> AssetManager2::NewTheme() {
return std::unique_ptr<Theme>(new Theme(this));
}
@@ -1054,44 +1275,242 @@ void Theme::Clear() {
}
}
-bool Theme::SetTo(const Theme& o) {
+void Theme::SetTo(const Theme& o) {
if (this == &o) {
- return true;
+ return;
}
type_spec_flags_ = o.type_spec_flags_;
- const bool copy_only_system = asset_manager_ != o.asset_manager_;
+ if (asset_manager_ == o.asset_manager_) {
+ // The theme comes from the same asset manager so all theme data can be copied exactly
+ for (size_t p = 0; p < packages_.size(); p++) {
+ const Package *package = o.packages_[p].get();
+ if (package == nullptr) {
+ // The other theme doesn't have this package, clear ours.
+ packages_[p].reset();
+ continue;
+ }
- for (size_t p = 0; p < packages_.size(); p++) {
- const Package* package = o.packages_[p].get();
- if (package == nullptr || (copy_only_system && p != 0x01)) {
- // The other theme doesn't have this package, clear ours.
- packages_[p].reset();
- continue;
+ if (packages_[p] == nullptr) {
+ // The other theme has this package, but we don't. Make one.
+ packages_[p].reset(new Package());
+ }
+
+ for (size_t t = 0; t < package->types.size(); t++) {
+ const ThemeType *type = package->types[t].get();
+ if (type == nullptr) {
+ // The other theme doesn't have this type, clear ours.
+ packages_[p]->types[t].reset();
+ continue;
+ }
+
+ // Create a new type and update it to theirs.
+ const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
+ void *copied_data = malloc(type_alloc_size);
+ memcpy(copied_data, type, type_alloc_size);
+ packages_[p]->types[t].reset(reinterpret_cast<ThemeType *>(copied_data));
+ }
+ }
+ } else {
+ std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
+ typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
+ std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
+
+ // Determine which ApkAssets are loaded in both theme AssetManagers.
+ std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
+ for (size_t i = 0; i < src_assets.size(); i++) {
+ const ApkAssets* src_asset = src_assets[i];
+
+ std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets();
+ for (size_t j = 0; j < dest_assets.size(); j++) {
+ const ApkAssets* dest_asset = dest_assets[j];
+
+ // Map the runtime package of the source apk asset to the destination apk asset.
+ if (src_asset->GetPath() == dest_asset->GetPath()) {
+ const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
+ src_asset->GetLoadedArsc()->GetPackages();
+ const std::vector<std::unique_ptr<const LoadedPackage>>& dest_packages =
+ dest_asset->GetLoadedArsc()->GetPackages();
+
+ SourceToDestinationRuntimePackageMap package_map;
+
+ // The source and destination package should have the same number of packages loaded in
+ // the same order.
+ const size_t N = src_packages.size();
+ CHECK(N == dest_packages.size())
+ << " LoadedArsc " << src_asset->GetPath() << " differs number of packages.";
+ for (size_t p = 0; p < N; p++) {
+ auto& src_package = src_packages[p];
+ auto& dest_package = dest_packages[p];
+ CHECK(src_package->GetPackageName() == dest_package->GetPackageName())
+ << " Package " << src_package->GetPackageName() << " differs in load order.";
+
+ int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get());
+ int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get());
+ package_map[src_package_id] = dest_package_id;
+ }
+
+ src_to_dest_asset_cookies.insert(std::make_pair(i, j));
+ src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
+ break;
+ }
+ }
}
- if (packages_[p] == nullptr) {
- // The other theme has this package, but we don't. Make one.
- packages_[p].reset(new Package());
+ // Reset the data in the destination theme.
+ for (size_t p = 0; p < packages_.size(); p++) {
+ if (packages_[p] != nullptr) {
+ packages_[p].reset();
+ }
}
- for (size_t t = 0; t < package->types.size(); t++) {
- const ThemeType* type = package->types[t].get();
+ for (size_t p = 0; p < packages_.size(); p++) {
+ const Package *package = o.packages_[p].get();
+ if (package == nullptr) {
+ continue;
+ }
+
+ for (size_t t = 0; t < package->types.size(); t++) {
+ const ThemeType *type = package->types[t].get();
+ if (type == nullptr) {
+ continue;
+ }
+
+ for (size_t e = 0; e < type->entry_count; e++) {
+ const ThemeEntry &entry = type->entries[e];
+ if (entry.value.dataType == Res_value::TYPE_NULL &&
+ entry.value.data != Res_value::DATA_NULL_EMPTY) {
+ continue;
+ }
+
+ bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_REFERENCE
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
+ && entry.value.data != 0x0;
+
+ // If the attribute value represents an attribute or reference, the package id of the
+ // value needs to be rewritten to the package id of the value in the destination.
+ uint32_t attribute_data = entry.value.data;
+ if (is_reference) {
+ // Determine the package id of the reference in the destination AssetManager.
+ auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
+ if (value_package_map == src_asset_cookie_id_map.end()) {
+ continue;
+ }
+
+ auto value_dest_package = value_package_map->second.find(
+ get_package_id(entry.value.data));
+ if (value_dest_package == value_package_map->second.end()) {
+ continue;
+ }
+
+ attribute_data = fix_package_id(entry.value.data, value_dest_package->second);
+ }
+
+ // Find the cookie of the value in the destination. If the source apk is not loaded in the
+ // destination, only copy resources that do not reference resources in the source.
+ ApkAssetsCookie data_dest_cookie;
+ auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
+ if (value_dest_cookie != src_to_dest_asset_cookies.end()) {
+ data_dest_cookie = value_dest_cookie->second;
+ } else {
+ if (is_reference || entry.value.dataType == Res_value::TYPE_STRING) {
+ continue;
+ } else {
+ data_dest_cookie = 0x0;
+ }
+ }
+
+ // The package id of the attribute needs to be rewritten to the package id of the
+ // attribute in the destination.
+ int attribute_dest_package_id = p;
+ if (attribute_dest_package_id != 0x01) {
+ // Find the cookie of the attribute resource id in the source AssetManager
+ FindEntryResult attribute_entry_result;
+ ApkAssetsCookie attribute_cookie =
+ o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
+ true /* stop_at_first_match */,
+ true /* ignore_configuration */,
+ &attribute_entry_result);
+
+ // Determine the package id of the attribute in the destination AssetManager.
+ auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
+ if (attribute_package_map == src_asset_cookie_id_map.end()) {
+ continue;
+ }
+ auto attribute_dest_package = attribute_package_map->second.find(
+ attribute_dest_package_id);
+ if (attribute_dest_package == attribute_package_map->second.end()) {
+ continue;
+ }
+ attribute_dest_package_id = attribute_dest_package->second;
+ }
+
+ // Lazily instantiate the destination package.
+ std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id];
+ if (dest_package == nullptr) {
+ dest_package.reset(new Package());
+ }
+
+ // Lazily instantiate and resize the destination type.
+ util::unique_cptr<ThemeType>& dest_type = dest_package->types[t];
+ if (dest_type == nullptr || dest_type->entry_count < type->entry_count) {
+ const size_t type_alloc_size = sizeof(ThemeType)
+ + (type->entry_count * sizeof(ThemeEntry));
+ void* dest_data = malloc(type_alloc_size);
+ memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry));
+
+ // Copy the existing destination type values if the type is resized.
+ if (dest_type != nullptr) {
+ memcpy(dest_data, type, sizeof(ThemeType)
+ + (dest_type->entry_count * sizeof(ThemeEntry)));
+ }
+
+ dest_type.reset(reinterpret_cast<ThemeType *>(dest_data));
+ dest_type->entry_count = type->entry_count;
+ }
+
+ dest_type->entries[e].cookie = data_dest_cookie;
+ dest_type->entries[e].value.dataType = entry.value.dataType;
+ dest_type->entries[e].value.data = attribute_data;
+ dest_type->entries[e].type_spec_flags = entry.type_spec_flags;
+ }
+ }
+ }
+ }
+}
+
+void Theme::Dump() const {
+ base::ScopedLogSeverity _log(base::INFO);
+ LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
+
+ for (int p = 0; p < packages_.size(); p++) {
+ auto& package = packages_[p];
+ if (package == nullptr) {
+ continue;
+ }
+
+ for (int t = 0; t < package->types.size(); t++) {
+ auto& type = package->types[t];
if (type == nullptr) {
- // The other theme doesn't have this type, clear ours.
- packages_[p]->types[t].reset();
continue;
}
- // Create a new type and update it to theirs.
- const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
- void* copied_data = malloc(type_alloc_size);
- memcpy(copied_data, type, type_alloc_size);
- packages_[p]->types[t].reset(reinterpret_cast<ThemeType*>(copied_data));
+ for (int e = 0; e < type->entry_count; e++) {
+ auto& entry = type->entries[e];
+ if (entry.value.dataType == Res_value::TYPE_NULL &&
+ entry.value.data != Res_value::DATA_NULL_EMPTY) {
+ continue;
+ }
+
+ LOG(INFO) << base::StringPrintf(" entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
+ make_resid(p, t, e), entry.value.data,
+ entry.value.dataType, entry.cookie);
+ }
}
}
- return true;
}
} // namespace android