Merge "Fix long paths on Windows"

This commit is contained in:
TreeHugger Robot
2019-02-25 21:06:17 +00:00
committed by Android (Google) Code Review
13 changed files with 307 additions and 161 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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()) {

View File

@@ -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.

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);
};

View File

@@ -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());

View File

@@ -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;
}

View 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);
};

View File

@@ -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 '/'.

View File

@@ -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(&current_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