diff options
author | Adam Lesinski <adamlesinski@google.com> | 2017-10-31 17:44:39 -0700 |
---|---|---|
committer | Adam Lesinski <adamlesinski@google.com> | 2017-11-01 10:58:28 -0700 |
commit | 8780eb6e4918ae24fb1ae74d631042c32e41dc3d (patch) | |
tree | 938e18951a562fcd043ac779c7e758444b4bf0a8 /tools/aapt2/LoadedApk.cpp | |
parent | 4f340a4f8b50b29b562407e39563ee78a90bea3f (diff) |
AAPT2: Add convert command
This command allows a developer to convert their proto APK
(generated from the link phase using --proto-format) into
a binary APK suitable for use on device.
aapt2 convert -o output.apk input.apk
Test: manual + make aapt2_tests
Change-Id: I10a7c33bb4b57006d01fe00a8bf92f78e04e7e50
Diffstat (limited to 'tools/aapt2/LoadedApk.cpp')
-rw-r--r-- | tools/aapt2/LoadedApk.cpp | 146 |
1 files changed, 110 insertions, 36 deletions
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index ae32ee965b48..921d8531cbd3 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -21,43 +21,139 @@ #include "format/Archive.h" #include "format/binary/TableFlattener.h" #include "format/binary/XmlFlattener.h" +#include "format/proto/ProtoDeserialize.h" #include "io/BigBufferStream.h" #include "io/Util.h" #include "xml/XmlDom.h" -namespace aapt { +using ::aapt::io::IFile; +using ::aapt::io::IFileCollection; +using ::aapt::xml::XmlResource; +using ::android::StringPiece; +using ::std::unique_ptr; -using xml::XmlResource; +namespace aapt { -std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context, - const android::StringPiece& path) { +std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, IDiagnostics* diag) { Source source(path); std::string error; std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::Create(path, &error); - if (!apk) { - context->GetDiagnostics()->Error(DiagMessage(source) << error); + if (apk == nullptr) { + diag->Error(DiagMessage(path) << "failed opening zip: " << error); + return {}; + } + + if (apk->FindFile("resources.arsc") != nullptr) { + return LoadBinaryApkFromFileCollection(source, std::move(apk), diag); + } else if (apk->FindFile("resources.pb") != nullptr) { + return LoadProtoApkFromFileCollection(source, std::move(apk), diag); + } + diag->Error(DiagMessage(path) << "no resource table found"); + return {}; +} + +std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection( + const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) { + io::IFile* table_file = collection->FindFile(kProtoResourceTablePath); + if (table_file == nullptr) { + diag->Error(DiagMessage(source) << "failed to find " << kProtoResourceTablePath); return {}; } - io::IFile* file = apk->FindFile("resources.arsc"); - if (!file) { - context->GetDiagnostics()->Error(DiagMessage(source) << "no resources.arsc found"); + std::unique_ptr<io::InputStream> in = table_file->OpenInputStream(); + if (in == nullptr) { + diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath); return {}; } - std::unique_ptr<io::IData> data = file->OpenAsData(); - if (!data) { - context->GetDiagnostics()->Error(DiagMessage(source) << "could not open resources.arsc"); + pb::ResourceTable pb_table; + io::ZeroCopyInputAdaptor adaptor(in.get()); + if (!pb_table.ParseFromZeroCopyStream(&adaptor)) { + diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath); return {}; } + std::string error; std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); - BinaryResourceParser parser(context, table.get(), source, data->data(), data->size(), apk.get()); + if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) { + diag->Error(DiagMessage(source) + << "failed to deserialize " << kProtoResourceTablePath << ": " << error); + return {}; + } + + io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath); + if (manifest_file == nullptr) { + diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath); + return {}; + } + + std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream(); + if (manifest_in == nullptr) { + diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath); + return {}; + } + + pb::XmlNode pb_node; + io::ZeroCopyInputAdaptor manifest_adaptor(manifest_in.get()); + if (!pb_node.ParseFromZeroCopyStream(&manifest_adaptor)) { + diag->Error(DiagMessage(source) << "failed to read proto " << kAndroidManifestPath); + return {}; + } + + std::unique_ptr<xml::XmlResource> manifest = DeserializeXmlResourceFromPb(pb_node, &error); + if (manifest == nullptr) { + diag->Error(DiagMessage(source) + << "failed to deserialize proto " << kAndroidManifestPath << ": " << error); + return {}; + } + return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table), + std::move(manifest)); +} + +std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection( + const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) { + io::IFile* table_file = collection->FindFile(kApkResourceTablePath); + if (table_file == nullptr) { + diag->Error(DiagMessage(source) << "failed to find " << kApkResourceTablePath); + + return {}; + } + + std::unique_ptr<io::IData> data = table_file->OpenAsData(); + if (data == nullptr) { + diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath); + return {}; + } + + std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); + BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(), + collection.get()); if (!parser.Parse()) { return {}; } - return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table)); + io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath); + if (manifest_file == nullptr) { + diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath); + return {}; + } + + std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData(); + if (manifest_data == nullptr) { + diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath); + return {}; + } + + std::string error; + std::unique_ptr<xml::XmlResource> manifest = + xml::Inflate(manifest_data->data(), manifest_data->size(), &error); + if (manifest == nullptr) { + diag->Error(DiagMessage(source) + << "failed to parse binary " << kAndroidManifestPath << ": " << error); + return {}; + } + return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table), + std::move(manifest)); } bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options, @@ -148,26 +244,4 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return true; } -std::unique_ptr<xml::XmlResource> LoadedApk::InflateManifest(IAaptContext* context) { - IDiagnostics* diag = context->GetDiagnostics(); - - io::IFile* manifest_file = GetFileCollection()->FindFile("AndroidManifest.xml"); - if (manifest_file == nullptr) { - diag->Error(DiagMessage(source_) << "no AndroidManifest.xml found"); - return {}; - } - - std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData(); - if (manifest_data == nullptr) { - diag->Error(DiagMessage(manifest_file->GetSource()) << "could not open AndroidManifest.xml"); - return {}; - } - - std::unique_ptr<xml::XmlResource> manifest = - xml::Inflate(manifest_data->data(), manifest_data->size(), diag, manifest_file->GetSource()); - if (manifest == nullptr) { - diag->Error(DiagMessage() << "failed to read binary AndroidManifest.xml"); - } - return manifest; -} } // namespace aapt |