Last active
September 28, 2019 06:10
-
-
Save anestisb/26ecf8ae13746dc476eddd8d04a5dd23 to your computer and use it in GitHub Desktop.
Patch for Android Pie ART oatdump to convert CompactDex to StandardDex before exporting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/oatdump/Android.bp b/oatdump/Android.bp | |
index 71e276d..3d50229 100644 | |
--- a/oatdump/Android.bp | |
+++ b/oatdump/Android.bp | |
@@ -35,6 +35,7 @@ art_cc_binary { | |
shared_libs: [ | |
"libart", | |
"libart-compiler", | |
+ "libart-dexlayout", | |
"libart-disassembler", | |
"libdexfile", | |
"libbase", | |
@@ -50,6 +51,7 @@ art_cc_binary { | |
shared_libs: [ | |
"libartd", | |
"libartd-compiler", | |
+ "libartd-dexlayout", | |
"libartd-disassembler", | |
"libdexfiled", | |
"libbase", | |
@@ -78,6 +80,7 @@ art_cc_binary { | |
"libart", | |
"libdexfile", | |
"libart-compiler", | |
+ "libart-dexlayout", | |
"libart-disassembler", | |
"libvixl-arm", | |
"libvixl-arm64", | |
@@ -109,6 +112,7 @@ art_cc_binary { | |
"libartd", | |
"libdexfiled", | |
"libartd-compiler", | |
+ "libartd-dexlayout", | |
"libartd-disassembler", | |
"libvixld-arm", | |
"libvixld-arm64", | |
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc | |
index 547a24c..f34d3f3 100644 | |
--- a/oatdump/oatdump.cc | |
+++ b/oatdump/oatdump.cc | |
@@ -44,11 +44,13 @@ | |
#include "debug/debug_info.h" | |
#include "debug/elf_debug_writer.h" | |
#include "debug/method_debug_info.h" | |
+#include "dex/art_dex_file_loader.h" | |
#include "dex/code_item_accessors-inl.h" | |
#include "dex/descriptors_names.h" | |
#include "dex/dex_file-inl.h" | |
#include "dex/dex_instruction-inl.h" | |
#include "dex/string_reference.h" | |
+#include "dexlayout.h" | |
#include "disassembler.h" | |
#include "gc/accounting/space_bitmap-inl.h" | |
#include "gc/space/image_space.h" | |
@@ -626,8 +628,60 @@ class OatDumper { | |
const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; | |
CHECK(oat_dex_file != nullptr); | |
CHECK(vdex_dex_file != nullptr); | |
- if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) { | |
- success = false; | |
+ | |
+ // If a CompactDex file is detected within a Vdex container, DexLayout is used to convert | |
+ // back to a StandardDex file. Since the converted DexFile will most likely not reproduce | |
+ // original input Dex file, ExportDexFile should know if DexLayout was used to adjust the | |
+ // checksum logic before writing the file on disk. | |
+ if (vdex_dex_file->IsCompactDexFile()) { | |
+ Options options; | |
+ options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone; | |
+ options.update_checksum_ = true; | |
+ DexLayout dex_layout(options, /*info*/ nullptr, /*out_file*/ nullptr, /*header*/ nullptr); | |
+ std::unique_ptr<art::DexContainer> dex_container; | |
+ bool result = dex_layout.ProcessDexFile(vdex_dex_file->GetLocation().c_str(), | |
+ vdex_dex_file.get(), | |
+ i, | |
+ &dex_container, | |
+ &error_msg); | |
+ if (!result) { | |
+ os << "DexLayout failed to process Dex file: " + error_msg; | |
+ success = false; | |
+ break; | |
+ } | |
+ DexContainer::Section* main_section = dex_container->GetMainSection(); | |
+ CHECK_EQ(dex_container->GetDataSection()->Size(), 0u); | |
+ | |
+ const ArtDexFileLoader dex_file_loader; | |
+ std::unique_ptr<const DexFile> dex(dex_file_loader.Open( | |
+ main_section->Begin(), | |
+ main_section->Size(), | |
+ vdex_dex_file->GetLocation(), | |
+ vdex_file->GetLocationChecksum(i), | |
+ nullptr /*oat_dex_file*/, | |
+ false /*verify*/, | |
+ true /*verify_checksum*/, | |
+ &error_msg)); | |
+ if (dex == nullptr) { | |
+ os << "Failed to load DexFile from layout container: " + error_msg; | |
+ success = false; | |
+ break; | |
+ } | |
+ if (dex->IsCompactDexFile()) { | |
+ os <<"CompactDex conversion to StandardDex failed"; | |
+ success = false; | |
+ break; | |
+ } | |
+ | |
+ if (!ExportDexFile(os, *oat_dex_file, dex.get(), true /*used_dexlayout*/)) { | |
+ success = false; | |
+ break; | |
+ } | |
+ } else { | |
+ if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get(), false /*used_dexlayout*/)) { | |
+ success = false; | |
+ break; | |
+ } | |
} | |
i++; | |
} | |
@@ -1131,13 +1185,15 @@ class OatDumper { | |
// Backwards compatible Dex file export. If dex_file is nullptr (valid Vdex file not present) the | |
// Dex resource is extracted from the oat_dex_file and its checksum is repaired since it's not | |
// unquickened. Otherwise the dex_file has been fully unquickened and is expected to verify the | |
- // original checksum. | |
+ // original checksum. If used_dexlayout is set, it means that the dex_file has been converted from | |
+ // a CompactDex file via dexlayout and requires to recompute checksum. | |
bool ExportDexFile(std::ostream& os, | |
const OatFile::OatDexFile& oat_dex_file, | |
- const DexFile* dex_file) { | |
+ const DexFile* dex_file, | |
+ bool used_dexlayout) { | |
std::string error_msg; | |
std::string dex_file_location = oat_dex_file.GetDexFileLocation(); | |
- size_t fsize = oat_dex_file.FileSize(); | |
+ size_t fsize = dex_file == nullptr ? oat_dex_file.FileSize() : dex_file->Size(); | |
// Some quick checks just in case | |
if (fsize == 0 || fsize < sizeof(DexFile::Header)) { | |
@@ -1157,27 +1213,22 @@ class OatDumper { | |
reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_ = | |
dex_file->CalculateChecksum(); | |
} else { | |
- // Vdex unquicken output should match original input bytecode | |
- uint32_t orig_checksum = | |
- reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_; | |
- CHECK_EQ(orig_checksum, dex_file->CalculateChecksum()); | |
- if (orig_checksum != dex_file->CalculateChecksum()) { | |
- os << "Unexpected checksum from unquicken dex file '" << dex_file_location << "'\n"; | |
- return false; | |
+ // When dexlayout is used to convert CompactDex back to StandardDex, checksum is not | |
+ // reproducible | |
+ if (used_dexlayout) { | |
+ reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_ = | |
+ dex_file->CalculateChecksum(); | |
+ } else { | |
+ // Vdex unquicken output should match original input bytecode | |
+ uint32_t orig_checksum = | |
+ reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_; | |
+ if (orig_checksum != dex_file->CalculateChecksum()) { | |
+ os << "Unexpected checksum from unquicken dex file '" << dex_file_location << "'\n"; | |
+ return false; | |
+ } | |
} | |
} | |
- // Update header for shared section. | |
- uint32_t shared_section_offset = 0u; | |
- uint32_t shared_section_size = 0u; | |
- if (dex_file->IsCompactDexFile()) { | |
- CompactDexFile::Header* const header = | |
- reinterpret_cast<CompactDexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin())); | |
- shared_section_offset = header->data_off_; | |
- shared_section_size = header->data_size_; | |
- // The shared section will be serialized right after the dex file. | |
- header->data_off_ = header->file_size_; | |
- } | |
// Verify output directory exists | |
if (!OS::DirectoryExists(options_.export_dex_location_)) { | |
// TODO: Extend OS::DirectoryExists if symlink support is required | |
@@ -1231,15 +1282,6 @@ class OatDumper { | |
return false; | |
} | |
- if (shared_section_size != 0) { | |
- success = file->WriteFully(dex_file->Begin() + shared_section_offset, shared_section_size); | |
- if (!success) { | |
- os << "Failed to write shared data section"; | |
- file->Erase(); | |
- return false; | |
- } | |
- } | |
- | |
if (file->FlushCloseOrErase() != 0) { | |
os << "Flush and close failed"; | |
return false; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this patch!