diff options
author | Pierre Lecesne <lecesne@google.com> | 2017-12-01 11:39:01 +0000 |
---|---|---|
committer | Pierre Lecesne <lecesne@google.com> | 2017-12-01 11:48:03 +0000 |
commit | f267a40400259483305a431250a4bd49e7312cb7 (patch) | |
tree | 50a66bca3644a31f6255ae3ecad041d42d9dafc3 /tools/aapt2/LoadedApk.cpp | |
parent | 031a2f1aafbc4e39ab5601567862d498e8949538 (diff) |
AAPT2: Use manifest parsing to determine format of APK.
This makes it possible to load APKs that don't have a resource table.
Bug: 69355482
Test: Manual
Change-Id: I8471dbe068e836b4beea9e6934d18dd16b70ef02
Diffstat (limited to 'tools/aapt2/LoadedApk.cpp')
-rw-r--r-- | tools/aapt2/LoadedApk.cpp | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index 5981401195a4..33b5a8b2686d 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -43,13 +43,16 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, I 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); + ApkFormat apkFormat = DetermineApkFormat(apk.get()); + switch (apkFormat) { + case ApkFormat::kBinary: + return LoadBinaryApkFromFileCollection(source, std::move(apk), diag); + case ApkFormat::kProto: + return LoadProtoApkFromFileCollection(source, std::move(apk), diag); + default: + diag->Error(DiagMessage(path) << "could not identify format of APK"); + return {}; } - diag->Error(DiagMessage(path) << "no resource table found"); - return {}; } std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection( @@ -243,4 +246,41 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return true; } +ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) { + if (apk->FindFile("resources.arsc") != nullptr) { + return ApkFormat::kBinary; + } else if (apk->FindFile("resources.pb") != nullptr) { + return ApkFormat::kProto; + } else { + // If the resource table is not present, attempt to read the manifest. + io::IFile* manifest_file = apk->FindFile(kAndroidManifestPath); + if (manifest_file == nullptr) { + return ApkFormat::kUnknown; + } + + // First try in proto format. + std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream(); + if (manifest_in != nullptr) { + pb::XmlNode pb_node; + io::ZeroCopyInputAdaptor manifest_adaptor(manifest_in.get()); + if (pb_node.ParseFromZeroCopyStream(&manifest_adaptor)) { + return ApkFormat::kProto; + } + } + + // If it didn't work, try in binary format. + std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData(); + if (manifest_data != nullptr) { + std::string error; + std::unique_ptr<xml::XmlResource> manifest = + xml::Inflate(manifest_data->data(), manifest_data->size(), &error); + if (manifest != nullptr) { + return ApkFormat::kBinary; + } + } + + return ApkFormat::kUnknown; + } +} + } // namespace aapt |