diff options
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 7 | ||||
-rw-r--r-- | libs/androidfw/AssetManager2.cpp | 64 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/AssetManager2.h | 14 | ||||
-rw-r--r-- | tools/aapt2/ResourceUtils.cpp | 36 | ||||
-rw-r--r-- | tools/aapt2/ResourceUtils.h | 7 | ||||
-rw-r--r-- | tools/aapt2/cmd/Link.cpp | 36 | ||||
-rw-r--r-- | tools/aapt2/process/SymbolTable.cpp | 160 | ||||
-rw-r--r-- | tools/aapt2/process/SymbolTable.h | 10 | ||||
-rw-r--r-- | tools/aapt2/process/SymbolTable_test.cpp | 72 | ||||
-rw-r--r-- | tools/aapt2/test/Fixture.cpp | 10 | ||||
-rw-r--r-- | tools/aapt2/test/Fixture.h | 3 | ||||
-rw-r--r-- | tools/aapt2/util/Files.cpp | 21 | ||||
-rw-r--r-- | tools/aapt2/util/Files_test.cpp | 36 |
13 files changed, 311 insertions, 165 deletions
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index a212f47c0104..af2d41399016 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -343,7 +343,9 @@ static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr, assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) { if (this_package_name == std_package_name) { map = assetmanager->GetOverlayableMapForPackage(package_id); + return false; } + return true; }); if (map == nullptr) { @@ -521,15 +523,16 @@ static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/ return nullptr; } - assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) { + assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) -> bool { jstring jpackage_name = env->NewStringUTF(package_name.c_str()); if (jpackage_name == nullptr) { // An exception is pending. - return; + return false; } env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id), jpackage_name); + return true; }); return sparse_array; } diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 66d8542553d2..d7b84ff1060d 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -356,6 +356,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; @@ -399,7 +400,7 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // 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]; @@ -475,21 +476,23 @@ 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); + ResTable_config this_config{}; - if (!this_config.match(*desired_config)) { - continue; - } + 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; + 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. @@ -506,6 +509,11 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri 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(), @@ -622,8 +630,9 @@ std::string AssetManager2::GetLastResourceResolution() const { 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); + ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, + true /* stop_at_first_match */, + true /* ignore_configuration */, &entry); if (cookie == kInvalidCookie) { return false; } @@ -652,13 +661,14 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons 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, @@ -666,8 +676,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; } @@ -759,8 +769,10 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& } 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; } @@ -1387,7 +1399,9 @@ void Theme::SetTo(const Theme& o) { // Find the cookie of the attribute resource id FindEntryResult attribute_entry_result; ApkAssetsCookie attribute_cookie = - o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false, + 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 diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index fc5aa9c7f1b9..1e2b36cb1703 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -257,11 +257,12 @@ class AssetManager2 { // Creates a new Theme from this AssetManager. std::unique_ptr<Theme> NewTheme(); - template <typename Func> - void ForEachPackage(Func func) const { + void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func) const { for (const PackageGroup& package_group : package_groups_) { - func(package_group.packages_.front().loaded_package_->GetPackageName(), - package_group.dynamic_ref_table.mAssignedPackageId); + if (!func(package_group.packages_.front().loaded_package_->GetPackageName(), + package_group.dynamic_ref_table.mAssignedPackageId)) { + return; + } } } @@ -282,10 +283,13 @@ class AssetManager2 { // care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete // and should not be used. // + // When `ignore_configuration` is true, FindEntry will return always select the first entry in + // for the type seen regardless of its configuration. + // // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds. ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match, - FindEntryResult* out_entry) const; + bool ignore_configuration, FindEntryResult* out_entry) const; // Assigns package IDs to all shared library ApkAssets. // Should be called whenever the ApkAssets are changed. diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 0032960ff93e..ffc1a92a88b0 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -44,6 +44,7 @@ constexpr int32_t kNonBreakingSpace = 0xa0; Maybe<ResourceName> ToResourceName( const android::ResTable::resource_name& name_in) { + // TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2 ResourceName name_out; if (!name_in.package) { return {}; @@ -79,6 +80,41 @@ Maybe<ResourceName> ToResourceName( return name_out; } +Maybe<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in) { + ResourceName name_out; + if (!name_in.package) { + return {}; + } + + name_out.package = std::string(name_in.package, name_in.package_len); + + const ResourceType* type; + if (name_in.type16) { + type = ParseResourceType( + util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len))); + } else if (name_in.type) { + type = ParseResourceType(StringPiece(name_in.type, name_in.type_len)); + } else { + return {}; + } + + if (!type) { + return {}; + } + + name_out.type = *type; + + if (name_in.entry16) { + name_out.entry = + util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len)); + } else if (name_in.entry) { + name_out.entry = std::string(name_in.entry, name_in.entry_len); + } else { + return {}; + } + return name_out; +} + bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref, bool* out_private) { if (str.empty()) { diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h index e282fd58d261..a8a312005e4e 100644 --- a/tools/aapt2/ResourceUtils.h +++ b/tools/aapt2/ResourceUtils.h @@ -20,6 +20,7 @@ #include <functional> #include <memory> +#include "androidfw/AssetManager2.h" #include "androidfw/ConfigDescription.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" @@ -78,6 +79,12 @@ Maybe<ResourceName> ToResourceName( const android::ResTable::resource_name& name); /** + * Convert an android::AssetManager2::ResourceName to an aapt::ResourceName struct. + */ +Maybe<ResourceName> ToResourceName( + const android::AssetManager2::ResourceName& name_in); + +/** * Returns a boolean value if the string is equal to TRUE, true, True, FALSE, * false, or False. */ diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 22edd2f2055a..a7b8d2535e79 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -717,28 +717,20 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path, return true; } -static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) { +static android::ApkAssetsCookie FindFrameworkAssetManagerCookie( + const android::AssetManager2& assets) { using namespace android; // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so // we're looking for the first attribute resource in the system package. - const ResTable& table = assets.getResources(true); - Res_value val; - ssize_t idx = table.getResource(0x01010000, &val, true); - if (idx != NO_ERROR) { - // Try as a bag. - const ResTable::bag_entry* entry; - ssize_t cnt = table.lockBag(0x01010000, &entry); - if (cnt >= 0) { - idx = entry->stringBlock; - } - table.unlockBag(entry); - } - - if (idx < 0) { - return 0; - } - return table.getTableCookie(idx); + Res_value val{}; + ResTable_config config{}; + uint32_t type_spec_flags; + ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */, + 0 /** density_override */, &val, &config, + &type_spec_flags); + + return idx; } class Linker { @@ -750,17 +742,17 @@ class Linker { file_collection_(util::make_unique<io::FileCollection>()) { } - void ExtractCompileSdkVersions(android::AssetManager* assets) { + void ExtractCompileSdkVersions(android::AssetManager2* assets) { using namespace android; - int32_t cookie = FindFrameworkAssetManagerCookie(*assets); - if (cookie == 0) { + android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets); + if (cookie == android::kInvalidCookie) { // No Framework assets loaded. Not a failure. return; } std::unique_ptr<Asset> manifest( - assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER)); + assets->OpenNonAsset(kAndroidManifestPath, cookie, Asset::AccessMode::ACCESS_BUFFER)); if (manifest == nullptr) { // No errors. return; diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp index a844a43698e5..78e00746f6cb 100644 --- a/tools/aapt2/process/SymbolTable.cpp +++ b/tools/aapt2/process/SymbolTable.cpp @@ -20,9 +20,11 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" -#include "androidfw/AssetManager.h" +#include "androidfw/Asset.h" +#include "androidfw/AssetManager2.h" #include "androidfw/ConfigDescription.h" #include "androidfw/ResourceTypes.h" +#include "androidfw/ResourceUtils.h" #include "NameMangler.h" #include "Resource.h" @@ -30,6 +32,7 @@ #include "ValueVisitor.h" #include "util/Util.h" +using ::android::ApkAssets; using ::android::ConfigDescription; using ::android::StringPiece; using ::android::StringPiece16; @@ -214,51 +217,75 @@ std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::FindByName( } bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) { - int32_t cookie = 0; - return assets_.addAssetPath(android::String8(path.data(), path.size()), &cookie); + if (std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path.data())) { + apk_assets_.push_back(std::move(apk)); + + std::vector<const ApkAssets*> apk_assets; + for (const std::unique_ptr<const ApkAssets>& apk_asset : apk_assets_) { + apk_assets.push_back(apk_asset.get()); + } + + asset_manager_.SetApkAssets(apk_assets, true /* invalidate_caches */, + false /* filter_incompatible_configs */); + return true; + } + return false; } std::map<size_t, std::string> AssetManagerSymbolSource::GetAssignedPackageIds() const { std::map<size_t, std::string> package_map; - const android::ResTable& table = assets_.getResources(false); - const size_t package_count = table.getBasePackageCount(); - for (size_t i = 0; i < package_count; i++) { - package_map[table.getBasePackageId(i)] = - util::Utf16ToUtf8(android::StringPiece16(table.getBasePackageName(i).string())); - } + asset_manager_.ForEachPackage([&package_map](const std::string& name, uint8_t id) -> bool { + package_map.insert(std::make_pair(id, name)); + return true; + }); + return package_map; } bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId) const { - return assets_.getResources(false).isPackageDynamic(packageId); + if (packageId == 0) { + return true; + } + + for (const std::unique_ptr<const ApkAssets>& assets : apk_assets_) { + for (const std::unique_ptr<const android::LoadedPackage>& loaded_package + : assets->GetLoadedArsc()->GetPackages()) { + if (packageId == loaded_package->GetPackageId() && loaded_package->IsDynamic()) { + return true; + } + } + } + + return false; } static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable( - const android::ResTable& table, ResourceId id) { - // Try as a bag. - const android::ResTable::bag_entry* entry; - ssize_t count = table.lockBag(id.id, &entry); - if (count < 0) { - table.unlockBag(entry); + android::AssetManager2& am, ResourceId id) { + if (am.GetApkAssets().empty()) { + return {}; + } + + const android::ResolvedBag* bag = am.GetBag(id.id); + if (bag == nullptr) { return nullptr; } // We found a resource. std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>(id); - // Check to see if it is an attribute. - for (size_t i = 0; i < (size_t)count; i++) { - if (entry[i].map.name.ident == android::ResTable_map::ATTR_TYPE) { - s->attribute = std::make_shared<Attribute>(entry[i].map.value.data); + const size_t count = bag->entry_count; + for (uint32_t i = 0; i < count; i++) { + if (bag->entries[i].key == android::ResTable_map::ATTR_TYPE) { + s->attribute = std::make_shared<Attribute>(bag->entries[i].value.data); break; } } if (s->attribute) { - for (size_t i = 0; i < (size_t)count; i++) { - const android::ResTable_map& map_entry = entry[i].map; - if (Res_INTERNALID(map_entry.name.ident)) { - switch (map_entry.name.ident) { + for (size_t i = 0; i < count; i++) { + const android::ResolvedBag::Entry& map_entry = bag->entries[i]; + if (Res_INTERNALID(map_entry.key)) { + switch (map_entry.key) { case android::ResTable_map::ATTR_MIN: s->attribute->min_int = static_cast<int32_t>(map_entry.value.data); break; @@ -269,74 +296,65 @@ static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable( continue; } - android::ResTable::resource_name entry_name; - if (!table.getResourceName(map_entry.name.ident, false, &entry_name)) { - table.unlockBag(entry); + android::AssetManager2::ResourceName name; + if (!am.GetResourceName(map_entry.key, &name)) { return nullptr; } - Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(entry_name); + Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(name); if (!parsed_name) { return nullptr; } Attribute::Symbol symbol; symbol.symbol.name = parsed_name.value(); - symbol.symbol.id = ResourceId(map_entry.name.ident); + symbol.symbol.id = ResourceId(map_entry.key); symbol.value = map_entry.value.data; s->attribute->symbols.push_back(std::move(symbol)); } } - table.unlockBag(entry); + return s; } std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName( const ResourceName& name) { - const android::ResTable& table = assets_.getResources(false); - - const std::u16string package16 = util::Utf8ToUtf16(name.package); - const std::u16string type16 = util::Utf8ToUtf16(to_string(name.type)); - const std::u16string entry16 = util::Utf8ToUtf16(name.entry); - const std::u16string mangled_entry16 = - util::Utf8ToUtf16(NameMangler::MangleEntry(name.package, name.entry)); + const std::string mangled_entry = NameMangler::MangleEntry(name.package, name.entry); + bool found = false; + ResourceId res_id = 0; uint32_t type_spec_flags; - ResourceId res_id; // There can be mangled resources embedded within other packages. Here we will // look into each package and look-up the mangled name until we find the resource. - const size_t count = table.getBasePackageCount(); - for (size_t i = 0; i < count; i++) { - const android::String16 package_name = table.getBasePackageName(i); - StringPiece16 real_package16 = package16; - StringPiece16 real_entry16 = entry16; - std::u16string scratch_entry16; - if (StringPiece16(package_name) != package16) { - real_entry16 = mangled_entry16; - real_package16 = package_name.string(); + asset_manager_.ForEachPackage([&](const std::string& package_name, uint8_t id) -> bool { + ResourceName real_name(name.package, name.type, name.entry); + + if (package_name != name.package) { + real_name.entry = mangled_entry; + real_name.package = package_name; } - type_spec_flags = 0; - res_id = table.identifierForName(real_entry16.data(), real_entry16.size(), type16.data(), - type16.size(), real_package16.data(), real_package16.size(), - &type_spec_flags); - if (res_id.is_valid()) { - break; + res_id = asset_manager_.GetResourceId(real_name.to_string()); + if (res_id.is_valid() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) { + found = true; + return false; } - } - if (!res_id.is_valid()) { + return true; + }); + + if (!found) { return {}; } std::unique_ptr<SymbolTable::Symbol> s; if (name.type == ResourceType::kAttr) { - s = LookupAttributeInTable(table, res_id); + s = LookupAttributeInTable(asset_manager_, res_id); } else { s = util::make_unique<SymbolTable::Symbol>(); s->id = res_id; - s->is_dynamic = table.isResourceDynamic(res_id.id); + s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id()); } if (s) { @@ -346,13 +364,13 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName( return {}; } -static Maybe<ResourceName> GetResourceName(const android::ResTable& table, +static Maybe<ResourceName> GetResourceName(android::AssetManager2& am, ResourceId id) { - android::ResTable::resource_name res_name = {}; - if (!table.getResourceName(id.id, true, &res_name)) { + android::AssetManager2::ResourceName name; + if (!am.GetResourceName(id.id, &name)) { return {}; } - return ResourceUtils::ToResourceName(res_name); + return ResourceUtils::ToResourceName(name); } std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById( @@ -361,22 +379,30 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById( // Exit early and avoid the error logs from AssetManager. return {}; } - const android::ResTable& table = assets_.getResources(false); - Maybe<ResourceName> maybe_name = GetResourceName(table, id); + + if (apk_assets_.empty()) { + return {}; + } + + Maybe<ResourceName> maybe_name = GetResourceName(asset_manager_, id); if (!maybe_name) { return {}; } + uint32_t type_spec_flags = 0; - table.getResourceFlags(id.id, &type_spec_flags); + if (!asset_manager_.GetResourceFlags(id.id, &type_spec_flags)) { + return {}; + } + ResourceName& name = maybe_name.value(); std::unique_ptr<SymbolTable::Symbol> s; - if (maybe_name.value().type == ResourceType::kAttr) { - s = LookupAttributeInTable(table, id); + if (name.type == ResourceType::kAttr) { + s = LookupAttributeInTable(asset_manager_, id); } else { s = util::make_unique<SymbolTable::Symbol>(); s->id = id; - s->is_dynamic = table.isResourceDynamic(id.id); + s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id()); } if (s) { diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h index 2d8bd02a3799..6997cd6714a8 100644 --- a/tools/aapt2/process/SymbolTable.h +++ b/tools/aapt2/process/SymbolTable.h @@ -22,7 +22,8 @@ #include <vector> #include "android-base/macros.h" -#include "androidfw/AssetManager.h" +#include "androidfw/Asset.h" +#include "androidfw/AssetManager2.h" #include "utils/JenkinsHash.h" #include "utils/LruCache.h" @@ -201,12 +202,13 @@ class AssetManagerSymbolSource : public ISymbolSource { std::unique_ptr<SymbolTable::Symbol> FindByReference( const Reference& ref) override; - android::AssetManager* GetAssetManager() { - return &assets_; + android::AssetManager2* GetAssetManager() { + return &asset_manager_; } private: - android::AssetManager assets_; + android::AssetManager2 asset_manager_; + std::vector<std::unique_ptr<const android::ApkAssets>> apk_assets_; DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource); }; diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp index 1f59d7034300..ddc210189793 100644 --- a/tools/aapt2/process/SymbolTable_test.cpp +++ b/tools/aapt2/process/SymbolTable_test.cpp @@ -76,40 +76,54 @@ TEST(SymbolTableTest, FindByName) { EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull()); } -TEST(SymbolTableTest, FindByNameWhenSymbolIsMangledInResTable) { +using SymbolTableTestFixture = CommandTestFixture; +TEST_F(SymbolTableTestFixture, FindByNameWhenSymbolIsMangledInResTable) { using namespace android; - - std::unique_ptr<IAaptContext> context = - test::ContextBuilder() - .SetCompilationPackage("com.android.app") - .SetPackageId(0x7f) - .SetPackageType(PackageType::kApp) - .SetMinSdkVersion(SDK_LOLLIPOP_MR1) - .SetNameManglerPolicy(NameManglerPolicy{"com.android.app"}) - .Build(); - - // Create a ResourceTable with a mangled resource, simulating a static library being merged into - // the main application package. - std::unique_ptr<ResourceTable> table = - test::ResourceTableBuilder() - .AddSimple("com.android.app:id/" + NameMangler::MangleEntry("com.android.lib", "foo"), - ResourceId(0x7f020000)) - .AddSimple("com.android.app:id/bar", ResourceId(0x7f020001)) - .Build(); - - BigBuffer buffer(1024u); - TableFlattener flattener({}, &buffer); - ASSERT_TRUE(flattener.Consume(context.get(), table.get())); - - std::unique_ptr<uint8_t[]> data = util::Copy(buffer); + StdErrDiagnostics diag; + + // Create a static library. + const std::string static_lib_compiled_files_dir = GetTestPath("static-lib-compiled"); + ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), + R"(<?xml version="1.0" encoding="utf-8"?> + <resources> + <item type="id" name="foo"/> + </resources>)", + static_lib_compiled_files_dir, &diag)); + + const std::string static_lib_apk = GetTestPath("static_lib.apk"); + std::vector<std::string> link_args = { + "--manifest", GetDefaultManifest("com.android.lib"), + "--min-sdk-version", "22", + "--static-lib", + "-o", static_lib_apk, + }; + ASSERT_TRUE(Link(link_args, static_lib_compiled_files_dir, &diag)); + + // Merge the static library into the main application package. The static library resources will + // be mangled with the library package name. + const std::string app_compiled_files_dir = GetTestPath("app-compiled"); + ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), + R"(<?xml version="1.0" encoding="utf-8"?> + <resources> + <item type="id" name="bar"/> + </resources>)", + app_compiled_files_dir, &diag)); + + const std::string out_apk = GetTestPath("out.apk"); + link_args = { + "--manifest", GetDefaultManifest("com.android.app"), + "--min-sdk-version", "22", + "-o", out_apk, + static_lib_apk + }; + ASSERT_TRUE(Link(link_args, app_compiled_files_dir, &diag)); // Construct the test AssetManager. auto asset_manager_source = util::make_unique<AssetManagerSymbolSource>(); - ResTable& res_table = const_cast<ResTable&>( - asset_manager_source->GetAssetManager()->getResources(false /*required*/)); - ASSERT_THAT(res_table.add(data.get(), buffer.size()), Eq(NO_ERROR)); + asset_manager_source->AddAssetPath(out_apk); - SymbolTable symbol_table(context->GetNameMangler()); + NameMangler name_mangler(NameManglerPolicy{"com.android.app"}); + SymbolTable symbol_table(&name_mangler); symbol_table.AppendSource(std::move(asset_manager_source)); EXPECT_THAT(symbol_table.FindByName(test::ParseNameOrDie("com.android.lib:id/foo")), NotNull()); diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp index 3fcdfb70a524..a51b4a4649f1 100644 --- a/tools/aapt2/test/Fixture.cpp +++ b/tools/aapt2/test/Fixture.cpp @@ -37,6 +37,8 @@ using testing::Ne; namespace aapt { +const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test"; + void ClearDirectory(const android::StringPiece& path) { const std::string root_dir = path.to_string(); std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir); @@ -124,12 +126,12 @@ bool CommandTestFixture::Link(const std::vector<std::string>& args, return LinkCommand(diag).Execute(link_args, &std::cerr) == 0; } -std::string CommandTestFixture::GetDefaultManifest() { +std::string CommandTestFixture::GetDefaultManifest(const char* package_name) { const std::string manifest_file = GetTestPath("AndroidManifest.xml"); - CHECK(WriteFile(manifest_file, R"( + CHECK(WriteFile(manifest_file, android::base::StringPrintf(R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.aapt.command.test"> - </manifest>)")); + package="%s"> + </manifest>)", package_name))); return manifest_file; } diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h index 3079c757f61a..fce2aebfecaa 100644 --- a/tools/aapt2/test/Fixture.h +++ b/tools/aapt2/test/Fixture.h @@ -81,7 +81,7 @@ class CommandTestFixture : public TestDirectoryFixture { IDiagnostics* diag); // Creates a minimal android manifest within the test directory and returns the file path. - std::string GetDefaultManifest(); + std::string GetDefaultManifest(const char* package_name = kDefaultPackageName); // Returns pointer to data inside APK files std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk, @@ -91,6 +91,7 @@ class CommandTestFixture : public TestDirectoryFixture { void AssertLoadXml(LoadedApk* apk, const io::IData* data, android::ResXMLTree* out_tree); + static const char* kDefaultPackageName; private: DISALLOW_COPY_AND_ASSIGN(CommandTestFixture); }; diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index 604b2575daa1..5d57de6a9fb1 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -102,12 +102,21 @@ FileType GetFileType(const std::string& path) { #endif bool mkdirs(const std::string& path) { - #ifdef _WIN32 - // Start after the drive path if present. Calling mkdir with only the drive will cause an error. - size_t current_pos = 1u; - if (path.size() >= 3 && path[1] == ':' && - (path[2] == '\\' || path[2] == '/')) { - current_pos = 3u; + #ifdef _WIN32 + // Start after the long path prefix if present. + bool require_drive = false; + size_t current_pos = 0u; + if (util::StartsWith(path, R"(\\?\)")) { + require_drive = true; + current_pos = 4u; + } + + // Start after the drive path if present. + if (path.size() >= 3 && path[current_pos + 1] == ':' && + (path[current_pos + 2] == '\\' || path[current_pos + 2] == '/')) { + current_pos += 3u; + } else if (require_drive) { + return false; } #else // Start after the first character so that we don't consume the root '/'. diff --git a/tools/aapt2/util/Files_test.cpp b/tools/aapt2/util/Files_test.cpp index 202cc261ad89..6c380808c0df 100644 --- a/tools/aapt2/util/Files_test.cpp +++ b/tools/aapt2/util/Files_test.cpp @@ -19,6 +19,7 @@ #include <sstream> #include "android-base/stringprintf.h" +#include "android-base/utf8.h" #include "test/Test.h" @@ -65,5 +66,40 @@ TEST_F(FilesTest, AppendPathWithLeadingOrTrailingSeparators) { EXPECT_EQ(expected_path_, base); } +#ifdef _WIN32 +TEST_F(FilesTest, WindowsMkdirsLongPath) { + // Creating directory paths longer than the Windows maximum path length (260 charatcers) should + // succeed. + const std::string kDirName = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + const size_t kRecursiveDepth = 10u; + + // Recursively create the test file path and clean up the created directories after the files have + // been created. + std::function<void(std::string, size_t)> CreateResursiveDirs = + [&kDirName, &CreateResursiveDirs](std::string current_path, const size_t n) -> void { + AppendPath(¤t_path, kDirName); + + if (n == 0) { + ASSERT_TRUE(file::mkdirs(current_path)) << "Failed to create path " << current_path; + } else { + CreateResursiveDirs(current_path, n - 1); + } + + // Clean up the created directories. + _rmdir(current_path.data()); + }; + + CreateResursiveDirs( + android::base::StringPrintf(R"(\\?\%s)", android::base::GetExecutableDirectory().data()), + kRecursiveDepth); +} + +TEST_F(FilesTest, WindowsMkdirsLongPathMissingDrive) { + ASSERT_FALSE(file::mkdirs(R"(\\?\local\path\to\file)")); + ASSERT_FALSE(file::mkdirs(R"(\\?\:local\path\to\file)")); + ASSERT_FALSE(file::mkdirs(R"(\\?\\local\path\to\file)")); +} +#endif + } // namespace files } // namespace aapt |