Merge "Fix long paths on Windows"
This commit is contained in:
committed by
Android (Google) Code Review
commit
c0a6d77625
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "androidfw/AssetManager2.h"
|
||||
#include "androidfw/ConfigDescription.h"
|
||||
#include "androidfw/ResourceTypes.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
@@ -77,6 +78,12 @@ bool IsAttributeReference(const android::StringPiece& str);
|
||||
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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
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);
|
||||
|
||||
if (idx < 0) {
|
||||
return 0;
|
||||
}
|
||||
return table.getTableCookie(idx);
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
uint32_t type_spec_flags = 0;
|
||||
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) {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
StdErrDiagnostics diag;
|
||||
|
||||
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 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));
|
||||
|
||||
// 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();
|
||||
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));
|
||||
|
||||
BigBuffer buffer(1024u);
|
||||
TableFlattener flattener({}, &buffer);
|
||||
ASSERT_TRUE(flattener.Consume(context.get(), table.get()));
|
||||
// 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));
|
||||
|
||||
std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
|
||||
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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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 '/'.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user