summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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
commitf267a40400259483305a431250a4bd49e7312cb7 (patch)
tree50a66bca3644a31f6255ae3ecad041d42d9dafc3
parent031a2f1aafbc4e39ab5601567862d498e8949538 (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
-rw-r--r--tools/aapt2/LoadedApk.cpp52
-rw-r--r--tools/aapt2/LoadedApk.h8
2 files changed, 54 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
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index ef97de301ad5..6d2257f2e17a 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -33,6 +33,12 @@ constexpr static const char kApkResourceTablePath[] = "resources.arsc";
constexpr static const char kProtoResourceTablePath[] = "resources.pb";
constexpr static const char kAndroidManifestPath[] = "AndroidManifest.xml";
+enum ApkFormat {
+ kUnknown,
+ kBinary,
+ kProto,
+};
+
// Info about an APK loaded in memory.
class LoadedApk {
public:
@@ -104,6 +110,8 @@ class LoadedApk {
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
std::unique_ptr<xml::XmlResource> manifest_;
+
+ static ApkFormat DetermineApkFormat(io::IFileCollection* apk);
};
} // namespace aapt