diff options
Diffstat (limited to 'tools/aapt2/Main.cpp')
-rw-r--r-- | tools/aapt2/Main.cpp | 188 |
1 files changed, 113 insertions, 75 deletions
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 91639c5..de2dafc 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -17,13 +17,13 @@ #include "AppInfo.h" #include "BigBuffer.h" #include "BinaryResourceParser.h" -#include "BinaryXmlPullParser.h" #include "BindingXmlPullParser.h" #include "Debug.h" #include "Files.h" #include "Flag.h" #include "JavaClassGenerator.h" #include "Linker.h" +#include "ManifestMerger.h" #include "ManifestParser.h" #include "ManifestValidator.h" #include "NameMangler.h" @@ -57,6 +57,20 @@ constexpr const char* kAaptVersionStr = "2.0-alpha"; using namespace aapt; /** + * Used with smart pointers to free malloc'ed memory. + */ +struct DeleteMalloc { + void operator()(void* ptr) { + free(ptr); + } +}; + +struct StaticLibraryData { + Source source; + std::unique_ptr<ZipFile> apk; +}; + +/** * Collect files from 'root', filtering out any files that do not * match the FileFilter 'filter'. */ @@ -128,7 +142,7 @@ void versionStylesForCompat(const std::shared_ptr<ResourceTable>& table) { auto iter = style.entries.begin(); while (iter != style.entries.end()) { if (iter->key.name.package == u"android") { - size_t sdkLevel = findAttributeSdkLevel(iter->key.name.entry); + size_t sdkLevel = findAttributeSdkLevel(iter->key.name); if (sdkLevel > 1 && sdkLevel > configValue.config.sdkVersion) { // Record that we are about to strip this. stripped.emplace_back(std::move(*iter)); @@ -300,6 +314,42 @@ struct AaptOptions { ResourceName dumpStyleTarget; }; +struct IdCollector : public xml::Visitor { + IdCollector(const Source& source, const std::shared_ptr<ResourceTable>& table) : + mSource(source), mTable(table) { + } + + virtual void visit(xml::Text* node) override {} + + virtual void visit(xml::Namespace* node) override { + for (const auto& child : node->children) { + child->accept(this); + } + } + + virtual void visit(xml::Element* node) override { + for (const xml::Attribute& attr : node->attributes) { + bool create = false; + bool priv = false; + ResourceNameRef nameRef; + if (ResourceParser::tryParseReference(attr.value, &nameRef, &create, &priv)) { + if (create) { + mTable->addResource(nameRef, {}, mSource.line(node->lineNumber), + util::make_unique<Id>()); + } + } + } + + for (const auto& child : node->children) { + child->accept(this); + } + } + +private: + Source mSource; + std::shared_ptr<ResourceTable> mTable; +}; + bool compileXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& table, const CompileItem& item, ZipFile* outApk) { std::ifstream in(item.source.path, std::ifstream::binary); @@ -308,20 +358,19 @@ bool compileXml(const AaptOptions& options, const std::shared_ptr<ResourceTable> return false; } - BigBuffer outBuffer(1024); - - // No resolver, since we are not compiling attributes here. - XmlFlattener flattener(table, {}); - - XmlFlattener::Options xmlOptions; - xmlOptions.defaultPackage = table->getPackage(); - xmlOptions.keepRawValues = true; + SourceLogger logger(item.source); + std::unique_ptr<xml::Node> root = xml::inflate(&in, &logger); + if (!root) { + return false; + } - std::shared_ptr<XmlPullParser> parser = std::make_shared<SourceXmlPullParser>(in); + // Collect any resource ID's declared here. + IdCollector idCollector(item.source, table); + root->accept(&idCollector); - Maybe<size_t> minStrippedSdk = flattener.flatten(item.source, parser, &outBuffer, - xmlOptions); - if (!minStrippedSdk) { + BigBuffer outBuffer(1024); + if (!xml::flatten(root.get(), options.appInfo.package, &outBuffer)) { + logger.error() << "failed to encode XML." << std::endl; return false; } @@ -369,19 +418,13 @@ bool shouldGenerateVersionedResource(const std::shared_ptr<const ResourceTable>& bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& table, const std::shared_ptr<IResolver>& resolver, const LinkItem& item, const void* data, size_t dataLen, ZipFile* outApk, std::queue<LinkItem>* outQueue) { - std::shared_ptr<android::ResXMLTree> tree = std::make_shared<android::ResXMLTree>(); - if (tree->setTo(data, dataLen, false) != android::NO_ERROR) { + SourceLogger logger(item.source); + std::unique_ptr<xml::Node> root = xml::inflate(data, dataLen, &logger); + if (!root) { return false; } - std::shared_ptr<XmlPullParser> parser = std::make_shared<BinaryXmlPullParser>(tree); - - BigBuffer outBuffer(1024); - XmlFlattener flattener({}, resolver); - - XmlFlattener::Options xmlOptions; - xmlOptions.defaultPackage = item.originalPackage; - + xml::FlattenOptions xmlOptions; if (options.packageType == AaptOptions::PackageType::StaticLibrary) { xmlOptions.keepRawValues = true; } @@ -392,16 +435,12 @@ bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& t xmlOptions.maxSdkAttribute = item.config.sdkVersion ? item.config.sdkVersion : 1; } - std::shared_ptr<BindingXmlPullParser> binding; - if (item.name.type == ResourceType::kLayout) { - // Layouts may have defined bindings, so we need to make sure they get processed. - binding = std::make_shared<BindingXmlPullParser>(parser); - parser = binding; - } - - Maybe<size_t> minStrippedSdk = flattener.flatten(item.source, parser, &outBuffer, - xmlOptions); + BigBuffer outBuffer(1024); + Maybe<size_t> minStrippedSdk = xml::flattenAndLink(item.source, root.get(), + item.originalPackage, resolver, + xmlOptions, &outBuffer); if (!minStrippedSdk) { + logger.error() << "failed to encode XML." << std::endl; return false; } @@ -431,30 +470,6 @@ bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& t << buildFileReference(item) << "' to apk." << std::endl; return false; } - - if (binding && !options.bindingOutput.path.empty()) { - // We generated a binding xml file, write it out. - Source bindingOutput = options.bindingOutput; - appendPath(&bindingOutput.path, buildFileReference(item)); - - if (!mkdirs(bindingOutput.path)) { - Logger::error(bindingOutput) << strerror(errno) << std::endl; - return false; - } - - appendPath(&bindingOutput.path, "bind.xml"); - - std::ofstream bout(bindingOutput.path); - if (!bout) { - Logger::error(bindingOutput) << strerror(errno) << std::endl; - return false; - } - - if (!binding->writeToFile(bout)) { - Logger::error(bindingOutput) << strerror(errno) << std::endl; - return false; - } - } return true; } @@ -493,6 +508,7 @@ bool copyFile(const AaptOptions& options, const CompileItem& item, ZipFile* outA } bool compileManifest(const AaptOptions& options, const std::shared_ptr<IResolver>& resolver, + const std::map<std::shared_ptr<ResourceTable>, StaticLibraryData>& libApks, const android::ResTable& table, ZipFile* outApk) { if (options.verbose) { Logger::note(options.manifest) << "compiling AndroidManifest.xml." << std::endl; @@ -504,13 +520,46 @@ bool compileManifest(const AaptOptions& options, const std::shared_ptr<IResolver return false; } - BigBuffer outBuffer(1024); - std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(in); - XmlFlattener flattener({}, resolver); + SourceLogger logger(options.manifest); + std::unique_ptr<xml::Node> root = xml::inflate(&in, &logger); + if (!root) { + return false; + } - XmlFlattener::Options xmlOptions; - xmlOptions.defaultPackage = options.appInfo.package; - if (!flattener.flatten(options.manifest, xmlParser, &outBuffer, xmlOptions)) { + ManifestMerger merger({}); + if (!merger.setAppManifest(options.manifest, options.appInfo.package, std::move(root))) { + return false; + } + + for (const auto& entry : libApks) { + ZipFile* libApk = entry.second.apk.get(); + const std::u16string& libPackage = entry.first->getPackage(); + const Source& libSource = entry.second.source; + + ZipEntry* zipEntry = libApk->getEntryByName("AndroidManifest.xml"); + if (!zipEntry) { + continue; + } + + std::unique_ptr<void, DeleteMalloc> uncompressedData = std::unique_ptr<void, DeleteMalloc>( + libApk->uncompress(zipEntry)); + assert(uncompressedData); + + SourceLogger logger(libSource); + std::unique_ptr<xml::Node> libRoot = xml::inflate(uncompressedData.get(), + zipEntry->getUncompressedLen(), &logger); + if (!libRoot) { + return false; + } + + if (!merger.mergeLibraryManifest(libSource, libPackage, std::move(libRoot))) { + return false; + } + } + + BigBuffer outBuffer(1024); + if (!xml::flattenAndLink(options.manifest, merger.getMergedXml(), options.appInfo.package, + resolver, {}, &outBuffer)) { return false; } @@ -665,17 +714,6 @@ static void addApkFilesToLinkQueue(const std::u16string& package, const Source& static constexpr int kOpenFlags = ZipFile::kOpenCreate | ZipFile::kOpenTruncate | ZipFile::kOpenReadWrite; -struct DeleteMalloc { - void operator()(void* ptr) { - free(ptr); - } -}; - -struct StaticLibraryData { - Source source; - std::unique_ptr<ZipFile> apk; -}; - bool link(const AaptOptions& options, const std::shared_ptr<ResourceTable>& outTable, const std::shared_ptr<IResolver>& resolver) { std::map<std::shared_ptr<ResourceTable>, StaticLibraryData> apkFiles; @@ -768,7 +806,7 @@ bool link(const AaptOptions& options, const std::shared_ptr<ResourceTable>& outT } android::ResTable binTable; - if (!compileManifest(options, resolver, binTable, &outApk)) { + if (!compileManifest(options, resolver, apkFiles, binTable, &outApk)) { return false; } |