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
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 5981401..33b5a8b 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -43,13 +43,16 @@
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 @@
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