AAPT2: Process <java-symbols> and private symbol package
Need to introduce the idea of multiple levels of visibility to support <java-symbol>. Public, Private, Undefined. Public means it is accessible from outside and requires an ID assigned. Private means that we explicitly want this to be a symbol (show up in R.java), but not visible to other packages. No ID required. Undefined is any normal resource. When --private-symbols is specified in the link phase, these resources will not show up in R.java. Change-Id: Icba89221e08e685dee7683786aa7112baf28c856
This commit is contained in:
@@ -124,17 +124,18 @@ void Debug::printTable(ResourceTable* table) {
|
||||
}
|
||||
|
||||
for (const ResourceEntry* entry : sortedEntries) {
|
||||
ResourceId id = {
|
||||
package->id ? package->id.value() : uint8_t(0),
|
||||
type->id ? type->id.value() : uint8_t(0),
|
||||
entry->id ? entry->id.value() : uint16_t(0)
|
||||
};
|
||||
ResourceId id(package->id ? package->id.value() : uint8_t(0),
|
||||
type->id ? type->id.value() : uint8_t(0),
|
||||
entry->id ? entry->id.value() : uint16_t(0));
|
||||
ResourceName name(package->name, type->type, entry->name);
|
||||
|
||||
ResourceName name = { package->name, type->type, entry->name };
|
||||
std::cout << " spec resource " << id << " " << name;
|
||||
if (entry->publicStatus.isPublic) {
|
||||
std::cout << " PUBLIC";
|
||||
switch (entry->symbolStatus.state) {
|
||||
case SymbolState::kPublic: std::cout << " PUBLIC"; break;
|
||||
case SymbolState::kPrivate: std::cout << " _PRIVATE_"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
PrintVisitor visitor;
|
||||
|
||||
@@ -77,6 +77,18 @@ static std::u16string transform(const StringPiece16& symbol) {
|
||||
return output;
|
||||
}
|
||||
|
||||
bool JavaClassGenerator::skipSymbol(SymbolState state) {
|
||||
switch (mOptions.types) {
|
||||
case JavaClassGeneratorOptions::SymbolTypes::kAll:
|
||||
return false;
|
||||
case JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate:
|
||||
return state == SymbolState::kUndefined;
|
||||
case JavaClassGeneratorOptions::SymbolTypes::kPublic:
|
||||
return state != SymbolState::kPublic;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGenerate,
|
||||
const std::u16string& entryName,
|
||||
const Styleable* styleable,
|
||||
@@ -121,7 +133,7 @@ void JavaClassGenerator::generateStyleable(const StringPiece16& packageNameToGen
|
||||
// We may reference IDs from other packages, so prefix the entry name with
|
||||
// the package.
|
||||
const ResourceNameRef& itemName = sortedAttributes[i].second;
|
||||
if (packageNameToGenerate != itemName.package) {
|
||||
if (!itemName.package.empty() && packageNameToGenerate != itemName.package) {
|
||||
*out << "_" << transform(itemName.package);
|
||||
}
|
||||
*out << "_" << transform(itemName.entry) << " = " << i << ";\n";
|
||||
@@ -137,7 +149,11 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate
|
||||
std::u16string unmangledPackage;
|
||||
std::u16string unmangledName;
|
||||
for (const auto& entry : type->entries) {
|
||||
ResourceId id = { package->id.value(), type->id.value(), entry->id.value() };
|
||||
if (skipSymbol(entry->symbolStatus.state)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceId id(package->id.value(), type->id.value(), entry->id.value());
|
||||
assert(id.isValid());
|
||||
|
||||
unmangledName = entry->name;
|
||||
@@ -157,7 +173,7 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate
|
||||
}
|
||||
|
||||
if (!isValidSymbol(unmangledName)) {
|
||||
ResourceNameRef resourceName = { packageNameToGenerate, type->type, unmangledName };
|
||||
ResourceNameRef resourceName(packageNameToGenerate, type->type, unmangledName);
|
||||
std::stringstream err;
|
||||
err << "invalid symbol name '" << resourceName << "'";
|
||||
mError = err.str();
|
||||
@@ -177,13 +193,24 @@ bool JavaClassGenerator::generateType(const StringPiece16& packageNameToGenerate
|
||||
}
|
||||
|
||||
bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, std::ostream* out) {
|
||||
generateHeader(packageNameToGenerate, out);
|
||||
return generate(packageNameToGenerate, packageNameToGenerate, out);
|
||||
}
|
||||
|
||||
bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate,
|
||||
const StringPiece16& outPackageName, std::ostream* out) {
|
||||
generateHeader(outPackageName, out);
|
||||
|
||||
*out << "public final class R {\n";
|
||||
|
||||
for (const auto& package : mTable->packages) {
|
||||
for (const auto& type : package->types) {
|
||||
*out << " public static final class " << type->type << " {\n";
|
||||
StringPiece16 typeStr;
|
||||
if (type->type == ResourceType::kAttrPrivate) {
|
||||
typeStr = toString(ResourceType::kAttr);
|
||||
} else {
|
||||
typeStr = toString(type->type);
|
||||
}
|
||||
*out << " public static final class " << typeStr << " {\n";
|
||||
if (!generateType(packageNameToGenerate, package.get(), type.get(), out)) {
|
||||
return false;
|
||||
}
|
||||
@@ -196,4 +223,6 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate, st
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
@@ -33,6 +33,17 @@ struct JavaClassGeneratorOptions {
|
||||
* on resource entries. Default is true.
|
||||
*/
|
||||
bool useFinal = true;
|
||||
|
||||
enum class SymbolTypes {
|
||||
kAll,
|
||||
kPublicPrivate,
|
||||
kPublic,
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
SymbolTypes types = SymbolTypes::kAll;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -49,7 +60,11 @@ public:
|
||||
* We need to generate these symbols in a separate file.
|
||||
* Returns true on success.
|
||||
*/
|
||||
bool generate(const StringPiece16& package, std::ostream* out);
|
||||
bool generate(const StringPiece16& packageNameToGenerate, std::ostream* out);
|
||||
|
||||
bool generate(const StringPiece16& packageNameToGenerate,
|
||||
const StringPiece16& outputPackageName,
|
||||
std::ostream* out);
|
||||
|
||||
const std::string& getError() const;
|
||||
|
||||
@@ -64,6 +79,8 @@ private:
|
||||
const Styleable* styleable,
|
||||
std::ostream* out);
|
||||
|
||||
bool skipSymbol(SymbolState state);
|
||||
|
||||
ResourceTable* mTable;
|
||||
JavaClassGeneratorOptions mOptions;
|
||||
std::string mError;
|
||||
|
||||
@@ -65,6 +65,87 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
|
||||
output.find("public static final int hey_dude_cool_attr = 0;"));
|
||||
}
|
||||
|
||||
TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
|
||||
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
|
||||
.setPackageId(u"android", 0x01)
|
||||
.addSimple(u"@android:id/one", ResourceId(0x01020000))
|
||||
.addSimple(u"@android:id/com.foo$two", ResourceId(0x01020001))
|
||||
.build();
|
||||
|
||||
JavaClassGenerator generator(table.get(), {});
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(generator.generate(u"android", u"com.android.internal", &out));
|
||||
|
||||
std::string output = out.str();
|
||||
EXPECT_NE(std::string::npos, output.find("package com.android.internal;"));
|
||||
EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;"));
|
||||
EXPECT_EQ(std::string::npos, output.find("two"));
|
||||
EXPECT_EQ(std::string::npos, output.find("com_foo$two"));
|
||||
}
|
||||
|
||||
TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
|
||||
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
|
||||
.setPackageId(u"android", 0x01)
|
||||
.addSimple(u"@android:^attr-private/one", ResourceId(0x01010000))
|
||||
.build();
|
||||
|
||||
JavaClassGenerator generator(table.get(), {});
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(generator.generate(u"android", &out));
|
||||
|
||||
std::string output = out.str();
|
||||
EXPECT_NE(std::string::npos, output.find("public static final class attr"));
|
||||
EXPECT_EQ(std::string::npos, output.find("public static final class ^attr-private"));
|
||||
}
|
||||
|
||||
TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
|
||||
StdErrDiagnostics diag;
|
||||
std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
|
||||
.setPackageId(u"android", 0x01)
|
||||
.addSimple(u"@android:id/one", ResourceId(0x01020000))
|
||||
.addSimple(u"@android:id/two", ResourceId(0x01020001))
|
||||
.addSimple(u"@android:id/three", ResourceId(0x01020002))
|
||||
.build();
|
||||
ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/one"), {}, {},
|
||||
SymbolState::kPublic, &diag));
|
||||
ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/two"), {}, {},
|
||||
SymbolState::kPrivate, &diag));
|
||||
|
||||
JavaClassGeneratorOptions options;
|
||||
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
|
||||
{
|
||||
JavaClassGenerator generator(table.get(), options);
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(generator.generate(u"android", &out));
|
||||
std::string output = out.str();
|
||||
EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;"));
|
||||
EXPECT_EQ(std::string::npos, output.find("two"));
|
||||
EXPECT_EQ(std::string::npos, output.find("three"));
|
||||
}
|
||||
|
||||
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
|
||||
{
|
||||
JavaClassGenerator generator(table.get(), options);
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(generator.generate(u"android", &out));
|
||||
std::string output = out.str();
|
||||
EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;"));
|
||||
EXPECT_NE(std::string::npos, output.find("public static final int two = 0x01020001;"));
|
||||
EXPECT_EQ(std::string::npos, output.find("three"));
|
||||
}
|
||||
|
||||
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
|
||||
{
|
||||
JavaClassGenerator generator(table.get(), options);
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(generator.generate(u"android", &out));
|
||||
std::string output = out.str();
|
||||
EXPECT_NE(std::string::npos, output.find("public static final int one = 0x01020000;"));
|
||||
EXPECT_NE(std::string::npos, output.find("public static final int two = 0x01020001;"));
|
||||
EXPECT_NE(std::string::npos, output.find("public static final int three = 0x01020002;"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(adamlesinski): Re-enable this once we get merging working again.
|
||||
* TEST(JavaClassGeneratorTest, EmitPackageMangledSymbols) {
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
#include "ResourceTable.h"
|
||||
#include "ResourceUtils.h"
|
||||
#include "ResourceValues.h"
|
||||
#include "util/Util.h"
|
||||
#include "ValueVisitor.h"
|
||||
#include "XmlPullParser.h"
|
||||
|
||||
#include "util/Util.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace aapt {
|
||||
@@ -184,7 +185,7 @@ struct ParsedResource {
|
||||
ResourceName name;
|
||||
Source source;
|
||||
ResourceId id;
|
||||
bool markPublic = false;
|
||||
SymbolState symbolState = SymbolState::kUndefined;
|
||||
std::unique_ptr<Value> value;
|
||||
std::list<ParsedResource> childResources;
|
||||
};
|
||||
@@ -192,8 +193,10 @@ struct ParsedResource {
|
||||
// Recursively adds resources to the ResourceTable.
|
||||
static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
|
||||
IDiagnostics* diag, ParsedResource* res) {
|
||||
if (res->markPublic && !table->markPublic(res->name, res->id, res->source, diag)) {
|
||||
return false;
|
||||
if (res->symbolState != SymbolState::kUndefined) {
|
||||
if (!table->setSymbolState(res->name, res->id, res->source, res->symbolState, diag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!res->value) {
|
||||
@@ -318,6 +321,8 @@ bool ResourceParser::parseResources(XmlPullParser* parser) {
|
||||
result = parseAttr(parser, &parsedResource);
|
||||
} else if (elementName == u"public") {
|
||||
result = parsePublic(parser, &parsedResource);
|
||||
} else if (elementName == u"java-symbol" || elementName == u"symbol") {
|
||||
result = parseSymbol(parser, &parsedResource);
|
||||
} else {
|
||||
mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber()))
|
||||
<< "unknown resource type '" << elementName << "'");
|
||||
@@ -506,7 +511,29 @@ bool ResourceParser::parsePublic(XmlPullParser* parser, ParsedResource* outResou
|
||||
outResource->value = util::make_unique<Id>();
|
||||
}
|
||||
|
||||
outResource->markPublic = true;
|
||||
outResource->symbolState = SymbolState::kPublic;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceParser::parseSymbol(XmlPullParser* parser, ParsedResource* outResource) {
|
||||
const Source source = mSource.withLine(parser->getLineNumber());
|
||||
|
||||
Maybe<StringPiece16> maybeType = findNonEmptyAttribute(parser, u"type");
|
||||
if (!maybeType) {
|
||||
mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a "
|
||||
"'type' attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
const ResourceType* parsedType = parseResourceType(maybeType.value());
|
||||
if (!parsedType) {
|
||||
mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
|
||||
<< "' in <" << parser->getElementName() << ">");
|
||||
return false;
|
||||
}
|
||||
|
||||
outResource->name.type = *parsedType;
|
||||
outResource->symbolState = SymbolState::kPrivate;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ private:
|
||||
bool parseColor(XmlPullParser* parser, ParsedResource* outResource);
|
||||
bool parsePrimitive(XmlPullParser* parser, ParsedResource* outResource);
|
||||
bool parsePublic(XmlPullParser* parser, ParsedResource* outResource);
|
||||
bool parseSymbol(XmlPullParser* parser, ParsedResource* outResource);
|
||||
bool parseAttr(XmlPullParser* parser, ParsedResource* outResource);
|
||||
bool parseAttrImpl(XmlPullParser* parser, ParsedResource* outResource, bool weak);
|
||||
Maybe<Attribute::Symbol> parseEnumOrFlagItem(XmlPullParser* parser, const StringPiece16& tag);
|
||||
|
||||
@@ -220,6 +220,16 @@ bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
|
||||
kValidNameMangledChars, diag);
|
||||
}
|
||||
|
||||
bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
|
||||
const ResourceId id,
|
||||
const ConfigDescription& config,
|
||||
const Source& source,
|
||||
std::unique_ptr<Value> value,
|
||||
IDiagnostics* diag) {
|
||||
return addResourceImpl(name, id, config, source, std::move(value),
|
||||
kValidNameMangledChars, diag);
|
||||
}
|
||||
|
||||
bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId resId,
|
||||
const ConfigDescription& config, const Source& source,
|
||||
std::unique_ptr<Value> value, const char16_t* validChars,
|
||||
@@ -305,19 +315,25 @@ bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceI
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceTable::markPublic(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, IDiagnostics* diag) {
|
||||
return markPublicImpl(name, resId, source, kValidNameChars, diag);
|
||||
bool ResourceTable::setSymbolState(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, SymbolState state, IDiagnostics* diag) {
|
||||
return setSymbolStateImpl(name, resId, source, state, kValidNameChars, diag);
|
||||
}
|
||||
|
||||
bool ResourceTable::markPublicAllowMangled(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, IDiagnostics* diag) {
|
||||
return markPublicImpl(name, resId, source, kValidNameMangledChars, diag);
|
||||
bool ResourceTable::setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, SymbolState state,
|
||||
IDiagnostics* diag) {
|
||||
return setSymbolStateImpl(name, resId, source, state, kValidNameMangledChars, diag);
|
||||
}
|
||||
|
||||
bool ResourceTable::markPublicImpl(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, const char16_t* validChars,
|
||||
IDiagnostics* diag) {
|
||||
bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, SymbolState state,
|
||||
const char16_t* validChars, IDiagnostics* diag) {
|
||||
if (state == SymbolState::kUndefined) {
|
||||
// Nothing to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
|
||||
if (badCharIter != name.entry.end()) {
|
||||
diag->error(DiagMessage(source)
|
||||
@@ -371,9 +387,18 @@ bool ResourceTable::markPublicImpl(const ResourceNameRef& name, const ResourceId
|
||||
return false;
|
||||
}
|
||||
|
||||
type->publicStatus.isPublic = true;
|
||||
entry->publicStatus.isPublic = true;
|
||||
entry->publicStatus.source = source;
|
||||
// Only mark the type state as public, it doesn't care about being private.
|
||||
if (state == SymbolState::kPublic) {
|
||||
type->symbolStatus.state = SymbolState::kPublic;
|
||||
}
|
||||
|
||||
// Downgrading to a private symbol from a public one is not allowed.
|
||||
if (entry->symbolStatus.state != SymbolState::kPublic) {
|
||||
if (entry->symbolStatus.state != state) {
|
||||
entry->symbolStatus.state = state;
|
||||
entry->symbolStatus.source = source;
|
||||
}
|
||||
}
|
||||
|
||||
if (resId.isValid()) {
|
||||
package->id = resId.packageId();
|
||||
|
||||
@@ -31,11 +31,17 @@
|
||||
|
||||
namespace aapt {
|
||||
|
||||
enum class SymbolState {
|
||||
kUndefined,
|
||||
kPublic,
|
||||
kPrivate
|
||||
};
|
||||
|
||||
/**
|
||||
* The Public status of a resource.
|
||||
*/
|
||||
struct Public {
|
||||
bool isPublic = false;
|
||||
struct Symbol {
|
||||
SymbolState state = SymbolState::kUndefined;
|
||||
Source source;
|
||||
std::u16string comment;
|
||||
};
|
||||
@@ -71,7 +77,7 @@ struct ResourceEntry {
|
||||
* Whether this resource is public (and must maintain the same
|
||||
* entry ID across builds).
|
||||
*/
|
||||
Public publicStatus;
|
||||
Symbol symbolStatus;
|
||||
|
||||
/**
|
||||
* The resource's values for each configuration.
|
||||
@@ -100,7 +106,7 @@ struct ResourceTableType {
|
||||
* Whether this type is public (and must maintain the same
|
||||
* type ID across builds).
|
||||
*/
|
||||
Public publicStatus;
|
||||
Symbol symbolStatus;
|
||||
|
||||
/**
|
||||
* List of resources for this type.
|
||||
@@ -171,10 +177,15 @@ public:
|
||||
const Source& source, std::unique_ptr<Value> value,
|
||||
IDiagnostics* diag);
|
||||
|
||||
bool markPublic(const ResourceNameRef& name, const ResourceId resId, const Source& source,
|
||||
IDiagnostics* diag);
|
||||
bool markPublicAllowMangled(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, IDiagnostics* diag);
|
||||
bool addResourceAllowMangled(const ResourceNameRef& name, const ResourceId id,
|
||||
const ConfigDescription& config,
|
||||
const Source& source, std::unique_ptr<Value> value,
|
||||
IDiagnostics* diag);
|
||||
|
||||
bool setSymbolState(const ResourceNameRef& name, const ResourceId resId, const Source& source,
|
||||
SymbolState state, IDiagnostics* diag);
|
||||
bool setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, SymbolState state, IDiagnostics* diag);
|
||||
struct SearchResult {
|
||||
ResourceTablePackage* package;
|
||||
ResourceTableType* type;
|
||||
@@ -217,8 +228,9 @@ private:
|
||||
const ConfigDescription& config, const Source& source,
|
||||
std::unique_ptr<Value> value, const char16_t* validChars,
|
||||
IDiagnostics* diag);
|
||||
bool markPublicImpl(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, const char16_t* validChars, IDiagnostics* diag);
|
||||
bool setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId,
|
||||
const Source& source, SymbolState state, const char16_t* validChars,
|
||||
IDiagnostics* diag);
|
||||
};
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
@@ -134,7 +134,14 @@ struct Public_header {
|
||||
|
||||
struct Public_entry {
|
||||
uint16_t entryId;
|
||||
uint16_t res0;
|
||||
|
||||
enum : uint16_t {
|
||||
kUndefined = 0,
|
||||
kPublic = 1,
|
||||
kPrivate = 2,
|
||||
};
|
||||
|
||||
uint16_t state;
|
||||
android::ResStringPool_ref key;
|
||||
android::ResStringPool_ref source;
|
||||
uint32_t sourceLine;
|
||||
|
||||
@@ -300,7 +300,7 @@ private:
|
||||
|
||||
T* result = buffer->nextBlock<T>();
|
||||
ResTable_entry* outEntry = (ResTable_entry*)(result);
|
||||
if (entry->entry->publicStatus.isPublic) {
|
||||
if (entry->entry->symbolStatus.state == SymbolState::kPublic) {
|
||||
outEntry->flags |= ResTable_entry::FLAG_PUBLIC;
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ private:
|
||||
|
||||
// Populate the config masks for this entry.
|
||||
|
||||
if (entry->publicStatus.isPublic) {
|
||||
if (entry->symbolStatus.state == SymbolState::kPublic) {
|
||||
configMasks[entry->id.value()] |=
|
||||
util::hostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
|
||||
}
|
||||
@@ -480,17 +480,31 @@ private:
|
||||
publicHeader->typeId = type->id.value();
|
||||
|
||||
for (ResourceEntry* entry : *sortedEntries) {
|
||||
if (entry->publicStatus.isPublic) {
|
||||
if (entry->symbolStatus.state != SymbolState::kUndefined) {
|
||||
// Write the public status of this entry.
|
||||
Public_entry* publicEntry = publicWriter.nextBlock<Public_entry>();
|
||||
publicEntry->entryId = util::hostToDevice32(entry->id.value());
|
||||
publicEntry->key.index = util::hostToDevice32(mKeyPool.makeRef(
|
||||
entry->name).getIndex());
|
||||
publicEntry->source.index = util::hostToDevice32(mSourcePool->makeRef(
|
||||
util::utf8ToUtf16(entry->publicStatus.source.path)).getIndex());
|
||||
if (entry->publicStatus.source.line) {
|
||||
util::utf8ToUtf16(entry->symbolStatus.source.path)).getIndex());
|
||||
if (entry->symbolStatus.source.line) {
|
||||
publicEntry->sourceLine = util::hostToDevice32(
|
||||
entry->publicStatus.source.line.value());
|
||||
entry->symbolStatus.source.line.value());
|
||||
}
|
||||
|
||||
switch (entry->symbolStatus.state) {
|
||||
case SymbolState::kPrivate:
|
||||
publicEntry->state = Public_entry::kPrivate;
|
||||
break;
|
||||
|
||||
case SymbolState::kPublic:
|
||||
publicEntry->state = Public_entry::kPublic;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false && "should not serialize any other state");
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't hostToDevice until the last step.
|
||||
|
||||
@@ -52,7 +52,7 @@ struct LinkOptions {
|
||||
bool staticLib = false;
|
||||
bool verbose = false;
|
||||
bool outputToDirectory = false;
|
||||
Maybe<std::string> privateSymbols;
|
||||
Maybe<std::u16string> privateSymbols;
|
||||
};
|
||||
|
||||
struct LinkContext : public IAaptContext {
|
||||
@@ -328,13 +328,14 @@ struct LinkCommand {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool writeJavaFile(ResourceTable* table, const StringPiece16& package) {
|
||||
bool writeJavaFile(ResourceTable* table, const StringPiece16& packageNameToGenerate,
|
||||
const StringPiece16& outPackage, JavaClassGeneratorOptions javaOptions) {
|
||||
if (!mOptions.generateJavaClassPath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string outPath = mOptions.generateJavaClassPath.value();
|
||||
file::appendPath(&outPath, file::packageToPath(util::utf16ToUtf8(package)));
|
||||
file::appendPath(&outPath, file::packageToPath(util::utf16ToUtf8(outPackage)));
|
||||
file::mkdirs(outPath);
|
||||
file::appendPath(&outPath, "R.java");
|
||||
|
||||
@@ -344,13 +345,8 @@ struct LinkCommand {
|
||||
return false;
|
||||
}
|
||||
|
||||
JavaClassGeneratorOptions javaOptions;
|
||||
if (mOptions.staticLib) {
|
||||
javaOptions.useFinal = false;
|
||||
}
|
||||
|
||||
JavaClassGenerator generator(table, javaOptions);
|
||||
if (!generator.generate(mContext.getCompilationPackage(), &fout)) {
|
||||
if (!generator.generate(packageNameToGenerate, outPackage, &fout)) {
|
||||
mContext.getDiagnostics()->error(DiagMessage(outPath) << generator.getError());
|
||||
return false;
|
||||
}
|
||||
@@ -652,8 +648,34 @@ struct LinkCommand {
|
||||
}
|
||||
|
||||
if (mOptions.generateJavaClassPath) {
|
||||
if (!writeJavaFile(&mergedTable, mContext.getCompilationPackage())) {
|
||||
return 1;
|
||||
JavaClassGeneratorOptions options;
|
||||
if (mOptions.staticLib) {
|
||||
options.useFinal = false;
|
||||
}
|
||||
|
||||
if (mOptions.privateSymbols) {
|
||||
// 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(&mergedTable, mContext.getCompilationPackage(),
|
||||
mContext.getCompilationPackage(), options)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
|
||||
if (!writeJavaFile(&mergedTable, mContext.getCompilationPackage(),
|
||||
mOptions.privateSymbols.value(), options)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Emit Everything.
|
||||
|
||||
if (!writeJavaFile(&mergedTable, mContext.getCompilationPackage(),
|
||||
mContext.getCompilationPackage(), options)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,6 +702,7 @@ struct LinkCommand {
|
||||
|
||||
int link(const std::vector<StringPiece>& args) {
|
||||
LinkOptions options;
|
||||
Maybe<std::string> privateSymbolsPackage;
|
||||
Flags flags = Flags()
|
||||
.requiredFlag("-o", "Output path", &options.outputPath)
|
||||
.requiredFlag("--manifest", "Path to the Android manifest to build",
|
||||
@@ -698,13 +721,17 @@ int link(const std::vector<StringPiece>& args) {
|
||||
.optionalSwitch("--static-lib", "Generate a static Android library", &options.staticLib)
|
||||
.optionalFlag("--private-symbols", "Package name to use when generating R.java for "
|
||||
"private symbols. If not specified, public and private symbols will "
|
||||
"use the application's package name", &options.privateSymbols)
|
||||
"use the application's package name", &privateSymbolsPackage)
|
||||
.optionalSwitch("-v", "Enables verbose logging", &options.verbose);
|
||||
|
||||
if (!flags.parse("aapt2 link", args, &std::cerr)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (privateSymbolsPackage) {
|
||||
options.privateSymbols = util::utf8ToUtf16(privateSymbolsPackage.value());
|
||||
}
|
||||
|
||||
LinkCommand cmd = { options };
|
||||
return cmd.run(flags.getArgs());
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ bool PrivateAttributeMover::consume(IAaptContext* context, ResourceTable* table)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!type->publicStatus.isPublic) {
|
||||
if (type->symbolStatus.state != SymbolState::kPublic) {
|
||||
// No public attributes, so we can safely leave these private attributes where they are.
|
||||
return true;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ bool PrivateAttributeMover::consume(IAaptContext* context, ResourceTable* table)
|
||||
|
||||
moveIf(type->entries, std::back_inserter(privAttrType->entries),
|
||||
[](const std::unique_ptr<ResourceEntry>& entry) -> bool {
|
||||
return !entry->publicStatus.isPublic;
|
||||
return entry->symbolStatus.state != SymbolState::kPublic;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -31,10 +31,12 @@ TEST(PrivateAttributeMoverTest, MovePrivateAttributes) {
|
||||
.addSimple(u"@android:attr/publicB")
|
||||
.addSimple(u"@android:attr/privateB")
|
||||
.build();
|
||||
ASSERT_TRUE(table->markPublic(test::parseNameOrDie(u"@android:attr/publicA"),
|
||||
ResourceId(0x01010000), {}, context->getDiagnostics()));
|
||||
ASSERT_TRUE(table->markPublic(test::parseNameOrDie(u"@android:attr/publicB"),
|
||||
ResourceId(0x01010002), {}, context->getDiagnostics()));
|
||||
ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:attr/publicA"),
|
||||
ResourceId(0x01010000), {}, SymbolState::kPublic,
|
||||
context->getDiagnostics()));
|
||||
ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:attr/publicB"),
|
||||
ResourceId(0x01010002), {}, SymbolState::kPublic,
|
||||
context->getDiagnostics()));
|
||||
|
||||
PrivateAttributeMover mover;
|
||||
ASSERT_TRUE(mover.consume(context.get(), table.get()));
|
||||
|
||||
@@ -249,10 +249,13 @@ bool ReferenceLinker::consume(IAaptContext* context, ResourceTable* table) {
|
||||
for (auto& package : table->packages) {
|
||||
for (auto& type : package->types) {
|
||||
for (auto& entry : type->entries) {
|
||||
// A public entry with no values will not be encoded properly.
|
||||
if (entry->publicStatus.isPublic && entry->values.empty()) {
|
||||
context->getDiagnostics()->error(DiagMessage(entry->publicStatus.source)
|
||||
<< "No value for public resource");
|
||||
// Symbol state information may be lost if there is no value for the resource.
|
||||
if (entry->symbolStatus.state != SymbolState::kUndefined && entry->values.empty()) {
|
||||
context->getDiagnostics()->error(
|
||||
DiagMessage(entry->symbolStatus.source)
|
||||
<< "no definition for declared symbol '"
|
||||
<< ResourceNameRef(package->name, type->type, entry->name)
|
||||
<< "'");
|
||||
error = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ bool TableMerger::doMerge(const Source& src, ResourceTable* srcTable,
|
||||
|
||||
for (auto& srcType : srcPackage->types) {
|
||||
ResourceTableType* dstType = mMasterPackage->findOrCreateType(srcType->type);
|
||||
if (srcType->publicStatus.isPublic) {
|
||||
if (dstType->publicStatus.isPublic && dstType->id && srcType->id
|
||||
if (srcType->symbolStatus.state == SymbolState::kPublic) {
|
||||
if (dstType->symbolStatus.state == SymbolState::kPublic && dstType->id && srcType->id
|
||||
&& dstType->id.value() == srcType->id.value()) {
|
||||
// Both types are public and have different IDs.
|
||||
mContext->getDiagnostics()->error(DiagMessage(src)
|
||||
@@ -81,7 +81,7 @@ bool TableMerger::doMerge(const Source& src, ResourceTable* srcTable,
|
||||
continue;
|
||||
}
|
||||
|
||||
dstType->publicStatus = std::move(srcType->publicStatus);
|
||||
dstType->symbolStatus = std::move(srcType->symbolStatus);
|
||||
dstType->id = srcType->id;
|
||||
}
|
||||
|
||||
@@ -94,20 +94,29 @@ bool TableMerger::doMerge(const Source& src, ResourceTable* srcTable,
|
||||
dstEntry = dstType->findOrCreateEntry(srcEntry->name);
|
||||
}
|
||||
|
||||
if (srcEntry->publicStatus.isPublic) {
|
||||
if (dstEntry->publicStatus.isPublic && dstEntry->id && srcEntry->id
|
||||
&& dstEntry->id.value() != srcEntry->id.value()) {
|
||||
// Both entries are public and have different IDs.
|
||||
mContext->getDiagnostics()->error(DiagMessage(src)
|
||||
<< "can not merge entry '"
|
||||
<< srcEntry->name
|
||||
<< "': conflicting public IDs");
|
||||
error = true;
|
||||
continue;
|
||||
if (srcEntry->symbolStatus.state != SymbolState::kUndefined) {
|
||||
if (srcEntry->symbolStatus.state == SymbolState::kPublic) {
|
||||
if (dstEntry->symbolStatus.state == SymbolState::kPublic &&
|
||||
dstEntry->id && srcEntry->id &&
|
||||
dstEntry->id.value() != srcEntry->id.value()) {
|
||||
// Both entries are public and have different IDs.
|
||||
mContext->getDiagnostics()->error(DiagMessage(src)
|
||||
<< "can not merge entry '"
|
||||
<< srcEntry->name
|
||||
<< "': conflicting public IDs");
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (srcEntry->id) {
|
||||
dstEntry->id = srcEntry->id;
|
||||
}
|
||||
}
|
||||
|
||||
dstEntry->publicStatus = std::move(srcEntry->publicStatus);
|
||||
dstEntry->id = srcEntry->id;
|
||||
if (dstEntry->symbolStatus.state != SymbolState::kPublic &&
|
||||
dstEntry->symbolStatus.state != srcEntry->symbolStatus.state) {
|
||||
dstEntry->symbolStatus = std::move(srcEntry->symbolStatus);
|
||||
}
|
||||
}
|
||||
|
||||
for (ResourceConfigValue& srcValue : srcEntry->values) {
|
||||
|
||||
@@ -87,8 +87,9 @@ public:
|
||||
|
||||
ResourceTableBuilder& addValue(const StringPiece16& name, ResourceId id,
|
||||
const ConfigDescription& config, std::unique_ptr<Value> value) {
|
||||
bool result = mTable->addResource(parseNameOrDie(name), id, config, {}, std::move(value),
|
||||
&mDiagnostics);
|
||||
ResourceName resName = parseNameOrDie(name);
|
||||
bool result = mTable->addResourceAllowMangled(resName, id, config, {}, std::move(value),
|
||||
&mDiagnostics);
|
||||
assert(result);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -429,7 +429,19 @@ bool BinaryResourceParser::parsePublic(const ResourceTablePackage* package,
|
||||
source.line = util::deviceToHost32(entry->sourceLine);
|
||||
}
|
||||
|
||||
if (!mTable->markPublicAllowMangled(name, resId, source, mContext->getDiagnostics())) {
|
||||
SymbolState state = SymbolState::kUndefined;
|
||||
switch (util::deviceToHost16(entry->state)) {
|
||||
case Public_entry::kPrivate:
|
||||
state = SymbolState::kPrivate;
|
||||
break;
|
||||
|
||||
case Public_entry::kPublic:
|
||||
state = SymbolState::kPublic;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mTable->setSymbolStateAllowMangled(name, resId, source, state,
|
||||
mContext->getDiagnostics())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -564,8 +576,9 @@ bool BinaryResourceParser::parseType(const ResourceTablePackage* package,
|
||||
}
|
||||
|
||||
if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
|
||||
if (!mTable->markPublicAllowMangled(name, resId, mSource.withLine(0),
|
||||
mContext->getDiagnostics())) {
|
||||
if (!mTable->setSymbolStateAllowMangled(name, resId, mSource.withLine(0),
|
||||
SymbolState::kPublic,
|
||||
mContext->getDiagnostics())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user