From 330edcdf1316ed599fe0eb16a64330821fd92f18 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 4 May 2015 17:40:56 -0700 Subject: AAPT2: Support static lib referencing static lib When a static library A references static library B, and app C references both A and B, we get the following symbol merging, symbols from library B get imported twice. We must only check that symbol references to library B are valid when building library A. We should only merge all the symbols when building final app C. Change-Id: I23cba33b0901dcbb5328d9c9dfaa6a979c073c36 --- tools/aapt2/Android.mk | 1 + tools/aapt2/BinaryResourceParser.cpp | 43 ++-- tools/aapt2/Debug.cpp | 181 +++++++++++++++++ tools/aapt2/Debug.h | 33 +++ tools/aapt2/JavaClassGenerator.cpp | 13 +- tools/aapt2/JavaClassGenerator_test.cpp | 7 +- tools/aapt2/Linker.cpp | 149 ++++++-------- tools/aapt2/Linker.h | 43 ++-- tools/aapt2/Linker_test.cpp | 3 +- tools/aapt2/Main.cpp | 344 +++++++++++++++----------------- tools/aapt2/MockResolver.h | 2 +- tools/aapt2/ResourceTable.cpp | 45 ++++- tools/aapt2/ResourceTable.h | 16 ++ tools/aapt2/ResourceTableResolver.cpp | 158 ++++++++------- tools/aapt2/ResourceTableResolver.h | 14 +- tools/aapt2/ResourceValues.cpp | 28 +-- tools/aapt2/ResourceValues.h | 5 + tools/aapt2/TableFlattener.cpp | 24 ++- tools/aapt2/XmlFlattener.cpp | 93 +++++---- tools/aapt2/XmlFlattener.h | 6 + 20 files changed, 751 insertions(+), 457 deletions(-) create mode 100644 tools/aapt2/Debug.cpp create mode 100644 tools/aapt2/Debug.h (limited to 'tools') diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk index 5ef4311..23d679d 100644 --- a/tools/aapt2/Android.mk +++ b/tools/aapt2/Android.mk @@ -30,6 +30,7 @@ sources := \ BinaryXmlPullParser.cpp \ BindingXmlPullParser.cpp \ ConfigDescription.cpp \ + Debug.cpp \ Files.cpp \ Flag.cpp \ JavaClassGenerator.cpp \ diff --git a/tools/aapt2/BinaryResourceParser.cpp b/tools/aapt2/BinaryResourceParser.cpp index d16f63b..bbd21fb 100644 --- a/tools/aapt2/BinaryResourceParser.cpp +++ b/tools/aapt2/BinaryResourceParser.cpp @@ -475,10 +475,17 @@ bool BinaryResourceParser::parsePublic(const ResChunk_header* chunk) { source.line = entry->sourceLine; } - if (!mTable->markPublic(name, resId, source)) { + if (!mTable->markPublicAllowMangled(name, resId, source)) { return false; } + // Add this resource name->id mapping to the index so + // that we can resolve all ID references to name references. + auto cacheIter = mIdIndex.find(resId); + if (cacheIter == mIdIndex.end()) { + mIdIndex.insert({ resId, name }); + } + entry++; } return true; @@ -611,12 +618,12 @@ bool BinaryResourceParser::parseType(const ResChunk_header* chunk) { source.line = sourceBlock->line; } - if (!mTable->addResource(name, config, source, std::move(resourceValue))) { + if (!mTable->addResourceAllowMangled(name, config, source, std::move(resourceValue))) { return false; } if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) { - if (!mTable->markPublic(name, resId, mSource.line(0))) { + if (!mTable->markPublicAllowMangled(name, resId, mSource.line(0))) { return false; } } @@ -635,6 +642,10 @@ std::unique_ptr BinaryResourceParser::parseValue(const ResourceNameRef& na const ConfigDescription& config, const Res_value* value, uint16_t flags) { + if (name.type == ResourceType::kId) { + return util::make_unique(); + } + if (value->dataType == Res_value::TYPE_STRING) { StringPiece16 str = util::getString(mValuePool, value->data); @@ -697,13 +708,6 @@ std::unique_ptr BinaryResourceParser::parseValue(const ResourceNameRef& na StringPool::Context{ 1, config })); } - if (name.type == ResourceType::kId || - (value->dataType == Res_value::TYPE_NULL && - value->data == Res_value::DATA_NULL_UNDEFINED && - (flags & ResTable_entry::FLAG_WEAK) != 0)) { - return util::make_unique(); - } - // Treat this as a raw binary primitive. return util::make_unique(*value); } @@ -789,10 +793,21 @@ std::unique_ptr BinaryResourceParser::parseAttr(const ResourceNameRef continue; } - attr->symbols.push_back(Attribute::Symbol{ - Reference(mapEntry.name.ident), - mapEntry.value.data - }); + Attribute::Symbol symbol; + symbol.value = mapEntry.value.data; + if (mapEntry.name.ident == 0) { + // The map entry's key (id) is not set. This must be + // a symbol reference, so resolve it. + ResourceNameRef symbolName; + bool result = getSymbol(&mapEntry.name.ident, &symbolName); + assert(result); + symbol.symbol.name = symbolName.toResourceName(); + } else { + // The map entry's key (id) is a regular reference. + symbol.symbol.id = mapEntry.name.ident; + } + + attr->symbols.push_back(std::move(symbol)); } } diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp new file mode 100644 index 0000000..a7b9bba --- /dev/null +++ b/tools/aapt2/Debug.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Debug.h" +#include "ResourceTable.h" +#include "ResourceValues.h" +#include "Util.h" + +#include +#include +#include +#include +#include +#include + +namespace aapt { + +struct PrintVisitor : ConstValueVisitor { + void visit(const Attribute& attr, ValueVisitorArgs&) override { + std::cout << "(attr) type="; + attr.printMask(std::cout); + static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | + android::ResTable_map::TYPE_FLAGS; + if (attr.typeMask & kMask) { + for (const auto& symbol : attr.symbols) { + std::cout << "\n " + << symbol.symbol.name.entry << " (" << symbol.symbol.id << ") = " + << symbol.value; + } + } + } + + void visit(const Style& style, ValueVisitorArgs&) override { + std::cout << "(style)"; + if (style.parent.name.isValid() || style.parent.id.isValid()) { + std::cout << " parent="; + if (style.parent.name.isValid()) { + std::cout << style.parent.name << " "; + } + + if (style.parent.id.isValid()) { + std::cout << style.parent.id; + } + } + + for (const auto& entry : style.entries) { + std::cout << "\n "; + if (entry.key.name.isValid()) { + std::cout << entry.key.name.package << ":" << entry.key.name.entry; + } + + if (entry.key.id.isValid()) { + std::cout << "(" << entry.key.id << ")"; + } + + std::cout << "=" << *entry.value; + } + } + + void visit(const Array& array, ValueVisitorArgs&) override { + array.print(std::cout); + } + + void visit(const Plural& plural, ValueVisitorArgs&) override { + plural.print(std::cout); + } + + void visit(const Styleable& styleable, ValueVisitorArgs&) override { + styleable.print(std::cout); + } + + void visitItem(const Item& item, ValueVisitorArgs& args) override { + item.print(std::cout); + } +}; + +void Debug::printTable(const std::shared_ptr& table) { + std::cout << "Package name=" << table->getPackage(); + if (table->getPackageId() != ResourceTable::kUnsetPackageId) { + std::cout << " id=" << std::hex << table->getPackageId() << std::dec; + } + std::cout << std::endl; + + for (const auto& type : *table) { + std::cout << " type " << type->type; + if (type->typeId != ResourceTableType::kUnsetTypeId) { + std::cout << " id=" << std::hex << type->typeId << std::dec; + } + std::cout << " entryCount=" << type->entries.size() << std::endl; + + std::vector sortedEntries; + for (const auto& entry : type->entries) { + auto iter = std::lower_bound(sortedEntries.begin(), sortedEntries.end(), entry.get(), + [](const ResourceEntry* a, const ResourceEntry* b) -> bool { + return a->entryId < b->entryId; + }); + sortedEntries.insert(iter, entry.get()); + } + + for (const ResourceEntry* entry : sortedEntries) { + ResourceId id = { table->getPackageId(), type->typeId, entry->entryId }; + ResourceName name = { table->getPackage(), type->type, entry->name }; + std::cout << " spec resource " << id << " " << name; + if (entry->publicStatus.isPublic) { + std::cout << " PUBLIC"; + } + std::cout << std::endl; + + PrintVisitor visitor; + for (const auto& value : entry->values) { + std::cout << " (" << value.config << ") "; + value.value->accept(visitor, {}); + std::cout << std::endl; + } + } + } +} + +static size_t getNodeIndex(const std::vector& names, const ResourceName& name) { + auto iter = std::lower_bound(names.begin(), names.end(), name); + assert(iter != names.end() && *iter == name); + return std::distance(names.begin(), iter); +} + +void Debug::printStyleGraph(const std::shared_ptr& table) { + std::vector names; + std::map> graph; + + for (const auto& type : *table) { + for (const auto& entry : type->entries) { + ResourceName name = { table->getPackage(), type->type, entry->name }; + for (const auto& value : entry->values) { + visitFunc