Merge "AAPT2: Few tweaks to get shared-libraries working"

This commit is contained in:
TreeHugger Robot
2017-02-23 20:24:22 +00:00
committed by Android (Google) Code Review
12 changed files with 132 additions and 71 deletions

View File

@@ -118,6 +118,9 @@ struct ResourceNameRef {
bool is_valid() const;
};
constexpr const uint8_t kAppPackageId = 0x7fu;
constexpr const uint8_t kFrameworkPackageId = 0x01u;
/**
* A binary identifier representing a resource. Internally it
* is a 32bit integer split as follows:

View File

@@ -533,6 +533,7 @@ uint32_t AndroidTypeToAttributeTypeMask(uint16_t type) {
case android::Res_value::TYPE_REFERENCE:
case android::Res_value::TYPE_ATTRIBUTE:
case android::Res_value::TYPE_DYNAMIC_REFERENCE:
case android::Res_value::TYPE_DYNAMIC_ATTRIBUTE:
return android::ResTable_map::TYPE_REFERENCE;
case android::Res_value::TYPE_STRING:

View File

@@ -88,10 +88,24 @@ bool Reference::Equals(const Value* value) const {
}
bool Reference::Flatten(android::Res_value* out_value) const {
out_value->dataType = (reference_type == Reference::Type::kResource)
? android::Res_value::TYPE_REFERENCE
: android::Res_value::TYPE_ATTRIBUTE;
out_value->data = util::HostToDevice32(id ? id.value().id : 0);
const ResourceId resid = id.value_or_default(ResourceId(0));
const bool dynamic =
(resid.package_id() != kFrameworkPackageId && resid.package_id() != kAppPackageId);
if (reference_type == Reference::Type::kResource) {
if (dynamic) {
out_value->dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE;
} else {
out_value->dataType = android::Res_value::TYPE_REFERENCE;
}
} else {
if (dynamic) {
out_value->dataType = android::Res_value::TYPE_DYNAMIC_ATTRIBUTE;
} else {
out_value->dataType = android::Res_value::TYPE_ATTRIBUTE;
}
}
out_value->data = util::HostToDevice32(resid.id);
return true;
}

View File

@@ -533,9 +533,14 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
std::unique_ptr<MethodDefinition> rewrite_method;
// Generate an onResourcesLoaded() callback if requested.
if (options_.generate_rewrite_callback) {
if (options_.rewrite_callback_options) {
rewrite_method =
util::make_unique<MethodDefinition>("public static void onResourcesLoaded(int p)");
for (const std::string& package_to_callback :
options_.rewrite_callback_options.value().packages_to_callback) {
rewrite_method->AppendStatement(
StringPrintf("%s.R.onResourcesLoaded(p);", package_to_callback.data()));
}
}
for (const auto& package : table_->packages) {

View File

@@ -33,13 +33,19 @@ class AnnotationProcessor;
class ClassDefinition;
class MethodDefinition;
// Options for generating onResourcesLoaded callback in R.java.
struct OnResourcesLoadedCallbackOptions {
// Other R classes to delegate the same callback to (with the same package ID).
std::vector<std::string> packages_to_callback;
};
struct JavaClassGeneratorOptions {
// Specifies whether to use the 'final' modifier on resource entries. Default is true.
bool use_final = true;
// Whether to generate code to rewrite the package ID of resources.
// Implies use_final == true. Default is false.
bool generate_rewrite_callback = false;
// If set, generates code to rewrite the package ID of resources.
// Implies use_final == true. Default is unset.
Maybe<OnResourcesLoadedCallbackOptions> rewrite_callback_options;
enum class SymbolTypes {
kAll,

View File

@@ -381,7 +381,9 @@ TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary)
JavaClassGeneratorOptions options;
options.use_final = false;
options.generate_rewrite_callback = true;
options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{
{"com.foo", "com.boo"},
};
JavaClassGenerator generator(context.get(), table.get(), options);
std::stringstream out;
@@ -389,7 +391,9 @@ TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary)
std::string actual = out.str();
EXPECT_NE(std::string::npos, actual.find("onResourcesLoaded"));
EXPECT_NE(std::string::npos, actual.find("void onResourcesLoaded"));
EXPECT_NE(std::string::npos, actual.find("com.foo.R.onResourcesLoaded"));
EXPECT_NE(std::string::npos, actual.find("com.boo.R.onResourcesLoaded"));
}
} // namespace aapt

View File

@@ -1097,18 +1097,15 @@ class LinkCommand {
return false;
}
std::unique_ptr<ResourceTable> table =
LoadTablePbFromCollection(collection.get());
std::unique_ptr<ResourceTable> table = LoadTablePbFromCollection(collection.get());
if (!table) {
context_->GetDiagnostics()->Error(DiagMessage(input)
<< "invalid static library");
context_->GetDiagnostics()->Error(DiagMessage(input) << "invalid static library");
return false;
}
ResourceTablePackage* pkg = table->FindPackageById(0x7f);
if (!pkg) {
context_->GetDiagnostics()->Error(DiagMessage(input)
<< "static library has no package");
context_->GetDiagnostics()->Error(DiagMessage(input) << "static library has no package");
return false;
}
@@ -1125,11 +1122,9 @@ class LinkCommand {
pkg->name = "";
if (override) {
result = table_merger_->MergeOverlay(Source(input), table.get(),
collection.get());
result = table_merger_->MergeOverlay(Source(input), table.get(), collection.get());
} else {
result =
table_merger_->Merge(Source(input), table.get(), collection.get());
result = table_merger_->Merge(Source(input), table.get(), collection.get());
}
} else {
@@ -1782,17 +1777,21 @@ class LinkCommand {
}
if (options_.generate_java_class_path) {
JavaClassGeneratorOptions options;
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
options.javadoc_annotations = options_.javadoc_annotations;
// The set of packages whose R class to call in the main classes
// onResourcesLoaded callback.
std::vector<std::string> packages_to_callback;
JavaClassGeneratorOptions template_options;
template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
template_options.javadoc_annotations = options_.javadoc_annotations;
if (options_.package_type == PackageType::kStaticLib || options_.generate_non_final_ids) {
options.use_final = false;
template_options.use_final = false;
}
if (options_.package_type == PackageType::kSharedLib) {
options.use_final = false;
options.generate_rewrite_callback = true;
template_options.use_final = false;
template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
}
const StringPiece actual_package = context_->GetCompilationPackage();
@@ -1802,36 +1801,51 @@ class LinkCommand {
output_package = options_.custom_java_package.value();
}
// Generate the private symbols if required.
if (options_.private_symbols) {
packages_to_callback.push_back(options_.private_symbols.value());
// If we defined a private symbols package, we only emit Public symbols
// to the original package, and private and public symbols to the
// private package.
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
if (!WriteJavaFile(&final_table_, context_->GetCompilationPackage(),
output_package, options)) {
return 1;
}
JavaClassGeneratorOptions options = template_options;
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
output_package = options_.private_symbols.value();
}
if (!WriteJavaFile(&final_table_, actual_package, output_package,
options)) {
return 1;
}
for (const std::string& extra_package : options_.extra_java_packages) {
if (!WriteJavaFile(&final_table_, actual_package, extra_package,
if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(),
options)) {
return 1;
}
}
// Generate all the symbols for all extra packages.
for (const std::string& extra_package : options_.extra_java_packages) {
packages_to_callback.push_back(extra_package);
JavaClassGeneratorOptions options = template_options;
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) {
return 1;
}
}
// Generate the main public R class.
JavaClassGeneratorOptions options = template_options;
// Only generate public symbols if we have a private package.
if (options_.private_symbols) {
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
}
if (options.rewrite_callback_options) {
options.rewrite_callback_options.value().packages_to_callback =
std::move(packages_to_callback);
}
if (!WriteJavaFile(&final_table_, actual_package, output_package, options)) {
return 1;
}
}
if (!WriteProguardFile(options_.generate_proguard_rules_path,
proguard_keep_set)) {
if (!WriteProguardFile(options_.generate_proguard_rules_path, proguard_keep_set)) {
return 1;
}

View File

@@ -79,6 +79,17 @@ static bool RequiredNameIsJavaPackage(xml::Element* el, SourcePathDiagnostics* d
return false;
}
static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool {
if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
diag->Error(DiagMessage(el->line_number)
<< "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
return false;
}
return true;
};
}
static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute({}, "package");
if (!attr) {
@@ -272,6 +283,16 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
application_action["uses-library"].Action(RequiredNameIsJavaPackage);
application_action["library"].Action(RequiredNameIsJavaPackage);
xml::XmlNodeAction& static_library_action = application_action["static-library"];
static_library_action.Action(RequiredNameIsJavaPackage);
static_library_action.Action(RequiredAndroidAttribute("version"));
xml::XmlNodeAction& uses_static_library_action = application_action["uses-static-library"];
uses_static_library_action.Action(RequiredNameIsJavaPackage);
uses_static_library_action.Action(RequiredAndroidAttribute("version"));
uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
application_action["meta-data"] = meta_data_action;
application_action["activity"] = component_action;
application_action["activity-alias"] = component_action;

View File

@@ -122,8 +122,7 @@ class ReferenceLinkerVisitor : public ValueVisitor {
DiagMessage msg(entry.key.GetSource());
// Call the matches method again, this time with a DiagMessage so we
// fill
// in the actual error message.
// fill in the actual error message.
symbol->attribute->Matches(entry.value.get(), &msg);
context_->GetDiagnostics()->Error(msg);
error_ = true;

View File

@@ -39,14 +39,12 @@ TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
bool TableMerger::Merge(const Source& src, ResourceTable* table,
io::IFileCollection* collection) {
return MergeImpl(src, table, collection, false /* overlay */,
true /* allow new */);
return MergeImpl(src, table, collection, false /* overlay */, true /* allow new */);
}
bool TableMerger::MergeOverlay(const Source& src, ResourceTable* table,
io::IFileCollection* collection) {
return MergeImpl(src, table, collection, true /* overlay */,
options_.auto_add_overlay);
return MergeImpl(src, table, collection, true /* overlay */, options_.auto_add_overlay);
}
/**
@@ -55,25 +53,13 @@ bool TableMerger::MergeOverlay(const Source& src, ResourceTable* table,
bool TableMerger::MergeImpl(const Source& src, ResourceTable* table,
io::IFileCollection* collection, bool overlay,
bool allow_new) {
const uint8_t desired_package_id = context_->GetPackageId();
bool error = false;
for (auto& package : table->packages) {
// Warn of packages with an unrelated ID.
const Maybe<ResourceId>& id = package->id;
if (id && id.value() != 0x0 && id.value() != desired_package_id) {
context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package "
<< package->name);
continue;
}
// Only merge an empty package or the package we're building.
// Other packages may exist, which likely contain attribute definitions.
// This is because at compile time it is unknown if the attributes are
// simply
// uses of the attribute or definitions.
if (package->name.empty() ||
context_->GetCompilationPackage() == package->name) {
// simply uses of the attribute or definitions.
if (package->name.empty() || context_->GetCompilationPackage() == package->name) {
FileMergeCallback callback;
if (collection) {
callback = [&](const ResourceNameRef& name,
@@ -83,8 +69,7 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table,
io::IFile* f = collection->FindFile(*old_file->path);
if (!f) {
context_->GetDiagnostics()->Error(DiagMessage(src)
<< "file '" << *old_file->path
<< "' not found");
<< "file '" << *old_file->path << "' not found");
return false;
}

View File

@@ -293,6 +293,11 @@ static Maybe<ResourceName> GetResourceName(const android::ResTable& table,
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
ResourceId id) {
if (!id.is_valid()) {
// 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 (!maybe_name) {

View File

@@ -458,10 +458,14 @@ std::unique_ptr<Item> BinaryResourceParser::ParseValue(
}
if (value->dataType == Res_value::TYPE_REFERENCE ||
value->dataType == Res_value::TYPE_ATTRIBUTE) {
const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE)
? Reference::Type::kResource
: Reference::Type::kAttribute;
value->dataType == Res_value::TYPE_ATTRIBUTE ||
value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE ||
value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
Reference::Type type = Reference::Type::kResource;
if (value->dataType == Res_value::TYPE_ATTRIBUTE ||
value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
type = Reference::Type::kAttribute;
}
if (data == 0) {
// A reference of 0, must be the magic @null reference.